@forumone/throughline 1.1.0-pr-281-cab5a91 → 1.1.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 +12 -3
- package/bin/payload-cli.mjs +13 -2
- package/bin/payload-exit-guard.mjs +36 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @forumone/throughline
|
|
2
2
|
|
|
3
|
-
## 1.1.0
|
|
3
|
+
## 1.1.0
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- c897829: Every tool the suite serves records a `system.error` when it throws. Editorial (`find_content_needing_attention`, `get_content_calendar`, `list_my_work`, `search_content`), references (`find_references`, `can_delete`), `check_slug` and `list_job_failures` were added to the MCP collector without an audit writer, so a crash in them reached the log and nowhere else. They now record one, under four new `mcp_server` values: `editorial`, `references`, `fields`, `observability`.
|
|
8
8
|
|
|
9
9
|
**Upgrading: a migration.** The audit collection's `mcpServer` select gains four options, which on Postgres is four values on `enum_audit_events_mcp_server`. Run `migrate:create` (with `BLOB_READ_WRITE_TOKEN` set if you use the storage plugin) and apply it before deploying; nothing else changes. A plugin registered by hand without `auditPlugin` still works, and only logs a crash.
|
|
10
10
|
|
|
@@ -14,7 +14,16 @@
|
|
|
14
14
|
|
|
15
15
|
- **Confirming a decision from an approval email works on Postgres.** The action endpoint wrote the token's approver id as a string into `decidedBy`, a relationship to a users collection whose ids are numbers there, so every emailed decision failed on Confirm. It now writes the id in the users collection's type, as `request_approval` and `respond_to_approval` do since 1.0.1.
|
|
16
16
|
- **A stored request or a recorded decision is reported as one when its event cannot be sent.** `request_approval`, `respond_to_approval` and the email action endpoint wrote first and then threw if `approval/requested`, `approval/decided` or `approval/discussed` failed to send, reporting an action that had landed as failed. The tools now return it with a `warnings` entry, and the endpoint shows the approver their confirmation and logs the warning — the same rule publishing follows. `sendEventSafely` moved to a shared module for it.
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
- 8212772: `throughline-payload` fails a Payload CLI run that exits 0 without finishing.
|
|
19
|
+
|
|
20
|
+
Intermittently the Payload CLI's config `import()` never settles, and node exits
|
|
21
|
+
by itself with status 0 having printed nothing and done nothing
|
|
22
|
+
(payloadcms/payload#17757). A `migrate` that does that reports success over an
|
|
23
|
+
unmigrated database. Every Payload command that completes calls `process.exit`,
|
|
24
|
+
so the runner now preloads a guard that turns an exit nobody asked for into
|
|
25
|
+
status 70, with a message saying to run it again.
|
|
26
|
+
- @forumone/throughline-design-system@1.1.0
|
|
18
27
|
|
|
19
28
|
## 1.0.1
|
|
20
29
|
|
package/bin/payload-cli.mjs
CHANGED
|
@@ -29,6 +29,10 @@ PAYLOAD_CLI_TIMEOUT_MS sets the wall clock; 0 disables it. The default is five
|
|
|
29
29
|
minutes, except for the `migrate` family (`migrate`, `migrate:create`, …),
|
|
30
30
|
which gets none: a large migration is legitimately long, and `migrate:create`
|
|
31
31
|
can stop at an interactive prompt. Layers 1 and 3 apply regardless.
|
|
32
|
+
|
|
33
|
+
One more failure is the opposite of a hang: the CLI exits 0 having done nothing
|
|
34
|
+
(payloadcms/payload#17757). `payload-exit-guard.mjs` is preloaded into the child
|
|
35
|
+
to make that exit non-zero — see that file.
|
|
32
36
|
*/
|
|
33
37
|
import { execFile, spawn } from 'node:child_process'
|
|
34
38
|
import { createRequire } from 'node:module'
|
|
@@ -45,6 +49,13 @@ export const DEFAULT_GRACE_MS = 5_000
|
|
|
45
49
|
/** Exit code for "gave up waiting", as coreutils `timeout` uses. */
|
|
46
50
|
export const TIMEOUT_EXIT_CODE = 124
|
|
47
51
|
|
|
52
|
+
/** Preloaded into every run, so a CLI that exits 0 without finishing fails. */
|
|
53
|
+
// A URL, not a path: `--import` refuses a Windows drive path.
|
|
54
|
+
export const EXIT_GUARD = new URL('./payload-exit-guard.mjs', import.meta.url).href
|
|
55
|
+
|
|
56
|
+
/** The node argv for one run of the Payload CLI at `bin`. */
|
|
57
|
+
export const payloadArgv = (bin, args) => ['--import', EXIT_GUARD, bin, ...args]
|
|
58
|
+
|
|
48
59
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
49
60
|
const log = (message) => process.stderr.write(`throughline-payload: ${message}\n`)
|
|
50
61
|
|
|
@@ -337,7 +348,7 @@ export async function main({
|
|
|
337
348
|
if (process.platform === 'win32') {
|
|
338
349
|
// No process groups and no `ps`: run it plainly rather than not at all.
|
|
339
350
|
if (parsed.mode === 'reap') return
|
|
340
|
-
const child = spawn(process.execPath,
|
|
351
|
+
const child = spawn(process.execPath, payloadArgv(resolvePayloadBin(cwd), parsed.args), {
|
|
341
352
|
stdio: 'inherit',
|
|
342
353
|
cwd,
|
|
343
354
|
})
|
|
@@ -360,7 +371,7 @@ export async function main({
|
|
|
360
371
|
}
|
|
361
372
|
|
|
362
373
|
const store = pidFileStore(root)
|
|
363
|
-
const childArgv =
|
|
374
|
+
const childArgv = payloadArgv(bin, parsed.args)
|
|
364
375
|
const child = spawn(process.execPath, childArgv, { stdio: 'inherit', detached: true, cwd, env })
|
|
365
376
|
|
|
366
377
|
let timer
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Preloaded into the Payload CLI by `payload-cli.mjs` (`node --import`), to turn
|
|
3
|
+
one silent failure into a loud one.
|
|
4
|
+
|
|
5
|
+
Every Payload command that finishes calls `process.exit` — `0` once the work is
|
|
6
|
+
done, `1` on an error. Intermittently the config's dynamic `import()` never
|
|
7
|
+
settles instead (payloadcms/payload#17757): nothing is left on the event loop,
|
|
8
|
+
so Node exits by itself, with status 0, having printed nothing and done
|
|
9
|
+
nothing. A `migrate` that does that reports success over an unmigrated
|
|
10
|
+
database; a `generate:*` reports success over a stale file.
|
|
11
|
+
|
|
12
|
+
So a natural exit with status 0 is not success here: it is this. This module
|
|
13
|
+
records whether `process.exit` was called, and if it was not, replaces the 0
|
|
14
|
+
with NO_COMPLETION_EXIT_CODE. Any other status — a non-zero code, an uncaught
|
|
15
|
+
error, a signal — is left exactly as it was.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** EX_SOFTWARE in sysexits.h: an internal error, not a usage or data error. */
|
|
19
|
+
export const NO_COMPLETION_EXIT_CODE = 70
|
|
20
|
+
|
|
21
|
+
let called = false
|
|
22
|
+
const exit = process.exit.bind(process)
|
|
23
|
+
process.exit = (code) => {
|
|
24
|
+
called = true
|
|
25
|
+
return exit(code)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
process.on('exit', (code) => {
|
|
29
|
+
if (called || code !== 0) return
|
|
30
|
+
process.stderr.write(
|
|
31
|
+
'throughline-payload: the Payload CLI exited without finishing — it never ' +
|
|
32
|
+
'called process.exit, so the command did not run (payloadcms/payload#17757). ' +
|
|
33
|
+
'Run it again.\n',
|
|
34
|
+
)
|
|
35
|
+
process.exitCode = NO_COMPLETION_EXIT_CODE
|
|
36
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forumone/throughline",
|
|
3
|
-
"version": "1.1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Throughline: an editorial platform for Payload CMS. Publishing, approvals, audit, integrations, email and jobs, with every feature reachable over MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"dependencies": {
|
|
163
163
|
"zod": "^3.23.0",
|
|
164
164
|
"zod-to-json-schema": "^3.25.2",
|
|
165
|
-
"@forumone/throughline-design-system": "1.1.0
|
|
165
|
+
"@forumone/throughline-design-system": "1.1.0"
|
|
166
166
|
},
|
|
167
167
|
"devDependencies": {
|
|
168
168
|
"@payloadcms/db-sqlite": "^3.83.0",
|
|
@@ -184,9 +184,9 @@
|
|
|
184
184
|
"resend": "^6.1.4",
|
|
185
185
|
"typescript": "^5.6.0",
|
|
186
186
|
"vitest": "^4.1.10",
|
|
187
|
+
"@forumone/throughline-reference-ds": "0.3.10",
|
|
187
188
|
"@forumone/throughline-eslint-config": "0.0.1",
|
|
188
|
-
"@forumone/throughline-tsconfig": "0.0.1"
|
|
189
|
-
"@forumone/throughline-reference-ds": "0.3.10-pr-281-cab5a91"
|
|
189
|
+
"@forumone/throughline-tsconfig": "0.0.1"
|
|
190
190
|
},
|
|
191
191
|
"scripts": {
|
|
192
192
|
"build": "tsc -b",
|