@percher/shared 0.1.9 → 1.0.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.
Files changed (53) hide show
  1. package/LICENSE +132 -0
  2. package/dist/brand.d.ts +64 -0
  3. package/dist/brand.d.ts.map +1 -0
  4. package/dist/brand.js +67 -0
  5. package/dist/brand.js.map +1 -0
  6. package/dist/client-ip-attestation.d.ts +67 -0
  7. package/dist/client-ip-attestation.d.ts.map +1 -0
  8. package/dist/client-ip-attestation.js +74 -0
  9. package/dist/client-ip-attestation.js.map +1 -0
  10. package/dist/index.d.ts +9 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +9 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/legal-changes.d.ts +118 -0
  15. package/dist/legal-changes.d.ts.map +1 -0
  16. package/dist/legal-changes.js +135 -0
  17. package/dist/legal-changes.js.map +1 -0
  18. package/dist/legal.d.ts +52 -9
  19. package/dist/legal.d.ts.map +1 -1
  20. package/dist/legal.js +47 -8
  21. package/dist/legal.js.map +1 -1
  22. package/dist/limits.d.ts +8 -0
  23. package/dist/limits.d.ts.map +1 -1
  24. package/dist/limits.js +8 -0
  25. package/dist/limits.js.map +1 -1
  26. package/dist/oauth-client-name.d.ts +22 -0
  27. package/dist/oauth-client-name.d.ts.map +1 -0
  28. package/dist/oauth-client-name.js +37 -0
  29. package/dist/oauth-client-name.js.map +1 -0
  30. package/dist/oauth-scopes.d.ts +19 -0
  31. package/dist/oauth-scopes.d.ts.map +1 -0
  32. package/dist/oauth-scopes.js +31 -0
  33. package/dist/oauth-scopes.js.map +1 -0
  34. package/dist/platform-env.d.ts.map +1 -1
  35. package/dist/platform-env.js +6 -0
  36. package/dist/platform-env.js.map +1 -1
  37. package/dist/platform.d.ts +1 -1
  38. package/dist/platform.d.ts.map +1 -1
  39. package/dist/platform.js +1 -1
  40. package/dist/platform.js.map +1 -1
  41. package/dist/signup-invite-hash.d.ts +8 -0
  42. package/dist/signup-invite-hash.d.ts.map +1 -0
  43. package/dist/signup-invite-hash.js +11 -0
  44. package/dist/signup-invite-hash.js.map +1 -0
  45. package/dist/signup-invite.d.ts +23 -0
  46. package/dist/signup-invite.d.ts.map +1 -0
  47. package/dist/signup-invite.js +29 -0
  48. package/dist/signup-invite.js.map +1 -0
  49. package/dist/timeouts.d.ts +85 -0
  50. package/dist/timeouts.d.ts.map +1 -1
  51. package/dist/timeouts.js +84 -0
  52. package/dist/timeouts.js.map +1 -1
  53. package/package.json +12 -2
@@ -64,4 +64,89 @@ export declare const TIMEOUTS: {
64
64
  readonly mcpWaitDeployMax: number;
65
65
  };
66
66
  export type TimeoutKey = keyof typeof TIMEOUTS;
