@forumone/throughline-workflows 0.3.0 → 0.4.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @forumone/throughline-workflows
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 35060e5: Scheduled publishing works from the admin, publishes on time, and cleans up after itself.
8
+
9
+ A schedule set from the admin never published. It was written by a draft save,
10
+ Payload keeps a draft save in the versions table only, and the cron read the main
11
+ row — so only a schedule written over MCP, by a non-draft update, was ever found.
12
+ - **publishing**: a Schedule control replaces the scheduled-publish date field on
13
+ any collection that declares one, and runs the pipeline's checks when a time is
14
+ picked. An approval not yet granted, or an embargo that ends first, schedules
15
+ with a warning rather than refusing. `schedule` and `unschedule` admin
16
+ endpoints, `PublishingService.schedule` / `.unschedule`, and
17
+ `scheduleDocument` / `unscheduleDocument`; `schedule_publish` now calls the
18
+ service and writes the time as a draft. An `afterChange` hook sends
19
+ `content/page.scheduled` whenever the time changes, whichever route set it.
20
+ Publishing and unpublishing clear the time, so an unpublished page can no longer
21
+ put itself back up.
22
+ - **workflows**: `createPublishAtScheduledTimeFunction` sleeps until the scheduled
23
+ time instead of polling, in six-day hops for schedules further out.
24
+ `createExecuteScheduledPublishesFunction` reads the latest version
25
+ (`draft: true`) and takes `overdueByMs`, for running it as a backstop.
26
+
27
+ ## 0.3.1
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [d02772f]
32
+ - @forumone/throughline-core@0.9.1
33
+
3
34
  ## 0.3.0
4
35
 
5
36
  ### Minor Changes
package/README.md CHANGED
@@ -9,7 +9,8 @@ This package has **no Payload plugin** — it exports factories only. Workflows
9
9
  | Factory | What it does |
10
10
  |---|---|
11
11
  | `createRevalidateOnPublishFunction` | Invalidates Next.js caches for the page, listings, and sitemap when content publishes |
12
- | `createExecuteScheduledPublishesFunction` | Cron-driven scheduled publish executor that calls through the Publishing Server's MCP |
12
+ | `createPublishAtScheduledTimeFunction` | Publishes a document at its scheduled time by sleeping until then, woken by `content/page.scheduled` |
13
+ | `createExecuteScheduledPublishesFunction` | Cron that publishes any document past its scheduled time — the backstop for the one above, or a poller on its own |
13
14
  | `createExpireStaleApprovalsFunction` | Daily cron that flips pending approvals past `expiresAt` to `expired` and fires an `approval/expired` event |
14
15
  | `createAuditEventEchoFunction` | Fan-out point: turns `audit/event.recorded` into `notification/send-approval-*` events plus custom handlers |
15
16
  | `createHealthcheckFunction` | Periodic health monitoring with configurable checks |
