@growth-labs/cms 0.6.6 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/foundry-dispatch.d.ts.map +1 -1
- package/dist/engine/foundry-dispatch.js +36 -7
- package/dist/engine/foundry-dispatch.js.map +1 -1
- package/dist/engine/fronts-publish-intent.d.ts +15 -4
- package/dist/engine/fronts-publish-intent.d.ts.map +1 -1
- package/dist/engine/fronts-publish-intent.js +52 -19
- package/dist/engine/fronts-publish-intent.js.map +1 -1
- package/dist/engine/fronts-publish.d.ts +19 -0
- package/dist/engine/fronts-publish.d.ts.map +1 -1
- package/dist/engine/fronts-publish.js +158 -5
- package/dist/engine/fronts-publish.js.map +1 -1
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +1 -0
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/podcast-source.d.ts +28 -0
- package/dist/engine/podcast-source.d.ts.map +1 -0
- package/dist/engine/podcast-source.js +50 -0
- package/dist/engine/podcast-source.js.map +1 -0
- package/dist/engine/publication-current-guard.d.ts +10 -0
- package/dist/engine/publication-current-guard.d.ts.map +1 -0
- package/dist/engine/publication-current-guard.js +76 -0
- package/dist/engine/publication-current-guard.js.map +1 -0
- package/dist/engine/publication.d.ts +4 -0
- package/dist/engine/publication.d.ts.map +1 -1
- package/dist/engine/publication.js +13 -0
- package/dist/engine/publication.js.map +1 -1
- package/dist/engine/publisher.d.ts.map +1 -1
- package/dist/engine/publisher.js +20 -13
- package/dist/engine/publisher.js.map +1 -1
- package/dist/engine/soft-delete.js +2 -2
- package/dist/engine/soft-delete.js.map +1 -1
- package/dist/providers/types.d.ts +9 -3
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/routes/content.d.ts +2 -0
- package/dist/routes/content.d.ts.map +1 -1
- package/dist/routes/content.js +1 -1
- package/dist/routes/content.js.map +1 -1
- package/dist/routes/fronts-publish.d.ts +2 -2
- package/dist/routes/fronts-publish.d.ts.map +1 -1
- package/dist/routes/fronts-publish.js +52 -23
- package/dist/routes/fronts-publish.js.map +1 -1
- package/dist/routes/index.js +1 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/schema/layout.d.ts +2 -2
- package/dist/ui/api/_content-config.d.ts.map +1 -1
- package/dist/ui/api/_content-config.js +1 -0
- package/dist/ui/api/_content-config.js.map +1 -1
- package/dist/ui/api/fronts/publish-callback.d.ts.map +1 -1
- package/dist/ui/api/fronts/publish-callback.js +2 -6
- package/dist/ui/api/fronts/publish-callback.js.map +1 -1
- package/dist/ui/api/fronts/schedule.d.ts.map +1 -1
- package/dist/ui/api/fronts/schedule.js +2 -6
- package/dist/ui/api/fronts/schedule.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/foundry-dispatch.ts +67 -12
- package/src/engine/fronts-publish-intent.ts +78 -26
- package/src/engine/fronts-publish.ts +223 -5
- package/src/engine/index.ts +4 -0
- package/src/engine/podcast-source.ts +82 -0
- package/src/engine/publication-current-guard.ts +87 -0
- package/src/engine/publication.ts +23 -0
- package/src/engine/publisher.ts +21 -13
- package/src/engine/soft-delete.ts +2 -2
- package/src/providers/types.ts +6 -1
- package/src/routes/content.ts +3 -1
- package/src/routes/fronts-publish.ts +63 -25
- package/src/routes/index.ts +1 -1
- package/src/ui/api/_content-config.ts +2 -0
- package/src/ui/api/fronts/publish-callback.ts +2 -8
- package/src/ui/api/fronts/schedule.ts +2 -8
|
@@ -29,9 +29,13 @@ import {
|
|
|
29
29
|
isFrontsPublishEnabled,
|
|
30
30
|
listFrontsPublishSchedule,
|
|
31
31
|
} from '../engine/fronts-publish.js'
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
FrontsScheduleOverflowError,
|
|
34
|
+
hydrateFrontsPublishIntents,
|
|
35
|
+
} from '../engine/fronts-publish-intent.js'
|
|
33
36
|
import { publicUrlFor } from '../ui/screens/public-url.js'
|
|
34
|
-
import {
|
|
37
|
+
import { resolveConfig } from './config.js'
|
|
38
|
+
import type { ContentRouteConfig } from './content.js'
|
|
35
39
|
import { json, type RouteContext } from './context.js'
|
|
36
40
|
|
|
37
41
|
/**
|
|
@@ -112,6 +116,7 @@ const CallbackSchema = z
|
|
|
112
116
|
intent_id: z.string().min(1).nullish(),
|
|
113
117
|
content_id: z.string().min(1),
|
|
114
118
|
version: z.number().int().nullish(),
|
|
119
|
+
publish_at: z.number().int().positive().nullish(),
|
|
115
120
|
correlation_id: z.string().min(1).nullish(),
|
|
116
121
|
status: z.enum(['queued', 'publishing', 'live', 'late', 'failed']),
|
|
117
122
|
occurred_at: z.union([z.string(), z.number()]).nullish(),
|
|
@@ -151,7 +156,7 @@ function parseWindow(
|
|
|
151
156
|
return { fromSeconds, toSeconds }
|
|
152
157
|
}
|
|
153
158
|
|
|
154
|
-
export function createFrontsPublishRoutes(config:
|
|
159
|
+
export function createFrontsPublishRoutes(config: ContentRouteConfig): FrontsPublishRouteHandlers {
|
|
155
160
|
const resolved = resolveConfig(config)
|
|
156
161
|
return {
|
|
157
162
|
async schedule(ctx) {
|
|
@@ -184,28 +189,37 @@ export function createFrontsPublishRoutes(config: CmsRouteConfig): FrontsPublish
|
|
|
184
189
|
// predicate, and `incomplete` names every due item that cannot form a
|
|
185
190
|
// complete intent, so a missing canonical field is an explicit, visible
|
|
186
191
|
// contract error rather than a silently short `intents` array.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
192
|
+
try {
|
|
193
|
+
const items = await listFrontsPublishSchedule(ctx.db, {
|
|
194
|
+
toSeconds: window.toSeconds,
|
|
195
|
+
nowSeconds: now,
|
|
196
|
+
})
|
|
197
|
+
const hydrated = await hydrateFrontsPublishIntents(ctx.db, {
|
|
198
|
+
toSeconds: window.toSeconds,
|
|
199
|
+
nowSeconds: now,
|
|
200
|
+
mediaPublicDomain: resolved.mediaPublicDomain,
|
|
201
|
+
podcastSourceProductionEnabled: config.podcastSourceProductionEnabled,
|
|
202
|
+
// Site-RELATIVE paths: the CMS does not know the site origin, and the
|
|
203
|
+
// consumer joins its own trusted configured origin. A host-supplied
|
|
204
|
+
// origin is deliberately deferred (packages-docs/cms.md).
|
|
205
|
+
resolveContentUrl: (row) => publicUrlFor(row),
|
|
206
|
+
})
|
|
207
|
+
return json({
|
|
208
|
+
ok: true,
|
|
209
|
+
now,
|
|
210
|
+
window: { from: window.fromSeconds, to: window.toSeconds },
|
|
211
|
+
count: items.length,
|
|
212
|
+
items,
|
|
213
|
+
intents: hydrated.intents,
|
|
214
|
+
incomplete: hydrated.incomplete,
|
|
215
|
+
})
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (error instanceof FrontsScheduleOverflowError) {
|
|
218
|
+
console.error(`[cms] fronts/schedule unavailable: ${error.message}`)
|
|
219
|
+
return json({ ok: false, error: 'schedule_overflow', message: error.message }, 503)
|
|
220
|
+
}
|
|
221
|
+
throw error
|
|
222
|
+
}
|
|
209
223
|
},
|
|
210
224
|
|
|
211
225
|
async publishCallback(ctx) {
|
|
@@ -253,16 +267,40 @@ export function createFrontsPublishRoutes(config: CmsRouteConfig): FrontsPublish
|
|
|
253
267
|
intentId: parsed.data.intent_id ?? null,
|
|
254
268
|
contentId: parsed.data.content_id,
|
|
255
269
|
version: parsed.data.version ?? null,
|
|
270
|
+
publishAt: parsed.data.publish_at ?? null,
|
|
256
271
|
correlationId: parsed.data.correlation_id ?? null,
|
|
257
272
|
status: parsed.data.status,
|
|
258
273
|
occurredAt: parsed.data.occurred_at ?? null,
|
|
259
274
|
receipt: parsed.data.receipt ?? null,
|
|
260
275
|
error: parsed.data.error ?? null,
|
|
276
|
+
checkReadiness: config.publishReadiness
|
|
277
|
+
? (item) =>
|
|
278
|
+
config.publishReadiness!({
|
|
279
|
+
ctx,
|
|
280
|
+
contentId: item.id,
|
|
281
|
+
type: item.type,
|
|
282
|
+
status: item.status,
|
|
283
|
+
})
|
|
284
|
+
: undefined,
|
|
261
285
|
})
|
|
262
286
|
|
|
263
287
|
if (!result.contentFound) {
|
|
264
288
|
return json({ error: 'content_not_found', contentId: parsed.data.content_id }, 404)
|
|
265
289
|
}
|
|
290
|
+
if (result.rejection) {
|
|
291
|
+
console.warn(
|
|
292
|
+
`[cms] fronts/publish-callback rejected for content ${parsed.data.content_id}: ${result.rejection.code}`,
|
|
293
|
+
)
|
|
294
|
+
return json(
|
|
295
|
+
{
|
|
296
|
+
ok: false,
|
|
297
|
+
error: result.rejection.code,
|
|
298
|
+
message: result.rejection.message,
|
|
299
|
+
...(result.rejection.blockers ? { blockers: result.rejection.blockers } : {}),
|
|
300
|
+
},
|
|
301
|
+
result.rejection.status,
|
|
302
|
+
)
|
|
303
|
+
}
|
|
266
304
|
if (result.ledgerError) {
|
|
267
305
|
// A confirmed `live` that could not be committed through the ledger is a
|
|
268
306
|
// hard, loud failure — never a silent zero.
|
package/src/routes/index.ts
CHANGED
|
@@ -312,7 +312,7 @@ export function createCmsRoutes(
|
|
|
312
312
|
authz: config.authz,
|
|
313
313
|
activeWorkspaceId: config.activeWorkspaceId,
|
|
314
314
|
}),
|
|
315
|
-
frontsPublish: createFrontsPublishRoutes(
|
|
315
|
+
frontsPublish: createFrontsPublishRoutes(config),
|
|
316
316
|
foundryPublish: createFoundryPublishRoutes(config),
|
|
317
317
|
}
|
|
318
318
|
}
|
|
@@ -24,6 +24,7 @@ type CmsHooksLocals = ContentRouteConfig['hooks'] & {
|
|
|
24
24
|
dispatchFaq?: DispatchFaqHook
|
|
25
25
|
dispatchWebhook?: DispatchWebhookHook
|
|
26
26
|
publishReadiness?: PublishReadinessHook
|
|
27
|
+
podcastSourceProductionEnabled?: boolean
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -73,5 +74,6 @@ export function toContentConfig(c: APIContext): ContentRouteConfig {
|
|
|
73
74
|
dispatchFaq: hooks.dispatchFaq,
|
|
74
75
|
dispatchWebhook: hooks.dispatchWebhook,
|
|
75
76
|
publishReadiness: hooks.publishReadiness,
|
|
77
|
+
podcastSourceProductionEnabled: hooks.podcastSourceProductionEnabled,
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -5,14 +5,8 @@
|
|
|
5
5
|
// content_publication_attempts 2PC ledger. HMAC-SHA256 (X-Foundry-Signature vs
|
|
6
6
|
// env.FOUNDRY_HMAC_SECRET) only — NOT behind requirePublisher.
|
|
7
7
|
import type { APIContext } from 'astro'
|
|
8
|
-
import type { RouteContext } from '../../../routes/context.js'
|
|
9
8
|
import { createFrontsPublishRoutes } from '../../../routes/fronts-publish.js'
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
function toCtx(c: APIContext): RouteContext {
|
|
13
|
-
const env = (c.locals as { cmsEnv?: Record<string, unknown> }).cmsEnv ?? {}
|
|
14
|
-
return { request: c.request, params: {}, db: env.SITE_DB as RouteContext['db'], env }
|
|
15
|
-
}
|
|
9
|
+
import { toContentConfig, toContentCtx } from '../_content-config.js'
|
|
16
10
|
|
|
17
11
|
export const POST = (c: APIContext) =>
|
|
18
|
-
createFrontsPublishRoutes(
|
|
12
|
+
createFrontsPublishRoutes(toContentConfig(c)).publishCallback(toContentCtx(c, {}))
|
|
@@ -5,14 +5,8 @@
|
|
|
5
5
|
// env.FOUNDRY_HMAC_SECRET) only — NOT behind requirePublisher. Sibling of the
|
|
6
6
|
// content foundry-callback / insights-ingest M2M routes.
|
|
7
7
|
import type { APIContext } from 'astro'
|
|
8
|
-
import type { RouteContext } from '../../../routes/context.js'
|
|
9
8
|
import { createFrontsPublishRoutes } from '../../../routes/fronts-publish.js'
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
function toCtx(c: APIContext): RouteContext {
|
|
13
|
-
const env = (c.locals as { cmsEnv?: Record<string, unknown> }).cmsEnv ?? {}
|
|
14
|
-
return { request: c.request, params: {}, db: env.SITE_DB as RouteContext['db'], env }
|
|
15
|
-
}
|
|
9
|
+
import { toContentConfig, toContentCtx } from '../_content-config.js'
|
|
16
10
|
|
|
17
11
|
export const GET = (c: APIContext) =>
|
|
18
|
-
createFrontsPublishRoutes(
|
|
12
|
+
createFrontsPublishRoutes(toContentConfig(c)).schedule(toContentCtx(c, {}))
|