Skip to content

Commit 1b14647

Browse files
authored
Merge pull request #793 from CodingCatDev/dev
feat(syndication): automate daily.dev Squad publishing via /boot session refresh and GraphQL
2 parents f6002f9 + 15f1528 commit 1b14647

5 files changed

Lines changed: 353 additions & 3 deletions

File tree

‎.github/workflows/syndicate-post.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
HASHNODE_ACCESS_TOKEN: ${{ secrets.PRIVATE_HASHNODE }}
5151
AWS_BUILDER_SESSION_TOKEN: ${{ secrets.AWS_BUILDER_SESSION_TOKEN }}
5252
DAILY_DEV_TOKEN: ${{ secrets.DAILY_DEV_TOKEN }}
53+
DAILY_DEV_SESSION_COOKIE: ${{ secrets.DAILY_DEV_SESSION_COOKIE }}
5354
GOOGLE_WORKSPACE_REFRESH_TOKEN: ${{ secrets.GOOGLE_WORKSPACE_REFRESH_TOKEN }}
5455
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
5556
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}

‎apps/sanity/functions/syndicate-content/index.ts‎

Lines changed: 175 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface ContentDocument {
1717
devto?: string;
1818
hashnode?: string;
1919
awsbuilder?: string;
20+
dailydev?: string;
2021
tags?: Array<{ _key?: string; label?: string; value?: string }>;
2122
sponsor?: Array<{ _ref: string }>;
2223
syndications?: Array<{ _type: "reference"; _ref: string; _key?: string }>;
@@ -118,9 +119,10 @@ export const handler = documentEventHandler<ContentDocument>(
118119
Boolean(data.awsbuilder) ||
119120
process.env.FORCE_AWS_BUILDER === "true";
120121

121-
const platforms: Array<"devto" | "hashnode" | "awsbuilder"> = [
122+
const platforms: Array<"devto" | "hashnode" | "dailydev" | "awsbuilder"> = [
122123
"devto",
123124
"hashnode",
125+
"dailydev",
124126
...(shouldSyndicateAws ? (["awsbuilder"] as const) : []),
125127
];
126128

@@ -145,7 +147,9 @@ export const handler = documentEventHandler<ContentDocument>(
145147
? "dev.to"
146148
: platform === "hashnode"
147149
? "hashnode.com"
148-
: "builder.aws.com";
150+
: platform === "dailydev"
151+
? "daily.dev"
152+
: "builder.aws.com";
149153
await client.createOrReplace({
150154
_id: syndicationDocId,
151155
_type: "syndication",
@@ -745,6 +749,175 @@ export const handler = documentEventHandler<ContentDocument>(
745749
console.log(
746750
`[Syndicate Content] Successfully published to AWS Builder Center: ${externalUrl}`,
747751
);
752+
} else if (platform === "dailydev") {
753+
const dailyDevSession = process.env.DAILY_DEV_SESSION_COOKIE;
754+
if (!dailyDevSession) {
755+
console.warn(
756+
"[Syndicate Content] DAILY_DEV_SESSION_COOKIE not configured. Skipping daily.dev Squad live dispatch.",
757+
);
758+
continue;
759+
}
760+
761+
const squadSourceId = "dc8ed5af-d1f6-423d-9f17-703d33946006";
762+
const baseCookie = dailyDevSession.includes("__Secure-dast=")
763+
? dailyDevSession
764+
: `da2=m7Z6H7R0hwoOhyQZ1WW7K; __Secure-dast=${dailyDevSession}`;
765+
766+
// 1. Refresh short-lived da3 JWT via /boot
767+
const bootRes = await fetch("https://api.daily.dev/boot?v=3.47.11", {
768+
headers: {
769+
app: "webapp",
770+
"Content-Type": "application/json",
771+
Cookie: baseCookie,
772+
Origin: "https://app.daily.dev",
773+
Referer: "https://app.daily.dev/",
774+
},
775+
});
776+
const refreshedCookies =
777+
bootRes.headers
778+
.getSetCookie?.()
779+
?.map((c) => c.split(";")[0])
780+
.join("; ") || baseCookie;
781+
782+
const gqlHeaders = {
783+
"Content-Type": "application/json",
784+
Cookie: refreshedCookies,
785+
Origin: "https://app.daily.dev",
786+
Referer: "https://app.daily.dev/",
787+
};
788+
789+
const existingSyndication = await client
790+
.getDocument(syndicationDocId)
791+
.catch(() => null);
792+
const existingPostId =
793+
existingSyndication?.externalId &&
794+
!String(existingSyndication.externalId).startsWith("simulated-")
795+
? String(existingSyndication.externalId)
796+
: null;
797+
798+
const commentary = (
799+
data.excerpt ||
800+
data.title ||
801+
"New on CodingCat.dev!"
802+
).slice(0, 240);
803+
const coverImageUrl =
804+
urlForImage(data.coverImage)?.width(1280).format("jpg").url() || "";
805+
806+
let postId = existingPostId;
807+
if (!postId && data.dailydev) {
808+
const match = data.dailydev.match(/-([A-Za-z0-9]{9})$/);
809+
if (match) postId = match[1];
810+
}
811+
812+
if (postId) {
813+
const editRes = await fetch("https://api.daily.dev/graphql", {
814+
method: "POST",
815+
headers: gqlHeaders,
816+
body: JSON.stringify({
817+
query: `mutation UpdateSquadPost($id: ID!, $commentary: String) {
818+
editSharePost(id: $id, commentary: $commentary) {
819+
id
820+
}
821+
}`,
822+
variables: { id: postId, commentary },
823+
}),
824+
});
825+
const editData = (await editRes.json()) as any;
826+
if (editData?.errors) {
827+
console.warn(
828+
"[Syndicate Content] editSharePost warning, creating new Squad post:",
829+
editData.errors,
830+
);
831+
postId = null;
832+
}
833+
}
834+
835+
if (!postId) {
836+
const createRes = await fetch("https://api.daily.dev/graphql", {
837+
method: "POST",
838+
headers: gqlHeaders,
839+
body: JSON.stringify({
840+
query: `mutation CreatePostInMultipleSources(
841+
$sourceIds: [ID!]!
842+
$title: String
843+
$commentary: String
844+
$imageUrl: String
845+
$externalLink: String
846+
) {
847+
createPostInMultipleSources(
848+
sourceIds: $sourceIds
849+
title: $title
850+
commentary: $commentary
851+
imageUrl: $imageUrl
852+
externalLink: $externalLink
853+
) {
854+
id
855+
sourceId
856+
type
857+
slug
858+
}
859+
}`,
860+
variables: {
861+
sourceIds: [squadSourceId],
862+
title: data.title || "Untitled",
863+
commentary,
864+
...(coverImageUrl ? { imageUrl: coverImageUrl } : {}),
865+
externalLink: canonicalUrl,
866+
},
867+
}),
868+
});
869+
const createData = (await createRes.json()) as any;
870+
if (createData?.errors) {
871+
throw new Error(
872+
`daily.dev createPostInMultipleSources error: ${JSON.stringify(createData.errors)}`,
873+
);
874+
}
875+
postId = createData?.data?.createPostInMultipleSources?.[0]?.id;
876+
}
877+
878+
if (!postId) {
879+
throw new Error("daily.dev Squad publish did not return a post ID");
880+
}
881+
882+
const postRes = await fetch("https://api.daily.dev/graphql", {
883+
method: "POST",
884+
headers: gqlHeaders,
885+
body: JSON.stringify({
886+
query: `query GetSquadPost($id: ID!) {
887+
post(id: $id) {
888+
id
889+
commentsPermalink
890+
permalink
891+
}
892+
}`,
893+
variables: { id: postId },
894+
}),
895+
});
896+
const postJson = (await postRes.json()) as any;
897+
const externalUrl =
898+
postJson?.data?.post?.commentsPermalink ||
899+
`https://daily.dev/posts/${postId}`;
900+
901+
await client.createOrReplace({
902+
_id: syndicationDocId,
903+
_type: "syndication",
904+
target: { _type: "reference", _ref: data._id },
905+
platform: "dailydev",
906+
status: "published",
907+
canonicalUrl,
908+
externalUrl,
909+
externalId: String(postId),
910+
syndicatedAt: new Date().toISOString(),
911+
error: undefined,
912+
});
913+
914+
if (data.dailydev !== externalUrl) {
915+
parentPatch.dailydev = externalUrl;
916+
}
917+
918+
console.log(
919+
`[Syndicate Content] Successfully published to daily.dev Squad: ${externalUrl}`,
920+
);
748921
}
749922
} catch (publishErr) {
750923
const errMsg =

‎apps/sanity/schemas/partials/content.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ const content = defineType({
8787
type: "url",
8888
group: "data",
8989
}),
90+
defineField({
91+
name: "dailydev",
92+
title: "daily.dev Squad",
93+
type: "url",
94+
group: "data",
95+
}),
9096
defineField({
9197
name: "tags",
9298
title: "Tags",

‎scripts/publish-php2shell-post.mjs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,9 +457,23 @@ sudo systemctl restart php8.4-fpm apache2`
457457
coverImage: postDoc.coverImage,
458458
content: postDoc.content,
459459
awsbuilder: "https://builder.aws.com/content/3L50qXKr83Y2r9mA6ZsGhcc4cRJ/php-shell-cve-how-ai-found-a-decade-old-bug-in-of-the-web",
460+
dailydev: "https://daily.dev/posts/two-critical-pre-auth-rce-flaws-in-php-cve-2026-109618-cve-2026-109619-uncovered-by-ai-models-f-lmbg2iyss",
460461
},
461462
},
462463
},
464+
{
465+
createOrReplace: {
466+
_id: "syndication.post-php2shell-cve-2026-109618.dailydev",
467+
_type: "syndication",
468+
target: { _type: "reference", _ref: postDoc._id },
469+
platform: "dailydev",
470+
status: "published",
471+
canonicalUrl: "https://codingcat.dev/post/php2shell-cve-2026-109618-ai-php-security-scramble",
472+
externalUrl: "https://daily.dev/posts/two-critical-pre-auth-rce-flaws-in-php-cve-2026-109618-cve-2026-109619-uncovered-by-ai-models-f-lmbg2iyss",
473+
externalId: "lmBG2IYsS",
474+
syndicatedAt: "2026-10-24T03:38:28.000Z",
475+
},
476+
},
463477
{ patch: { id: "LzgcvqoNSwz5R8loykZyIB", set: { excerpt: "Learn how to customize your Slack workspace theme using SlackThemes.net and contribute custom color themes on GitHub." } } },
464478
{ patch: { id: "ZKdo3vLUqcb4sYreiCMc5A", set: { excerpt: "Learn how to inspect and debug Angular 9 components directly inside the Chrome DevTools console using the new ng global object." } } },
465479
{ patch: { id: "ZKdo3vLUqcb4sYreiCPNnI", set: { excerpt: "Join Alex Patterson and Brittney Postma with special guests Zach DeRose, Facundo Giuliani, Swyx, Jason Lengstorf, and Scott Tolinski for a year-end Holiday AMA." } } },

0 commit comments

Comments
 (0)