67
+ /**
68
+ * Bun refuses a `Bun.serve({ idleTimeout })` above this and throws at boot
69
+ * ("Bun.serve expects idleTimeout to be 255 or less"). Measured on Bun 1.3.14,
70
+ * the version `packages/api/Dockerfile` and `packages/mcp/Dockerfile` both
71
+ * digest-pin, on linux and win32. It is a hard ceiling, not a guideline: an
72
+ * operation whose budget exceeds it can never be covered by a server-wide
73
+ * value and has to be exempted per route
74
+ * (`packages/api/src/http/scoped-idle-timeout.ts`) or made job-based.
75
+ */
76
+ export declare const BUN_MAX_IDLE_TIMEOUT_SECONDS = 255;
77
+ /**
78
+ * Transport-level idle timeout, in SECONDS, for each `Bun.serve` Percher runs.
79
+ * (Every other budget in this file is in milliseconds; Bun's option is
80
+ * seconds, so the unit is in the name.)
81
+ *
82
+ * Bun's default is 10 s, and leaving it there is how a healthy request dies of
83
+ * something unrelated to itself. 2026-09-08: a supervised admin POST to
84
+ * `/admin/migrate-networks` returned `curl: (52) Empty reply from server`
85
+ * while the same log window held `[watchdog] WARNING: disk usage 80% —
86
+ * triggering auto-prune` and `[Bun.serve]: request timed out after 10
87
+ * seconds`. Identical earlier runs answered in under 10 s; concurrent pruning
88
+ * was observed, but the log timing alone does not prove the cause of the delay.
89
+ * The client had budgeted 900 s.
90
+ *
91
+ * Two measurements shape these numbers. Both were taken with curl against a
92
+ * real `Bun.serve` on the pinned 1.3.14 linux image:
93
+ *
94
+ * - A request whose body is EMPTY (`GET`, or `curl -X POST` with no `-d`) is
95
+ * reset at the idle timeout: 200 at 8 s, `curl: (52)` at ~12 s.
96
+ * - A request carrying a non-empty body survived the measured 30 s handler,
97
+ * answering 200 under both the 10 s default and a 2 s override.
98
+ *
99
+ * That asymmetry is undocumented, so nothing may depend on it, but it does
100
+ * explain the shape of the incident report: the long-held bodied calls
101
+ * (`/build/nixpacks`, held for up to `workerBuildSubprocess`) never showed a
102
+ * symptom, while every bodyless operator `-X POST` and the watchdog's own
103
+ * non-aggressive `POST /docker/prune` were being cut at 10 s.
104
+ *
105
+ * Each value must outlive the longest SYNCHRONOUS request that surface
106
+ * legitimately serves. Anything longer than {@link BUN_MAX_IDLE_TIMEOUT_SECONDS}
107
+ * cannot be expressed here at all and stays on the per-route exemption list.
108
+ */
109
+ export declare const HTTP_IDLE_TIMEOUT_SECONDS: {
110
+ /**
111
+ * `packages/api/src/server.ts`. Deliberately the most conservative of the
112
+ * three: this one `Bun.serve` also carries the anonymous lane and every
113
+ * signed-in user route, and the caps that bound that traffic (anon global
114
+ * 20, the per-network concurrency ceiling, the 25 MiB anon upload, the
115
+ * per-IP rate limits) all bound REQUESTS — a connection that sends nothing
116
+ * is bounded by this value and nothing else, so raising it is a real, if
117
+ * small, increase in what one idle socket can hold.
118
+ *
119
+ * 120 s is what the API's own downstream budgets ask for: a single
120
+ * `RemotePocketBaseManager.post()` is 90 s, `RemoteDeployer.post()` is 60 s,
121
+ * `waitHealthy` is its deadline + 10 s. Below those the transport, not the
122
+ * deadline, would decide the outcome — the misalignment the rest of this
123
+ * file exists to prevent. The operator routes that legitimately run longer
124
+ * (`/admin/backup/verify` at 10 min, `/admin/migrate-networks` at the
125
+ * runbook's 180 s and beyond) are on the exact-route exemption list, which
126
+ * is narrower than any process-wide number could be.
127
+ */
128
+ readonly api: 120;
129
+ /**
130
+ * `packages/api/bin/percher-worker.ts`. The internal control plane: reached
131
+ * over the private networks with the shared worker secret, never from the
132
+ * public internet. Its unexempted routes are the ones the API budgets 60–90 s
133
+ * for, and the prune ladder the 2026-09-08 window was running has no API-side
134
+ * budget at all — the watchdog's non-aggressive `POST /docker/prune` sends no
135
+ * body and no signal, so it was being reset at 10 s and reported as
136
+ * `auto-prune failed` while the worker kept pruning unobserved. 240 s covers
137
+ * those with room for the IO stalls this exists for, and leaves the ceiling
138
+ * visible rather than sitting on it.
139
+ */
140
+ readonly worker: 240;
141
+ /**
142
+ * `packages/mcp/bin/percher-mcp-http.ts`. Public through Caddy, so not the
143
+ * place for the ceiling either. Its longest legitimate single POST is
144
+ * `percher_wait_for_deploy`, whose hosted schema clamps `timeoutSeconds` to
145
+ * 120; 180 s covers that plus the internal API hop and JSON-RPC framing.
146
+ * Every hosted call carries a JSON-RPC body, so this is a guard rather than
147
+ * a fix for an observed failure.
148
+ */
149
+ readonly hostedMcp: 180;
150
+ };
151
+ export type HttpIdleTimeoutSurface = keyof typeof HTTP_IDLE_TIMEOUT_SECONDS;
67
152
  //# sourceMappingURL=timeouts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timeouts.d.ts","sourceRoot":"","sources":["../src/timeouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,QAAQ;IACnB;;;;;OAKG;aACH,qBAAqB;IAErB;;;;;;OAMG;aACH,qBAAqB;IAErB;;;;;OAKG;aACH,iBAAiB;IAEjB,2CAA2C;aAC3C,iBAAiB,EAAE,IAAK;IAExB,2CAA2C;aAC3C,YAAY,EAAE,KAAM;IAEpB,uEAAuE;aACvE,oBAAoB,EAAE,KAAM;IAE5B;;;;;;OAMG;aACH,gBAAgB;CACR,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,QAAQ,CAAC"}