@@ -93,6 +94,46 @@ createRevalidateOnPublishFunction({
93
94
 
94
95
  `next` is declared as an optional peer (`peerDependenciesMeta.next.optional = true`) so non-Next consumers don't see a missing-peer warning.
95
96
 
97
+ ## Scheduled publishing: sleep, don't poll
98
+
99
+ `createPublishAtScheduledTimeFunction` is woken by `content/page.scheduled` — which
100
+ the publishing plugin sends whenever a document's scheduled time changes — sleeps
101
+ until that time, re-reads the document, and publishes it only if the document still
102
+ carries that exact time. The document is the source of truth and the event is a
103
+ wake-up call, so a reschedule, a cancellation, or a publish or unpublish in the
104
+ meantime needs no cancellation event: the old run wakes, finds the time changed, and
105
+ ends.
106
+
107
+ It publishes on the minute and costs a few steps per schedule. The poller costs two
108
+ executions per tick whether or not anything is due — at `*/15` that is 5,760 a month
109
+ to find, almost always, nothing.
110
+
111
+ A schedule more than six days out is carried in hops: the run sleeps six days,
112
+ re-sends the event and ends, so no single sleep passes the seven-day cap on
113
+ Inngest's free plan and no run approaches its thirty-day limit. Set `maxSleepMs` on
114
+ a paid plan if you prefer fewer hops.
115
+
116
+ Run the poller alongside it as a backstop for an event that never arrived, on a slow
117
+ schedule and with `overdueByMs`, so the two never reach a just-due document in the
118
+ same moment:
119
+
120
+ ```ts
121
+ createPublishAtScheduledTimeFunction({ inngest, payload, collections, publish }),
122
+ createExecuteScheduledPublishesFunction({
123
+ inngest,
124
+ payload,
125
+ collections,
126
+ publish,
127
+ schedule: '17 3 * * *',
128
+ overdueByMs: 60 * 60 * 1000,
129
+ }),
130
+ ```
131
+
132
+ Both read the document's **latest version** (`draft: true`). A schedule is written
133
+ by a draft save, and Payload writes a draft save to the versions table only, so the
134
+ main row never carries it — and reading the versions is also what lets a revision
135
+ of a live document be scheduled.
136
+
96
137
  ## Why scheduled publishes go through the pipeline
97
138
 
98
139
  `createExecuteScheduledPublishesFunction` never writes to Payload. It finds what is
@@ -154,7 +195,8 @@ Each handler runs in its own `step.run`, so failures isolate.
154
195
  Every factory takes a typed options object. See `src/types.ts` for the full surface — defaults documented there:
155
196
 
156
197
  - `RevalidateOnPublishOptions` — `revalidate?`, `urlBuilders?`, `collectionTags?`, `id?`
157
- - `ExecuteScheduledPublishesOptions` — `collections[]`, `publishingServerUrl`, `publishingApiKey?` (env fallback), `schedule?` (default `*/5 * * * *`), `id?`
198
+ - `PublishAtScheduledTimeOptions` — `collections[]`, `publish`, `maxSleepMs?` (default six days), `id?`
199
+ - `ExecuteScheduledPublishesOptions` — `collections[]`, `publish`, `schedule?` (default `*/5 * * * *`), `overdueByMs?` (default 0), `id?`
158
200
  - `ExpireStaleApprovalsOptions` — `collectionSlug?` (default `approvals`), `schedule?` (default `0 2 * * *`), `id?`
159
201
  - `AuditEventEchoOptions` — `handlers?`, `id?`
160
202
  - `HealthcheckOptions` — `checks[]`, `schedule?` (default `*/15 * * * *`), `onFailure?`, `id?`
@@ -3,9 +3,13 @@ import type { ExecuteScheduledPublishesOptions } from './types.js';
3
3
  /**
4
4
  * Cron-driven scheduled publish executor. Every tick (default: every 5
5
5
  * minutes) the function looks for documents in any of the configured
6
- * collections whose `_status` is still `draft` and whose
6
+ * collections whose latest version is still a draft and whose
7
7
  * `scheduledPublishAt` has passed, and calls `options.publish` for each.
8
8
  *
9
+ * `createPublishAtScheduledTimeFunction` does the same job on time and without
10
+ * polling. Run alongside it, this is the backstop — set `overdueByMs` and a
11
+ * slow schedule, and it only ever finds a document whose event went missing.
12
+ *
9
13
  * `publish` must go through the publishing pipeline — see the option's own
10
14
  * documentation for the wiring. That is what makes a scheduled publish get the
11
15
  * same composition / accessibility / approval checks as an interactive one.
@@ -1 +1 @@
1
- {"version":3,"file":"execute-scheduled-publishes.d.ts","sourceRoot":"","sources":["../src/execute-scheduled-publishes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAA;AAWlE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,gCAAgC,GACxC,eAAe,CAAC,GAAG,CAuFrB"}
1
+ {"version":3,"file":"execute-scheduled-publishes.d.ts","sourceRoot":"","sources":["../src/execute-scheduled-publishes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAA;AAWlE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,gCAAgC,GACxC,eAAe,CAAC,GAAG,CAiGrB"}
@@ -4,9 +4,13 @@ const REASONING = 'Scheduled publish executed by workflow cron';
4
4
  /**
5
5
  * Cron-driven scheduled publish executor. Every tick (default: every 5
6
6
  * minutes) the function looks for documents in any of the configured
7
- * collections whose `_status` is still `draft` and whose
7
+ * collections whose latest version is still a draft and whose
8
8
  * `scheduledPublishAt` has passed, and calls `options.publish` for each.
9
9
  *
10
+ * `createPublishAtScheduledTimeFunction` does the same job on time and without
11
+ * polling. Run alongside it, this is the backstop — set `overdueByMs` and a
12
+ * slow schedule, and it only ever finds a document whose event went missing.
13
+ *
10
14
  * `publish` must go through the publishing pipeline — see the option's own
11
15
  * documentation for the wiring. That is what makes a scheduled publish get the
12
16
  * same composition / accessibility / approval checks as an interactive one.
@@ -33,7 +37,7 @@ export function createExecuteScheduledPublishesFunction(options) {
33
37
  ...failureOptions(options, 1),
34
38
  triggers: [{ cron: schedule }],
35
39
  }, async ({ step, logger }) => {
36
- const nowIso = new Date().toISOString();
40
+ const dueBy = new Date(Date.now() - (options.overdueByMs ?? 0)).toISOString();
37
41
  let publishedCount = 0;
38
42
  let blockedCount = 0;
39
43
  for (const config of options.collections) {
@@ -46,9 +50,19 @@ export function createExecuteScheduledPublishesFunction(options) {
46
50
  and: [
47
51
  { [statusField]: { equals: 'draft' } },
48
52
  { [scheduledField]: { exists: true } },
49
- { [scheduledField]: { less_than_equal: nowIso } },
53
+ { [scheduledField]: { less_than_equal: dueBy } },
50
54
  ],
51
55
  },
56
+ /*
57
+ The latest version, not the main row. A schedule is set by a draft
58
+ save, and Payload writes a draft save to the versions table alone —
59
+ so without this the poll read a column that the admin never wrote,
60
+ and only a schedule set over MCP, by a non-draft update, was ever
61
+ found. It is also what lets a revision of a live document be
62
+ scheduled: its latest version is a draft even while the main row
63
+ says `published`.
64
+ */
65
+ draft: true,
52
66
  limit: 100,
53
67
  });
