@percher/shared 0.1.1

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.
@@ -0,0 +1,3 @@
1
+ export { DEFAULT_NODE_VERSION_LABEL, DEFAULT_NODE_VERSION_MAJOR } from "./runtime";
2
+ export { TIMEOUTS, type TimeoutKey } from "./timeouts";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { DEFAULT_NODE_VERSION_LABEL, DEFAULT_NODE_VERSION_MAJOR } from "./runtime";
2
+ export { TIMEOUTS } from "./timeouts";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Single source of truth for the Node default applied when a user app
3
+ * pins neither `.nvmrc` nor `engines.node`. Two consumers must stay
4
+ * locked together:
5
+ *
6
+ * - the build path (Nixpacks gets `DEFAULT_NODE_VERSION_MAJOR` written
7
+ * into a synthetic `.nvmrc` — see packages/api/src/nixpacks/build.ts)
8
+ * - the CLI preflight (the publish dry-run reports
9
+ * `DEFAULT_NODE_VERSION_LABEL` so users see the same version the
10
+ * server will use — see packages/core/src/commands/publish-node.ts)
11
+ *
12
+ * Pre-FUTURE14 the two ran from independent literals and drifted (API
13
+ * was bumped to 24, preflight stayed on 22 — Codex catch on de29914).
14
+ * Updating these constants here is the only edit needed when bumping
15
+ * the runtime; consumers + their tests import from this module so the
16
+ * `bun run check:runtime-currency` script alone is enough to confirm
17
+ * the bump is wired everywhere.
18
+ */
19
+ export declare const DEFAULT_NODE_VERSION_MAJOR = "24";
20
+ export declare const DEFAULT_NODE_VERSION_LABEL = "24 LTS";
21
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAC/C,eAAO,MAAM,0BAA0B,WAAsC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Single source of truth for the Node default applied when a user app
3
+ * pins neither `.nvmrc` nor `engines.node`. Two consumers must stay
4
+ * locked together:
5
+ *
6
+ * - the build path (Nixpacks gets `DEFAULT_NODE_VERSION_MAJOR` written
7
+ * into a synthetic `.nvmrc` — see packages/api/src/nixpacks/build.ts)
8
+ * - the CLI preflight (the publish dry-run reports
9
+ * `DEFAULT_NODE_VERSION_LABEL` so users see the same version the
10
+ * server will use — see packages/core/src/commands/publish-node.ts)
11
+ *
12
+ * Pre-FUTURE14 the two ran from independent literals and drifted (API
13
+ * was bumped to 24, preflight stayed on 22 — Codex catch on de29914).
14
+ * Updating these constants here is the only edit needed when bumping
15
+ * the runtime; consumers + their tests import from this module so the
16
+ * `bun run check:runtime-currency` script alone is enough to confirm
17
+ * the bump is wired everywhere.
18
+ */
19
+ export const DEFAULT_NODE_VERSION_MAJOR = "24";
20
+ export const DEFAULT_NODE_VERSION_LABEL = `${DEFAULT_NODE_VERSION_MAJOR} LTS`;
21
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAC/C,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,0BAA0B,MAAM,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Cross-process publish timeout contract.
3
+ *
4
+ * The 2026-05-07 incident batch (`dep_lvi4lrwxbjzh4q799320` and three
5
+ * siblings) was caused by the CLI publish-poll giving up at 5 min while
6
+ * the worker build subprocess + API → worker fetch wrapper kept running
7
+ * for up to 11 min. The agent saw "WORKER_UNAVAILABLE: build worker did
8
+ * not respond within 11 minutes" — but the client had already given up
9
+ * 6 minutes earlier. The platform was healthy; the timeouts were misaligned.
10
+ *
11
+ * This module is the single source of truth for every timeout that
12
+ * needs to agree across the publish pipeline. Each layer adds slack on
13
+ * top of the layer below it so a healthy build that takes the entire
14
+ * worker budget never trips an outer timeout.
15
+ *
16
+ * Stack (top to bottom = outer to inner):
17
+ *
18
+ * mcpWaitDeployMax ── outermost agent-facing wait window
19
+ * ≥ clientPublishPoll
20
+ * ≥ apiToWorkerBuildFetch + 60 s slack
21
+ * ≥ workerBuildSubprocess + 60 s slack
22
+ *
23
+ * The invariants are encoded as runtime asserts in
24
+ * `packages/shared/test/timeouts.invariants.test.ts` and gate
25
+ * `bun run review:quick` so a future PR that introduces a hard-coded
26
+ * `5 * 60_000` while server budgets stay at 10 min fails CI.
27
+ */
28
+ export declare const TIMEOUTS: {
29
+ /**
30
+ * Wall-clock build budget on the worker — enforced by the worker-side
31
+ * `setTimeout(...).proc.kill()` in `nixpacks/build.ts` and
32
+ * `nixpacks/docker-build.ts`. Beyond this the build is killed with
33
+ * exit code 124 → BUILD_TIMEOUT errorCode.
34
+ */
35
+ readonly workerBuildSubprocess: number;
36
+ /**
37
+ * API-side wrapper around the build-fetch HTTP call to the worker.
38
+ * Must exceed `workerBuildSubprocess` by at least 60 s so the worker
39
+ * has room to flush its response after killing the subprocess. If
40
+ * this fires the worker may still be running — the API treats it as
41
+ * `WORKER_UNAVAILABLE` (transient).
42
+ */
43
+ readonly apiToWorkerBuildFetch: number;
44
+ /**
45
+ * CLI/MCP sync-publish poll. Must exceed `apiToWorkerBuildFetch` by
46
+ * at least 60 s so a healthy build that fully consumes the API
47
+ * budget never preempts the client. The 2026-05-07 incident is
48
+ * exactly this invariant being violated (5 min < 11 min).
49
+ */
50
+ readonly clientPublishPoll: number;
51
+ /** Worker → /healthz self-check budget. */
52
+ readonly workerHealthcheck: 5000;
53
+ /** Pipeline watchdog list-fetch budget. */
54
+ readonly watchdogList: 15000;
55
+ /** Default `timeoutSeconds` for `percher_wait_for_deploy` MCP tool. */
56
+ readonly mcpWaitDeployDefault: 30000;
57
+ /**
58
+ * Maximum `timeoutSeconds` an MCP caller can request for a single
59
+ * `percher_wait_for_deploy` invocation. Equal to `clientPublishPoll`
60
+ * so the longest legal MCP wait can in principle ride a single
61
+ * publish all the way to live. Default stays short
62
+ * (`mcpWaitDeployDefault`) to favour resumable polling.
63
+ */
64
+ readonly mcpWaitDeployMax: number;
65
+ };
66
+ export type TimeoutKey = keyof typeof TIMEOUTS;
67
+ //# sourceMappingURL=timeouts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeouts.d.ts","sourceRoot":"","sources":["../src/timeouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,QAAQ;IACnB;;;;;OAKG;;IAGH;;;;;;OAMG;;IAGH;;;;;OAKG;;IAGH,2CAA2C;;IAG3C,2CAA2C;;IAG3C,uEAAuE;;IAGvE;;;;;;OAMG;;CAEK,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,QAAQ,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Cross-process publish timeout contract.
3
+ *
4
+ * The 2026-05-07 incident batch (`dep_lvi4lrwxbjzh4q799320` and three
5
+ * siblings) was caused by the CLI publish-poll giving up at 5 min while
6
+ * the worker build subprocess + API → worker fetch wrapper kept running
7
+ * for up to 11 min. The agent saw "WORKER_UNAVAILABLE: build worker did
8
+ * not respond within 11 minutes" — but the client had already given up
9
+ * 6 minutes earlier. The platform was healthy; the timeouts were misaligned.
10
+ *
11
+ * This module is the single source of truth for every timeout that
12
+ * needs to agree across the publish pipeline. Each layer adds slack on
13
+ * top of the layer below it so a healthy build that takes the entire
14
+ * worker budget never trips an outer timeout.
15
+ *
16
+ * Stack (top to bottom = outer to inner):
17
+ *
18
+ * mcpWaitDeployMax ── outermost agent-facing wait window
19
+ * ≥ clientPublishPoll
20
+ * ≥ apiToWorkerBuildFetch + 60 s slack
21
+ * ≥ workerBuildSubprocess + 60 s slack
22
+ *
23
+ * The invariants are encoded as runtime asserts in
24
+ * `packages/shared/test/timeouts.invariants.test.ts` and gate
25
+ * `bun run review:quick` so a future PR that introduces a hard-coded
26
+ * `5 * 60_000` while server budgets stay at 10 min fails CI.
27
+ */
28
+ export const TIMEOUTS = {
29
+ /**
30
+ * Wall-clock build budget on the worker — enforced by the worker-side
31
+ * `setTimeout(...).proc.kill()` in `nixpacks/build.ts` and
32
+ * `nixpacks/docker-build.ts`. Beyond this the build is killed with
33
+ * exit code 124 → BUILD_TIMEOUT errorCode.
34
+ */
35
+ workerBuildSubprocess: 10 * 60_000,
36
+ /**
37
+ * API-side wrapper around the build-fetch HTTP call to the worker.
38
+ * Must exceed `workerBuildSubprocess` by at least 60 s so the worker
39
+ * has room to flush its response after killing the subprocess. If
40
+ * this fires the worker may still be running — the API treats it as
41
+ * `WORKER_UNAVAILABLE` (transient).
42
+ */
43
+ apiToWorkerBuildFetch: 11 * 60_000,
44
+ /**
45
+ * CLI/MCP sync-publish poll. Must exceed `apiToWorkerBuildFetch` by
46
+ * at least 60 s so a healthy build that fully consumes the API
47
+ * budget never preempts the client. The 2026-05-07 incident is
48
+ * exactly this invariant being violated (5 min < 11 min).
49
+ */
50
+ clientPublishPoll: 12 * 60_000,
51
+ /** Worker → /healthz self-check budget. */
52
+ workerHealthcheck: 5_000,
53
+ /** Pipeline watchdog list-fetch budget. */
54
+ watchdogList: 15_000,
55
+ /** Default `timeoutSeconds` for `percher_wait_for_deploy` MCP tool. */
56
+ mcpWaitDeployDefault: 30_000,
57
+ /**
58
+ * Maximum `timeoutSeconds` an MCP caller can request for a single
59
+ * `percher_wait_for_deploy` invocation. Equal to `clientPublishPoll`
60
+ * so the longest legal MCP wait can in principle ride a single
61
+ * publish all the way to live. Default stays short
62
+ * (`mcpWaitDeployDefault`) to favour resumable polling.
63
+ */
64
+ mcpWaitDeployMax: 12 * 60_000,
65
+ };
66
+ //# sourceMappingURL=timeouts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeouts.js","sourceRoot":"","sources":["../src/timeouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB;;;;;OAKG;IACH,qBAAqB,EAAE,EAAE,GAAG,MAAM;IAElC;;;;;;OAMG;IACH,qBAAqB,EAAE,EAAE,GAAG,MAAM;IAElC;;;;;OAKG;IACH,iBAAiB,EAAE,EAAE,GAAG,MAAM;IAE9B,2CAA2C;IAC3C,iBAAiB,EAAE,KAAK;IAExB,2CAA2C;IAC3C,YAAY,EAAE,MAAM;IAEpB,uEAAuE;IACvE,oBAAoB,EAAE,MAAM;IAE5B;;;;;;OAMG;IACH,gBAAgB,EAAE,EAAE,GAAG,MAAM;CACrB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@percher/shared",
3
+ "version": "0.1.1",
4
+ "description": "Shared constants and contracts (timeouts, etc.) used across the Percher CLI, API, MCP, and worker. Internal — values change in lockstep across packages.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./timeouts": {
15
+ "types": "./dist/timeouts.d.ts",
16
+ "import": "./dist/timeouts.js",
17
+ "default": "./dist/timeouts.js"
18
+ },
19
+ "./runtime": {
20
+ "types": "./dist/runtime.d.ts",
21
+ "import": "./dist/runtime.js",
22
+ "default": "./dist/runtime.js"
23
+ }
24
+ },
25
+ "files": ["dist"],
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.json",
28
+ "test": "bun test",
29
+ "typecheck": "tsc --noEmit"
30
+ },
31
+ "devDependencies": {
32
+ "bun-types": "^1.1.0"
33
+ },
34
+ "license": "MIT",
35
+ "author": "Mattias Malmborg",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/mattiasmalmborg/percher",
39
+ "directory": "packages/shared"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ }
44
+ }