1
+ {"version":3,"file":"timeouts.d.ts","sourceRoot":"","sources":["../src/timeouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,QAAQ;IACnB;;;;;OAKG;aACH,qBAAqB;IAErB;;;;;;OAMG;aACH,qBAAqB;IAErB;;;;;OAKG;aACH,iBAAiB;IAEjB,2CAA2C;aAC3C,iBAAiB,EAAE,IAAK;IAExB,2CAA2C;aAC3C,YAAY,EAAE,KAAM;IAEpB,uEAAuE;aACvE,oBAAoB,EAAE,KAAM;IAE5B;;;;;;OAMG;aACH,gBAAgB;CACR,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,QAAQ,CAAC;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,yBAAyB;IACpC;;;;;;;;;;;;;;;;;OAiBG;aACH,GAAG,EAAE,GAAG;IACR;;;;;;;;;;OAUG;aACH,MAAM,EAAE,GAAG;IACX;;;;;;;OAOG;aACH,SAAS,EAAE,GAAG;CACN,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,yBAAyB,CAAC"}
package/dist/timeouts.js CHANGED
@@ -63,4 +63,88 @@ export const TIMEOUTS = {
63
63
  */
64
64
  mcpWaitDeployMax: 12 * 60_000,
65
65
  };
66
+ /**
67
+ * Bun refuses a `Bun.serve({ idleTimeout })` above this and throws at boot
68
+ * ("Bun.serve expects idleTimeout to be 255 or less"). Measured on Bun 1.3.14,
69
+ * the version `packages/api/Dockerfile` and `packages/mcp/Dockerfile` both
70
+ * digest-pin, on linux and win32. It is a hard ceiling, not a guideline: an
71
+ * operation whose budget exceeds it can never be covered by a server-wide
72
+ * value and has to be exempted per route
73
+ * (`packages/api/src/http/scoped-idle-timeout.ts`) or made job-based.
74
+ */
75
+ export const BUN_MAX_IDLE_TIMEOUT_SECONDS = 255;
76
+ /**
77
+ * Transport-level idle timeout, in SECONDS, for each `Bun.serve` Percher runs.
78
+ * (Every other budget in this file is in milliseconds; Bun's option is
79
+ * seconds, so the unit is in the name.)
80
+ *
81
+ * Bun's default is 10 s, and leaving it there is how a healthy request dies of
82
+ * something unrelated to itself. 2026-09-08: a supervised admin POST to
83
+ * `/admin/migrate-networks` returned `curl: (52) Empty reply from server`
84
+ * while the same log window held `[watchdog] WARNING: disk usage 80% —
85
+ * triggering auto-prune` and `[Bun.serve]: request timed out after 10
86
+ * seconds`. Identical earlier runs answered in under 10 s; concurrent pruning
87
+ * was observed, but the log timing alone does not prove the cause of the delay.
88
+ * The client had budgeted 900 s.
89
+ *
90
+ * Two measurements shape these numbers. Both were taken with curl against a
91
+ * real `Bun.serve` on the pinned 1.3.14 linux image:
92
+ *
93
+ * - A request whose body is EMPTY (`GET`, or `curl -X POST` with no `-d`) is
94
+ * reset at the idle timeout: 200 at 8 s, `curl: (52)` at ~12 s.
95
+ * - A request carrying a non-empty body survived the measured 30 s handler,
96
+ * answering 200 under both the 10 s default and a 2 s override.
97
+ *
98
+ * That asymmetry is undocumented, so nothing may depend on it, but it does
99
+ * explain the shape of the incident report: the long-held bodied calls
100
+ * (`/build/nixpacks`, held for up to `workerBuildSubprocess`) never showed a
101
+ * symptom, while every bodyless operator `-X POST` and the watchdog's own
102
+ * non-aggressive `POST /docker/prune` were being cut at 10 s.
103
+ *
104
+ * Each value must outlive the longest SYNCHRONOUS request that surface
105
+ * legitimately serves. Anything longer than {@link BUN_MAX_IDLE_TIMEOUT_SECONDS}
106
+ * cannot be expressed here at all and stays on the per-route exemption list.
107
+ */
108
+ export const HTTP_IDLE_TIMEOUT_SECONDS = {
109
+ /**
110
+ * `packages/api/src/server.ts`. Deliberately the most conservative of the
111
+ * three: this one `Bun.serve` also carries the anonymous lane and every
112
+ * signed-in user route, and the caps that bound that traffic (anon global
113
+ * 20, the per-network concurrency ceiling, the 25 MiB anon upload, the
114
+ * per-IP rate limits) all bound REQUESTS — a connection that sends nothing
115
+ * is bounded by this value and nothing else, so raising it is a real, if
116
+ * small, increase in what one idle socket can hold.
117
+ *
118
+ * 120 s is what the API's own downstream budgets ask for: a single
119
+ * `RemotePocketBaseManager.post()` is 90 s, `RemoteDeployer.post()` is 60 s,
120
+ * `waitHealthy` is its deadline + 10 s. Below those the transport, not the
121
+ * deadline, would decide the outcome — the misalignment the rest of this
122
+ * file exists to prevent. The operator routes that legitimately run longer
123
+ * (`/admin/backup/verify` at 10 min, `/admin/migrate-networks` at the
124
+ * runbook's 180 s and beyond) are on the exact-route exemption list, which
125
+ * is narrower than any process-wide number could be.
126
+ */
127
+ api: 120,
128
+ /**
129
+ * `packages/api/bin/percher-worker.ts`. The internal control plane: reached
130
+ * over the private networks with the shared worker secret, never from the
131
+ * public internet. Its unexempted routes are the ones the API budgets 60–90 s
132
+ * for, and the prune ladder the 2026-09-08 window was running has no API-side
133
+ * budget at all — the watchdog's non-aggressive `POST /docker/prune` sends no
134
+ * body and no signal, so it was being reset at 10 s and reported as
135
+ * `auto-prune failed` while the worker kept pruning unobserved. 240 s covers
136
+ * those with room for the IO stalls this exists for, and leaves the ceiling
137
+ * visible rather than sitting on it.
138
+ */
139
+ worker: 240,
140
+ /**
141
+ * `packages/mcp/bin/percher-mcp-http.ts`. Public through Caddy, so not the
142
+ * place for the ceiling either. Its longest legitimate single POST is
143
+ * `percher_wait_for_deploy`, whose hosted schema clamps `timeoutSeconds` to
144
+ * 120; 180 s covers that plus the internal API hop and JSON-RPC framing.
145
+ * Every hosted call carries a JSON-RPC body, so this is a guard rather than
146
+ * a fix for an observed failure.
147
+ */
148
+ hostedMcp: 180,
149
+ };
66
150
  //# sourceMappingURL=timeouts.js.map
@@ -1 +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"}
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;AAIX;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC;;;;;;;;;;;;;;;;;OAiBG;IACH,GAAG,EAAE,GAAG;IACR;;;;;;;;;;OAUG;IACH,MAAM,EAAE,GAAG;IACX;;;;;;;OAOG;IACH,SAAS,EAAE,GAAG;CACN,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percher/shared",
3
- "version": "0.1.9",
3
+ "version": "1.0.0",
4
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
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,6 +11,11 @@
11
11
  "import": "./dist/index.js",
12
12
  "default": "./dist/index.js"
13
13
  },
14
+ "./brand": {
15
+ "types": "./dist/brand.d.ts",
16
+ "import": "./dist/brand.js",
17
+ "default": "./dist/brand.js"
18
+ },
14
19
  "./timeouts": {
15
20
  "types": "./dist/timeouts.d.ts",
16
21
  "import": "./dist/timeouts.js",
@@ -30,6 +35,11 @@
30
35
  "types": "./dist/pow.d.ts",
31
36
  "import": "./dist/pow.js",
32
37
  "default": "./dist/pow.js"
38
+ },
39
+ "./signup-invite-hash": {
40
+ "types": "./dist/signup-invite-hash.d.ts",
41
+ "import": "./dist/signup-invite-hash.js",
42
+ "default": "./dist/signup-invite-hash.js"
33
43
  }
34
44
  },
35
45
  "files": [
@@ -44,7 +54,7 @@
44
54
  "bun-types": "^1.1.0",
45
55
  "tsc-alias": "^1.8.17"
46
56
  },
47
- "license": "MIT",
57
+ "license": "FSL-1.1-MIT",
48
58
  "author": "Mattias Malmborg",
49
59
  "repository": {
50
60
  "type": "git",