54
68
  return result.docs.map((doc) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"execute-scheduled-publishes.js","sourceRoot":"","sources":["../src/execute-scheduled-publishes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAI3C,MAAM,gBAAgB,GAAG,aAAa,CAAA;AACtC,MAAM,SAAS,GAAG,6CAA6C,CAAA;AAQ/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uCAAuC,CACrD,OAAyC;IAEzC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,gBAAgB,CAAA;IAErD,OAAO,OAAO,CAAC,OAAO,CAAC,cAAc,CACnC;QACE,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,6BAA6B;QAC/C;;;;;;;;;UASE;QACF,GAAG,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7B,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;KAC/B,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QACzB,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACvC,IAAI,cAAc,GAAG,CAAC,CAAA;QACtB,IAAI,YAAY,GAAG,CAAC,CAAA;QAEpB,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACzC,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,SAAS,CAAA;YACnD,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,oBAAoB,CAAA;YAEpE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,IAAuB,EAAE;gBAClF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;oBACxC,UAAU,EAAE,MAAM,CAAC,IAAI;oBACvB,KAAK,EAAE;wBACL,GAAG,EAAE;4BACH,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;4BACtC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;4BACtC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE;yBAClD;qBACF;oBACD,KAAK,EAAE,GAAG;iBACX,CAAC,CAAA;gBACF,OAAQ,MAAM,CAAC,IAAuC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBACnE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACrB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;oBACxC,UAAU,EAAE,MAAM,CAAC,IAAI;iBACxB,CAAC,CAAC,CAAA;YACL,CAAC,CAAC,CAAA;YAEF,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;gBACtB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAC5B,WAAW,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,EAAE,EAClC,KAAK,IAAgD,EAAE;oBACrD,IAAI,MAAM,CAAA;oBACV,IAAI,CAAC;wBACH,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;4BAC7B,UAAU,EAAE,GAAG,CAAC,UAAU;4BAC1B,EAAE,EAAE,GAAG,CAAC,EAAE;4BACV,SAAS,EAAE,SAAS;yBACrB,CAAC,CAAA;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;4BACtC,QAAQ,EAAE,GAAG,CAAC,KAAK;4BACnB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;yBAC9D,CAAC,CAAA;wBACF,OAAO,OAAO,CAAA;oBAChB,CAAC;oBAED,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;wBACtB,MAAM,CAAC,IAAI,CAAC,qCAAqC,EAAE;4BACjD,QAAQ,EAAE,GAAG,CAAC,KAAK;4BACnB,MAAM,EAAE,MAAM,CAAC,MAAM;yBACtB,CAAC,CAAA;wBACF,OAAO,SAAS,CAAA;oBAClB,CAAC;oBAED,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAA;oBACnE,OAAO,WAAW,CAAA;gBACpB,CAAC,CACF,CAAA;gBACD,IAAI,OAAO,KAAK,WAAW;oBAAE,cAAc,IAAI,CAAC,CAAA;gBAChD,IAAI,OAAO,KAAK,SAAS;oBAAE,YAAY,IAAI,CAAC,CAAA;YAC9C,CAAC;QACH,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAA;QAChF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,CAAA;IACzC,CAAC,CACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"execute-scheduled-publishes.js","sourceRoot":"","sources":["../src/execute-scheduled-publishes.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  export { createRevalidateOnPublishFunction } from './revalidate-on-publish.js';
2
2
  export { createExecuteScheduledPublishesFunction } from './execute-scheduled-publishes.js';
3
+ export { createPublishAtScheduledTimeFunction } from './publish-at-scheduled-time.js';
3
4
  export { createExpireStaleApprovalsFunction } from './expire-stale-approvals.js';
4
5
  export { createAuditEventEchoFunction } from './audit-event-echo.js';
5
6
  export { createHealthcheckFunction, createPayloadReachableCheck, createManifestReachableCheck, } from './healthcheck.js';
6
7
  export { failureOptions } from './types.js';
7
- export type { BaseWorkflowOptions, WorkflowFailureHandler, FailureAwareOptions, RevalidateFn, RevalidatePathsInput, RevalidateOnPublishOptions, ScheduledCollectionConfig, ExecuteScheduledPublishesOptions, ExpireStaleApprovalsOptions, AuditEchoEvent, AuditEchoHandler, AuditEventEchoOptions, HealthcheckDefinition, HealthcheckOptions, HealthcheckResult, } from './types.js';
8
+ export type { BaseWorkflowOptions, WorkflowFailureHandler, FailureAwareOptions, RevalidateFn, RevalidatePathsInput, RevalidateOnPublishOptions, ScheduledCollectionConfig, ExecuteScheduledPublishesOptions, PublishAtScheduledTimeOptions, ScheduledPublishRequest, ScheduledPublishResult, ExpireStaleApprovalsOptions, AuditEchoEvent, AuditEchoHandler, AuditEventEchoOptions, HealthcheckDefinition, HealthcheckOptions, HealthcheckResult, } from './types.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAA;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,kCAAkC,CAAA;AAC1F,OAAO,EAAE,kCAAkC,EAAE,MAAM,6BAA6B,CAAA;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,2BAA2B,EAC3B,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAA;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,kCAAkC,CAAA;AAC1F,OAAO,EAAE,oCAAoC,EAAE,MAAM,gCAAgC,CAAA;AACrF,OAAO,EAAE,kCAAkC,EAAE,MAAM,6BAA6B,CAAA;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EACpB,0BAA0B,EAC1B,yBAAyB,EACzB,gCAAgC,EAChC,6BAA6B,EAC7B,uBAAuB,EACvB,sBAAsB,EACtB,2BAA2B,EAC3B,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // Other factory exports land in subsequent commits.
2
2
  export { createRevalidateOnPublishFunction } from './revalidate-on-publish.js';
3
3
  export { createExecuteScheduledPublishesFunction } from './execute-scheduled-publishes.js';
4
+ export { createPublishAtScheduledTimeFunction } from './publish-at-scheduled-time.js';
4
5
  export { createExpireStaleApprovalsFunction } from './expire-stale-approvals.js';
5
6
  export { createAuditEventEchoFunction } from './audit-event-echo.js';
6
7
  export { createHealthcheckFunction, createPayloadReachableCheck, createManifestReachableCheck, } from './healthcheck.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAA;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,kCAAkC,CAAA;AAC1F,OAAO,EAAE,kCAAkC,EAAE,MAAM,6BAA6B,CAAA;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAA;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,kCAAkC,CAAA;AAC1F,OAAO,EAAE,oCAAoC,EAAE,MAAM,gCAAgC,CAAA;AACrF,OAAO,EAAE,kCAAkC,EAAE,MAAM,6BAA6B,CAAA;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,23 @@
1
+ import type { InngestFunction } from 'inngest';
2
+ import type { PublishAtScheduledTimeOptions } from './types.js';
3
+ /**
4
+ * Publishes a document at the moment it was scheduled for, by sleeping until
5
+ * then — rather than polling for due documents.
6
+ *
7
+ * Triggered by `content/page.scheduled`, which the publishing plugin sends
8
+ * whenever a document's scheduled time changes to a new value. The event is a
9
+ * wake-up call and nothing more: **the document is the source of truth.** On
10
+ * waking, the run re-reads the document's latest version and publishes only if
11
+ * it still carries this exact time. So a reschedule, a cancellation, a manual
12
+ * publish in the meantime or an unpublish — each of which changes or clears
13
+ * the field — leaves the old run to wake, find nothing to do, and end. No
14
+ * cancellation event has to arrive for that to be correct, and a duplicate
15
+ * event cannot publish twice (the `idempotency` key drops the second anyway).
16
+ *
17
+ * `publish` must go through the publishing pipeline, exactly as for
18
+ * `createExecuteScheduledPublishesFunction`: a scheduled publish gets the same
19
+ * composition / accessibility / approval checks as an interactive one, and a
20
+ * refusal is logged, not retried.
21
+ */
22
+ export declare function createPublishAtScheduledTimeFunction(options: PublishAtScheduledTimeOptions): InngestFunction.Any;
23
+ //# sourceMappingURL=publish-at-scheduled-time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-at-scheduled-time.d.ts","sourceRoot":"","sources":["../src/publish-at-scheduled-time.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,KAAK,EAAE,6BAA6B,EAA6B,MAAM,YAAY,CAAA;AA8B1F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,6BAA6B,GACrC,eAAe,CAAC,GAAG,CA4FrB"}
@@ -0,0 +1,133 @@
1
+ import { failureOptions } from './types.js';
2
+ const SCHEDULED_EVENT = 'content/page.scheduled';
3
+ const REASONING = 'Scheduled publish executed at its scheduled time';
4
+ /*
5
+ Six days, under the seven Inngest's free plan allows a single sleep.
6
+
7
+ A schedule further out than one hop is carried by a relay: the run sleeps a
8
+ hop, then re-sends the event and ends, so each leg is its own run. That also
9
+ keeps every run far inside the free plan's thirty-day run duration, which a
10
+ loop of sleeps inside one run would not — a post scheduled for next quarter
11
+ would simply be killed.
12
+ */
13
+ const DEFAULT_MAX_SLEEP_MS = 6 * 24 * 60 * 60 * 1000;
14
+ /**
15
+ * Publishes a document at the moment it was scheduled for, by sleeping until
16
+ * then — rather than polling for due documents.
17
+ *
18
+ * Triggered by `content/page.scheduled`, which the publishing plugin sends
19
+ * whenever a document's scheduled time changes to a new value. The event is a
20
+ * wake-up call and nothing more: **the document is the source of truth.** On
21
+ * waking, the run re-reads the document's latest version and publishes only if
22
+ * it still carries this exact time. So a reschedule, a cancellation, a manual
23
+ * publish in the meantime or an unpublish — each of which changes or clears
24
+ * the field — leaves the old run to wake, find nothing to do, and end. No
25
+ * cancellation event has to arrive for that to be correct, and a duplicate
26
+ * event cannot publish twice (the `idempotency` key drops the second anyway).
27
+ *
28
+ * `publish` must go through the publishing pipeline, exactly as for
29
+ * `createExecuteScheduledPublishesFunction`: a scheduled publish gets the same
30
+ * composition / accessibility / approval checks as an interactive one, and a
31
+ * refusal is logged, not retried.
32
+ */
33
+ export function createPublishAtScheduledTimeFunction(options) {
34
+ const maxSleepMs = options.maxSleepMs ?? DEFAULT_MAX_SLEEP_MS;
35
+ const collections = new Map(options.collections.map((c) => [c.slug, c]));
36
+ return options.inngest.createFunction({
37
+ id: options.id ?? 'publish-at-scheduled-time',
38
+ /*
39
+ One run per schedule. The plugin sends once per change, but an MCP
40
+ schedule and the field hook seeing the same write, or a retried send,
41
+ would otherwise start two sleepers that both wake and both publish.
42
+ Inngest keeps this key for 24 hours, and a relay is six days after the
43
+ event that started its leg, so a relay is never mistaken for a duplicate.
44
+ */
45
+ idempotency: 'event.data.collection + ":" + event.data.id + ":" + event.data.scheduledFor',
46
+ ...failureOptions(options),
47
+ triggers: [{ event: SCHEDULED_EVENT }],
48
+ }, async ({ event, step, logger }) => {
49
+ const data = event.data;
50
+ const config = data.collection ? collections.get(data.collection) : undefined;
51
+ const target = typeof data.scheduledFor === 'string' ? Date.parse(data.scheduledFor) : NaN;
52
+ if (!config || !data.id || !data.scheduledFor || Number.isNaN(target)) {
53
+ return { outcome: 'ignored', reason: 'not a scheduled publish this function handles' };
54
+ }
55
+ const request = { collection: config.slug, id: data.id, scheduledFor: data.scheduledFor };
56
+ /*
57
+ Measured from the event's own timestamp, not the clock. Inngest replays
58
+ the handler from the top after every step, so a `Date.now()` here would
59
+ give a different answer on each replay — and flipping from the relay
60
+ branch to the direct branch halfway through a run is a run whose steps
61
+ no longer match its history.
62
+ */
63
+ const startedAt = typeof event.ts === 'number' ? event.ts : Date.now();
64
+ if (target - startedAt > maxSleepMs) {
65
+ const hopUntil = new Date(startedAt + maxSleepMs);
66
+ await step.sleepUntil('wait-one-hop', hopUntil);
67
+ // Only relay a schedule that still stands, or a cancelled one would
68
+ // keep re-sending itself every six days until its date came round.
69
+ const current = await step.run('check-still-scheduled', () => isStillScheduled(options, config, request));
70
+ if (!current)
71
+ return { outcome: 'superseded' };
72
+ await step.sendEvent('relay', { name: SCHEDULED_EVENT, data: request });
73
+ return { outcome: 'relayed', hopUntil: hopUntil.toISOString() };
74
+ }
75
+ await step.sleepUntil('wait-until-due', new Date(target));
76
+ const due = await step.run('check-still-scheduled', () => isStillScheduled(options, config, request));
77
+ if (!due) {
78
+ logger.info('Scheduled publish superseded', request);
79
+ return { outcome: 'superseded' };
80
+ }
81
+ return step.run('publish', async () => {
82
+ try {
83
+ const result = await options.publish({
84
+ collection: config.slug,
85
+ id: request.id,
86
+ reasoning: REASONING,
87
+ });
88
+ if (!result.published) {
89
+ logger.warn('Scheduled publish blocked by policy', {
90
+ ...request,
91
+ reason: result.reason,
92
+ });
93
+ return { outcome: 'blocked', reason: result.reason };
94
+ }
95
+ logger.info('Scheduled publish succeeded', request);
96
+ return { outcome: 'published' };
97
+ }
98
+ catch (error) {
99
+ /*
100
+ Not rethrown. A retry would re-run the pipeline against the same
101
+ document, and the daily backstop in
102
+ `createExecuteScheduledPublishesFunction` already comes back for a
103
+ document that is still a draft past its time.
104
+ */
105
+ const reason = error instanceof Error ? error.message : String(error);
106
+ logger.error('Scheduled publish threw', { ...request, error: reason });
107
+ return { outcome: 'error', reason };
108
+ }
109
+ });
110
+ });
111
+ }
112
+ /**
113
+ * Whether the document's latest version still carries this schedule.
114
+ *
115
+ * `draft: true`, because a schedule is written by a draft save and Payload
116
+ * writes a draft save to the versions table only — the main row is not
117
+ * touched, so a read without it would see a document with no schedule at all.
118
+ */
119
+ async function isStillScheduled(options, config, request) {
120
+ const field = config.scheduledField ?? 'scheduledPublishAt';
121
+ const doc = (await options.payload.findByID({
122
+ collection: config.slug,
123
+ id: request.id,
124
+ draft: true,
125
+ depth: 0,
126
+ disableErrors: true,
127
+ }));
128
+ const value = doc?.[field];
129
+ if (typeof value !== 'string')
130
+ return false;
131
+ return Date.parse(value) === Date.parse(request.scheduledFor);
132
+ }
133
+ //# sourceMappingURL=publish-at-scheduled-time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-at-scheduled-time.js","sourceRoot":"","sources":["../src/publish-at-scheduled-time.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -172,9 +172,36 @@ export interface ExecuteScheduledPublishesOptions extends BaseWorkflowOptions {
172
172
  * URL sat behind access protection.
173
173
  */
174
174
  publish: (request: ScheduledPublishRequest) => Promise<ScheduledPublishResult>;
175
+ /**
176
+ * Leave a document alone until it is this many milliseconds past its time.
177
+ * Default: 0.
178
+ *
179
+ * For a host that also runs `createPublishAtScheduledTimeFunction`, which
180
+ * publishes on time and makes this poll a backstop for an event that never
181
+ * arrived. Without a grace period the two can reach the same due document in
182
+ * the same moment and publish it twice.
183
+ */
184
+ overdueByMs?: number;
175
185
  /** Override the function id. Default: `execute-scheduled-publishes`. */
176
186
  id?: string;
177
187
  }
188
+ export interface PublishAtScheduledTimeOptions extends BaseWorkflowOptions {
189
+ /**
190
+ * Collections that participate in scheduled publishing. An event naming any
191
+ * other collection is ignored.
192
+ */
193
+ collections: ScheduledCollectionConfig[];
194
+ /** How to publish one document. The same contract, and the same warning, as `ExecuteScheduledPublishesOptions.publish`. */
195
+ publish: (request: ScheduledPublishRequest) => Promise<ScheduledPublishResult>;
196
+ /**
197
+ * The longest single sleep, in milliseconds. A schedule further out is
198
+ * reached by relaying the event. Default: six days — Inngest's free plan caps
199
+ * a sleep at seven.
200
+ */
201
+ maxSleepMs?: number;
202
+ /** Override the function id. Default: `publish-at-scheduled-time`. */
203
+ id?: string;
204
+ }
178
205
  export interface ExpireStaleApprovalsOptions extends BaseWorkflowOptions {
179
206
  /** Approvals collection slug. Default: 'approvals'. */
180
207
  collectionSlug?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forumone/throughline-workflows",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Composable Inngest function factories for the Throughline framework — revalidation, scheduled publishing, approval expiration, audit fan-out, healthcheck.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -46,11 +46,11 @@
46
46
  }
47
47
  },
48
48
  "dependencies": {
49
- "@forumone/throughline-core": "0.9.0"
49
+ "@forumone/throughline-core": "0.9.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^24.13.2",
53
- "eslint": "^9.15.0",
53
+ "eslint": "^10.11.0",
54
54
  "inngest": "^4.2.0",
55
55
  "next": "^16.2.4",
56
56
  "payload": "^3.83.0",