@pithy-sh/core 0.7.3 → 0.8.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 (39) hide show
  1. package/dist/naming/domains.d.ts +43 -3
  2. package/dist/naming/domains.d.ts.map +1 -1
  3. package/dist/naming/domains.js +62 -4
  4. package/dist/naming/feature.d.ts +126 -11
  5. package/dist/naming/feature.d.ts.map +1 -1
  6. package/dist/naming/feature.js +184 -30
  7. package/dist/naming/limits.d.ts +23 -7
  8. package/dist/naming/limits.d.ts.map +1 -1
  9. package/dist/naming/limits.js +22 -9
  10. package/dist/naming/provisionScope.d.ts +25 -11
  11. package/dist/naming/provisionScope.d.ts.map +1 -1
  12. package/dist/naming/provisionScope.js +28 -11
  13. package/dist/seed/seed.d.ts +36 -7
  14. package/dist/seed/seed.d.ts.map +1 -1
  15. package/dist/version.generated.d.ts +1 -1
  16. package/dist/version.generated.js +1 -1
  17. package/dist/worker/identity.d.ts +9 -0
  18. package/dist/worker/identity.d.ts.map +1 -1
  19. package/dist/worker/identity.js +10 -1
  20. package/dist/workflow/faults.d.ts +34 -2
  21. package/dist/workflow/faults.d.ts.map +1 -1
  22. package/dist/workflow/faults.js +42 -18
  23. package/dist/workflow/host.d.ts +7 -0
  24. package/dist/workflow/host.d.ts.map +1 -1
  25. package/dist/workflow/host.js +5 -3
  26. package/dist/workflow/naming.d.ts +8 -0
  27. package/dist/workflow/naming.d.ts.map +1 -1
  28. package/dist/workflow/naming.js +15 -0
  29. package/package.json +1 -1
  30. package/src/naming/domains.ts +75 -5
  31. package/src/naming/feature.ts +274 -38
  32. package/src/naming/limits.ts +25 -8
  33. package/src/naming/provisionScope.ts +39 -14
  34. package/src/seed/seed.ts +36 -7
  35. package/src/version.generated.ts +1 -1
  36. package/src/worker/identity.ts +10 -0
  37. package/src/workflow/faults.ts +61 -4
  38. package/src/workflow/host.ts +15 -3
  39. package/src/workflow/naming.ts +25 -0
@@ -1 +1 @@
1
- {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/seed/seed.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/seed/seed.ts"],"names":[],"mappings":"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"}
@@ -3,5 +3,5 @@
3
3
  /** This package's npm name — the join key against a release feed. */
4
4
  export declare const PACKAGE_NAME = "@pithy-sh/core";
5
5
  /** This package's version, stamped from its own package.json at generation time. */
6
- export declare const PACKAGE_VERSION = "0.7.3";
6
+ export declare const PACKAGE_VERSION = "0.8.0";
7
7
  //# sourceMappingURL=version.generated.d.ts.map
@@ -4,6 +4,6 @@
4
4
  /** This package's npm name — the join key against a release feed. */
5
5
  const PACKAGE_NAME = "@pithy-sh/core";
6
6
  /** This package's version, stamped from its own package.json at generation time. */
7
- const PACKAGE_VERSION = "0.7.3";
7
+ const PACKAGE_VERSION = "0.8.0";
8
8
  //#endregion
9
9
  export { PACKAGE_NAME, PACKAGE_VERSION };
@@ -24,6 +24,15 @@
24
24
  export declare const PROJECT_VAR = "PROJECT";
25
25
  /** The var naming the environment this deployment serves — `dev`, `staging`, or `prod`. */
26
26
  export declare const ENVIRONMENT_VAR = "ENVIRONMENT";
27
+ /**
28
+ * The var naming where a deployed Worker answers — `https://<host>`, no path, no trailing slash.
29
+ *
30
+ * Generated, never hand-set: `pithy worker sync` writes it from a declared domain, and `pithy provision
31
+ * --feature` writes a feature's from its `workers.dev` address (#643). It is the one statement of a feature's
32
+ * origin a running Worker can read, because the account's `workers.dev` subdomain is something only the
33
+ * Cloudflare API knows, and a Worker has no business calling it at module scope.
34
+ */
35
+ export declare const BASE_URL_VAR = "BASE_URL";
27
36
  /**
28
37
  * The var carrying a Worker's **own** dev origin, from `pithy dev` to whatever launches that Worker.
29
38
  *
@@ -1 +1 @@
1
- {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/worker/identity.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,qFAAqF;AACrF,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,2FAA2F;AAC3F,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAE9D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,qGAAqG;AACrG,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wEAAwE;IACxE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC,yGAAyG;IACzG,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAgBD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAW3D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,qBAAqB,CAazE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzD"}
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/worker/identity.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,qFAAqF;AACrF,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,2FAA2F;AAC3F,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAE9D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,qGAAqG;AACrG,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wEAAwE;IACxE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC,yGAAyG;IACzG,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAgBD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAW3D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,qBAAqB,CAazE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzD"}
@@ -26,6 +26,15 @@ const PROJECT_VAR = "PROJECT";
26
26
  /** The var naming the environment this deployment serves — `dev`, `staging`, or `prod`. */
27
27
  const ENVIRONMENT_VAR = "ENVIRONMENT";
28
28
  /**
29
+ * The var naming where a deployed Worker answers — `https://<host>`, no path, no trailing slash.
30
+ *
31
+ * Generated, never hand-set: `pithy worker sync` writes it from a declared domain, and `pithy provision
32
+ * --feature` writes a feature's from its `workers.dev` address (#643). It is the one statement of a feature's
33
+ * origin a running Worker can read, because the account's `workers.dev` subdomain is something only the
34
+ * Cloudflare API knows, and a Worker has no business calling it at module scope.
35
+ */
36
+ const BASE_URL_VAR = "BASE_URL";
37
+ /**
29
38
  * The var carrying a Worker's **own** dev origin, from `pithy dev` to whatever launches that Worker.
30
39
  *
31
40
  * Not stamped into `wrangler.jsonc` like the three above, and that is the whole point of it. A dev port
@@ -175,4 +184,4 @@ function workerVersion(env) {
175
184
  return workerVersionMetadata(env).id;
176
185
  }
177
186
  //#endregion
178
- export { ENVIRONMENT_VAR, PROJECT_VAR, SELF_BINDING, VERSION_METADATA_BINDING, WORKER_ORIGIN_VAR, WORKER_VAR, workerIdentity, workerVersion, workerVersionMetadata };
187
+ export { BASE_URL_VAR, ENVIRONMENT_VAR, PROJECT_VAR, SELF_BINDING, VERSION_METADATA_BINDING, WORKER_ORIGIN_VAR, WORKER_VAR, workerIdentity, workerVersion, workerVersionMetadata };
@@ -65,10 +65,42 @@ export interface WorkflowFault {
65
65
  * test rather than a claim — and so the same function decides in a test, in Miniflare, and in production.
66
66
  */
67
67
  export declare function classifyWorkflowFault(error: unknown, policy: WorkflowRetryPolicy): WorkflowFault;
68
- /** The half of a Workflow step this kit uses: run a named body, or serve its journalled result. */
68
+ /**
69
+ * The half of a Workflow step this kit uses: run a named body, or serve its journalled result.
70
+ *
71
+ * **`sleep` is optional here and required on what {@link classifiedSteps} hands back, and the asymmetry
72
+ * is the truth rather than a convenience.** The platform's own `WorkflowStep` always offers one. What
73
+ * does not are this kit's hand-written test doubles, which exist to exercise the classification and
74
+ * nothing else — and demanding a primitive the classifier never classifies would cost every one of them
75
+ * a line of noise. Handing an optional one back instead would push a null check into the one caller that
76
+ * genuinely pauses.
77
+ */
69
78
  export interface WorkflowStepLike {
70
79
  /** Run a named step, or return its journalled result if this instance already completed it. */
71
80
  do<T>(name: string, fn: () => Promise<T>): Promise<T>;
81
+ /**
82
+ * Pause the instance for `durationMs` and resume it afterwards — possibly in a fresh isolate, which
83
+ * is the whole reason a caller reaches for it rather than for a timer. Absent only on a test double.
84
+ */
85
+ sleep?(name: string, durationMs: number): Promise<void>;
86
+ }
87
+ /**
88
+ * A step runner that can pause — what {@link classifiedSteps} hands back, always.
89
+ *
90
+ * The durable pause is why this type exists rather than being a convenience over the one above. A `sleep`
91
+ * is journalled, so a wait survives the instance being evicted during it; a `setTimeout` inside one step
92
+ * burns that step's wall clock and dies with the instance holding it.
93
+ *
94
+ * **It was introduced on a stronger claim, and the claim did not survive contact (pithy-sh/pithy#647).** The
95
+ * argument was that a Secrets Store binding answers the same for its isolate's whole life, so only a resume
96
+ * into a fresh isolate could ever see a write land. Measured against a real store on 2026-09-25, that is
97
+ * false: a binding refreshes inside a live isolate roughly 1.3-1.5s after the REST write, proved by holding
98
+ * two isolates warm through a write and watching each serve the old value before it and the new one after,
99
+ * over 328 samples. The durability argument above is the true one and is sufficient on its own.
100
+ */
101
+ export interface DurableStepLike extends WorkflowStepLike {
102
+ /** Pause the instance for `durationMs`, then resume. */
103
+ sleep(name: string, durationMs: number): Promise<void>;
72
104
  }
73
105
  /**
74
106
  * The platform's terminal-error class — `NonRetryableError` from `cloudflare:workflows`, taken as a
@@ -95,5 +127,5 @@ export interface TerminalErrorConstructor {
95
127
  * `runSendBatch`, `runAtRestKeyRotation`) takes this instead with no change: the classification is
96
128
  * declared once, at the entrypoint, and every step below it inherits the decision.
97
129
  */
98
- export declare function classifiedSteps(step: WorkflowStepLike, policy: WorkflowRetryPolicy, terminalError: TerminalErrorConstructor): WorkflowStepLike;
130
+ export declare function classifiedSteps(step: WorkflowStepLike, policy: WorkflowRetryPolicy, terminalError: TerminalErrorConstructor): DurableStepLike;
99
131
  //# sourceMappingURL=faults.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"faults.d.ts","sourceRoot":"","sources":["../../src/workflow/faults.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,2FAA2F;AAC3F,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,UAAU,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,iHAAiH;IACjH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7C;AAED,2FAA2F;AAC3F,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,WAAW,EAAE,wBAAwB,CAAC;IACtC,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;CAChB;AAsDD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,GAAG,aAAa,CA0BhG;AAED,mGAAmG;AACnG,MAAM,WAAW,gBAAgB;IAC/B,+FAA+F;IAC/F,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,mBAAmB,EAC3B,aAAa,EAAE,wBAAwB,GACtC,gBAAgB,CA2BlB"}
1
+ {"version":3,"file":"faults.d.ts","sourceRoot":"","sources":["../../src/workflow/faults.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,2FAA2F;AAC3F,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,UAAU,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,iHAAiH;IACjH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7C;AAED,2FAA2F;AAC3F,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,WAAW,EAAE,wBAAwB,CAAC;IACtC,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;CAChB;AAsDD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,GAAG,aAAa,CA0BhG;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+FAA+F;IAC/F,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtD;;;OAGG;IACH,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,wDAAwD;IACxD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,mBAAmB,EAC3B,aAAa,EAAE,wBAAwB,GACtC,eAAe,CAmDjB"}
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
- import { PithyError } from "../error/pithyError.js";
3
+ import { InternalError, PithyError } from "../error/pithyError.js";
4
4
  import { d1TransientFault } from "../data/withD1Retry.js";
5
5
  import { encodeWorkflowStepMessage } from "./stepMessage.js";
6
6
  //#region src/workflow/faults.ts
@@ -91,23 +91,47 @@ function classifyWorkflowFault(error, policy) {
91
91
  * declared once, at the entrypoint, and every step below it inherits the decision.
92
92
  */
93
93
  function classifiedSteps(step, policy, terminalError) {
94
- return { do(name, fn) {
95
- return step.do(name, async () => {
96
- try {
97
- return await fn();
98
- } catch (error) {
99
- const fault = classifyWorkflowFault(error, policy);
100
- if (fault.disposition === "retry") throw error;
101
- const terminal = new terminalError(encodeWorkflowStepMessage({
102
- code: fault.code,
103
- message: messageOf(error),
104
- action: pithyActionOf(error)
105
- }));
106
- terminal.cause = error;
107
- throw terminal;
108
- }
109
- });
110
- } };
94
+ const runner = {
95
+ do(name, fn) {
96
+ return step.do(name, async () => {
97
+ try {
98
+ return await fn();
99
+ } catch (error) {
100
+ const fault = classifyWorkflowFault(error, policy);
101
+ if (fault.disposition === "retry") throw error;
102
+ const terminal = new terminalError(encodeWorkflowStepMessage({
103
+ code: fault.code,
104
+ message: messageOf(error),
105
+ action: pithyActionOf(error)
106
+ }));
107
+ terminal.cause = error;
108
+ throw terminal;
109
+ }
110
+ });
111
+ },
112
+ /**
113
+ * Forwarded, and deliberately unclassified. A pause raises no fault of the capability's — the
114
+ * instance either resumes or it is gone — so there is nothing here for a policy to decide.
115
+ *
116
+ * A runner that cannot pause is refused, and the refusal is raised **through `do`** rather than
117
+ * thrown from here. A throw from here is a throw the engine never classifies, so it is free to
118
+ * re-drive the instance — and re-driving is the unbounded loop the caller is spending its sleeps to
119
+ * avoid. Going through `do` makes the refusal terminal on its first attempt, like every other
120
+ * answer that cannot change.
121
+ */
122
+ sleep(name, durationMs) {
123
+ const pause = step.sleep;
124
+ if (pause === void 0) return runner.do(`${name}/cannot-pause`, async () => {
125
+ throw new InternalError({
126
+ message: "This Workflow step runner cannot pause.",
127
+ action: "Give the step runner a `sleep`; the platform's own `WorkflowStep` always has one.",
128
+ detail: `step '${name}' asked to pause ${durationMs}ms through a runner that declares no sleep`
129
+ });
130
+ });
131
+ return pause.call(step, name, durationMs);
132
+ }
133
+ };
134
+ return runner;
111
135
  }
112
136
  //#endregion
113
137
  export { classifiedSteps, classifyWorkflowFault };
@@ -1,5 +1,6 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
+ import type { FeatureIdentity } from "../naming/feature";
3
4
  import { type WorkflowHostNameParts } from "./naming";
4
5
  import type { WorkflowRegistry } from "./spec";
5
6
  /**
@@ -106,6 +107,12 @@ export interface WorkflowHostParams {
106
107
  capability: string;
107
108
  /** The target environment (`dev` | `staging` | `production`). */
108
109
  env: string;
110
+ /**
111
+ * The feature this host serves, when it serves one (#643). Its name then takes the feature's head —
112
+ * `<project>-f<issue>-<slug>-<capability>` — as the Workflows derived with the same parts do; `env` still
113
+ * says `feature`, and that is what the host's `ENVIRONMENT` var is stamped with.
114
+ */
115
+ feature?: FeatureIdentity;
109
116
  /** D1 binding name → database id. An unlisted binding keeps the template's id. */
110
117
  databaseIds?: Record<string, string>;
111
118
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/workflow/host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/workflow/host.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,KAAK,qBAAqB,EAAwC,MAAM,UAAU,CAAC;AAC5F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,uGAAuG;AACvG,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,8GAA8G;AAC9G,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4GAA4G;AAC5G,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,kGAAkG;AAClG,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,sGAAsG;AACtG,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACnC,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACpC,qBAAqB,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAClD,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAClC,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,yGAAyG;AACzG,MAAM,WAAW,kBAAkB;IACjC;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,UAAU,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,2CAA2C;IAC3C,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,iGAAiG;IACjG,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;OAGG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC5C;AAOD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,MAAM,EAAE,kBAAkB,GAAG,oBAAoB,CAgGpH;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,qBAAqB,GAC3B;IAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAsBvD"}
@@ -31,7 +31,8 @@ function resolveWorkflowHost(template, params) {
31
31
  resolved.name = workflowHostName({
32
32
  project: params.project,
33
33
  capability: params.capability,
34
- env: params.env
34
+ env: params.env,
35
+ ...params.feature ? { feature: params.feature } : {}
35
36
  });
36
37
  if (resolved.d1_databases) resolved.d1_databases = resolved.d1_databases.map((entry) => ({
37
38
  ...entry,
@@ -91,7 +92,7 @@ function resolveWorkflowHost(template, params) {
91
92
  * `className` cannot be hosted: there would be no class for wrangler to instantiate.
92
93
  */
93
94
  function hostWorkflowsFor(registry, parts) {
94
- const { project, capability, env } = parts;
95
+ const { project, capability, env, feature } = parts;
95
96
  const owned = Object.values(registry).filter((entry) => entry.capability === capability);
96
97
  const workflows = [];
97
98
  const crons = [];
@@ -106,7 +107,8 @@ function hostWorkflowsFor(registry, parts) {
106
107
  project,
107
108
  capability,
108
109
  job: entry.job,
109
- env
110
+ env,
111
+ ...feature ? { feature } : {}
110
112
  }),
111
113
  class_name: entry.spec.className
112
114
  });
@@ -1,5 +1,6 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
+ import { type FeatureIdentity } from "../naming/feature";
3
4
  /**
4
5
  * Every name a durable job answers to, in one module. The CLI writes these into a host worker's
5
6
  * resolved `wrangler.jsonc`, the provisioner deploys under them, and the dispatcher resolves
@@ -43,6 +44,13 @@ export interface WorkflowHostNameParts {
43
44
  capability: string;
44
45
  /** The deployment environment (e.g. `staging`). */
45
46
  env: string;
47
+ /**
48
+ * **The feature this deployment is, when it is one (#643).** A feature's host Worker and Workflows take the
49
+ * feature's head — `<project>-f<issue>-<slug>-…` — not `<project>-feature-…`, which every open branch would
50
+ * share: Worker and Workflow names are account-wide, so a second branch's deploy would replace the first's.
51
+ * `env` stays `feature`, which is what the host's `ENVIRONMENT` var says; only the names change.
52
+ */
53
+ feature?: FeatureIdentity;
46
54
  }
47
55
  /** The identity of one durable job's Workflow in one environment. */
48
56
  export interface WorkflowScriptNameParts extends WorkflowHostNameParts {
@@ -1 +1 @@
1
- {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../src/workflow/naming.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,IAAsC,CAAC;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,IAAoC,CAAC;AAmEvE,oEAAoE;AACpE,MAAM,WAAW,qBAAqB;IACpC,gHAAgH;IAChH,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAKzE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAGrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAInE"}
1
+ {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../src/workflow/naming.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,eAAe,EAA0C,MAAM,mBAAmB,CAAC;AAKjG;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,IAAsC,CAAC;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,IAAoC,CAAC;AAkFvE,oEAAoE;AACpE,MAAM,WAAW,qBAAqB;IACpC,gHAAgH;IAChH,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAMzE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAIrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAInE"}
@@ -4,6 +4,7 @@ import { InternalError } from "../error/pithyError.js";
4
4
  import { NAME_SEGMENT } from "../naming/segment.js";
5
5
  import { NAMESPACE_LIMITS } from "../naming/limits.js";
6
6
  import { assertValidProjectName, kebab } from "../naming/resource.js";
7
+ import { featureWorkerName, featureWorkflowName } from "../naming/feature.js";
7
8
  //#region src/workflow/naming.ts
8
9
  /**
9
10
  * Every name a durable job answers to, in one module. The CLI writes these into a host worker's
@@ -96,6 +97,18 @@ function head(project, env) {
96
97
  return `${kebab(project)}-${env}`;
97
98
  }
98
99
  /**
100
+ * The feature a name is composed for, held to the project the parts name — two projects in one set of parts is
101
+ * a name composed for somebody else's feature.
102
+ */
103
+ function featureOf(parts) {
104
+ const feature = parts.feature;
105
+ if (feature.project !== parts.project) throw new InternalError({
106
+ message: "A feature's Workflow name was asked for with two different projects.",
107
+ detail: `parts name project "${parts.project}" and a feature of project "${feature.project}".`
108
+ });
109
+ return feature;
110
+ }
111
+ /**
99
112
  * The deployed name of one job's Workflow in one environment — `<project>-<env>-<capability>-<job>`,
100
113
  * e.g. `acme-staging-media-image-to-text`. This is what the CLI writes as the `name` of a
101
114
  * `workflows` entry, and what `CloudflareWorkflowsClient` addresses when triggering from outside
@@ -109,6 +122,7 @@ function workflowScriptName(parts) {
109
122
  assertSegment(parts.capability, "capability");
110
123
  assertSegment(parts.job, "job");
111
124
  assertCapabilityJob(parts.capability, parts.job);
125
+ if (parts.feature) return featureWorkflowName(featureOf(parts), parts.capability, parts.job);
112
126
  return assertLength(`${head(parts.project, parts.env)}-${parts.capability}-${parts.job}`, MAX_WORKFLOW_NAME_BYTES);
113
127
  }
114
128
  /**
@@ -120,6 +134,7 @@ function workflowScriptName(parts) {
120
134
  */
121
135
  function workflowHostName(parts) {
122
136
  assertSegment(parts.capability, "capability");
137
+ if (parts.feature) return featureWorkerName(featureOf(parts), parts.capability);
123
138
  return assertLength(`${head(parts.project, parts.env)}-${parts.capability}`, MAX_WORKER_NAME_BYTES);
124
139
  }
125
140
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pithy-sh/core",
3
- "version": "0.7.3",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -2,7 +2,9 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
 
4
4
  import { z } from "zod";
5
- import { ENVIRONMENTS } from "./environment";
5
+ import { type AmbientEnv, ambientEnv } from "../env/ambient";
6
+ import { BASE_URL_VAR } from "../worker/identity";
7
+ import { ENVIRONMENTS, FEATURE_ENVIRONMENT } from "./environment";
6
8
 
7
9
  /**
8
10
  * Where a Worker answers, declared once per Worker per environment.
@@ -39,6 +41,18 @@ import { ENVIRONMENTS } from "./environment";
39
41
  /** A hostname a Worker answers on. No scheme, no path, no port — wrangler's `routes` pattern is a host. */
40
42
  const HOSTNAME_PATTERN = /^(?!-)[a-z0-9-]{1,63}(?<!-)(\.(?!-)[a-z0-9-]{1,63}(?<!-))+$/;
41
43
 
44
+ /**
45
+ * Whether a string is a public hostname: dot-separated DNS labels, at least two, lowercase. No scheme, no
46
+ * port, no trailing dot, and nothing a URL parser decoded into one — `%2e%2e` is `..` once parsed, which is an
47
+ * empty label rather than a host (#643). `localhost` is not one: it has a single label, and it is this machine.
48
+ *
49
+ * The one test for "is this a host" that an origin read from a stamp and an origin typed on a command line
50
+ * both pass, so the two cannot accept different things.
51
+ */
52
+ export function isPublicHostname(hostname: string): boolean {
53
+ return hostname.length <= 253 && HOSTNAME_PATTERN.test(hostname);
54
+ }
55
+
42
56
  /** The environments a domain may be declared for — every managed one, never `dev`. */
43
57
  export const DOMAIN_ENVIRONMENTS = ENVIRONMENTS.filter((environment) => environment !== "dev");
44
58
 
@@ -135,10 +149,46 @@ export interface ResolvedOrigin {
135
149
  origin: string;
136
150
  /** The hostname alone: a route pattern, and what Turnstile binds a widget to. */
137
151
  hostname: string;
138
- /** Whether `domains` declared it. `false` means {@link LOCAL_ORIGIN} was substituted. */
152
+ /**
153
+ * Whether `domains` declared it. `false` means {@link LOCAL_ORIGIN} was substituted, or — for a feature
154
+ * environment only — that the address is the `workers.dev` one provisioning stamped ({@link featureOrigin}).
155
+ */
139
156
  declared: boolean;
140
157
  }
141
158
 
159
+ /**
160
+ * **A feature environment's origin: the `workers.dev` address provisioning stamped, or null (#643).**
161
+ *
162
+ * A feature Worker answers on `https://<script>.<account subdomain>.workers.dev`. Nothing can declare that —
163
+ * `domains` has no feature key, because a branch's hostname is composed from the branch — and the Worker cannot
164
+ * derive it either, because the subdomain is the account's and only the Cloudflare API knows it. So `pithy
165
+ * provision --feature` derives it, through the CLI's one address resolver, and stamps it as the feature
166
+ * stanza's {@link BASE_URL_VAR}. This is the one reader of that stamp.
167
+ *
168
+ * **Only a `workers.dev` https origin is accepted, and that is the guard rather than a tidiness check.** A
169
+ * feature stanza is generated from the Worker's top level, so a `BASE_URL` somebody set by hand up there
170
+ * arrives in the feature too — and it is another environment's origin, most likely production's. Honoring it
171
+ * would send a branch's magic links into production, which is the one thing {@link resolveOrigin} exists to
172
+ * make impossible. A feature's address is `workers.dev` by construction, so anything else is not one and
173
+ * resolves to nothing. No path, no port, no credentials: an origin, or null.
174
+ */
175
+ export function featureOrigin(stamped: string | undefined): { origin: string; hostname: string } | null {
176
+ if (!stamped) return null;
177
+ let url: URL;
178
+ try {
179
+ url = new URL(stamped);
180
+ } catch {
181
+ return null;
182
+ }
183
+ if (url.protocol !== "https:" || url.port !== "" || url.username !== "" || url.password !== "") return null;
184
+ if (url.pathname !== "/" || url.search !== "" || url.hash !== "") return null;
185
+ // A script name and an account subdomain, at least: `workers.dev` alone, or `<sub>.workers.dev`, is not a Worker.
186
+ if (!url.hostname.endsWith(".workers.dev") || url.hostname.split(".").length < 4) return null;
187
+ // Every label a DNS label: the parser decodes `%2e%2e` into `..`, which ends in `.workers.dev` and is no host.
188
+ if (!isPublicHostname(url.hostname)) return null;
189
+ return { origin: url.origin, hostname: url.hostname };
190
+ }
191
+
142
192
  /**
143
193
  * **Where is this Worker publicly reachable, in this environment?** — asked once, answered once.
144
194
  *
@@ -164,10 +214,21 @@ export interface ResolvedOrigin {
164
214
  * checks that stored value, so a per-environment issuer would make a connection minted in staging
165
215
  * unverifiable in production. That may be the better isolation, but it is a decision about trust rather
166
216
  * than about reachability, and a helper whose job is "where am I reachable" must not sweep it up.
217
+ *
218
+ * **`stamped` is a feature environment's `BASE_URL`, and is read for nothing else** — see {@link featureOrigin}.
167
219
  */
168
- export function resolveOrigin(environment: string | undefined, domains: WorkerDomains | undefined): ResolvedOrigin {
220
+ export function resolveOrigin(
221
+ environment: string | undefined,
222
+ domains: WorkerDomains | undefined,
223
+ stamped?: string | undefined,
224
+ ): ResolvedOrigin {
169
225
  const domain = domainFor(domains, environment);
170
226
  if (domain) return { origin: baseUrlFor(domain), hostname: domain.pattern, declared: true };
227
+ // A feature environment, and only a feature environment, reads the address provisioning stamped. Every other
228
+ // environment ignores `stamped` outright: a declared one without a domain is unpublished, and `dev` resolves
229
+ // its address from the request.
230
+ const feature = environment === FEATURE_ENVIRONMENT ? featureOrigin(stamped) : null;
231
+ if (feature) return { ...feature, declared: false };
171
232
  return { origin: LOCAL_ORIGIN, hostname: "localhost", declared: false };
172
233
  }
173
234
 
@@ -188,7 +249,16 @@ export function resolveOrigin(environment: string | undefined, domains: WorkerDo
188
249
  * `AUTH_BASE_URL`, which is part of why `email` and `payments` were missed for days: the constant read
189
250
  * as auth's private business when it is the Worker's address, and every capability that needs an origin
190
251
  * needs this one.
252
+ *
253
+ * **A feature deployment is answered from its own vars (#643).** `env` is the ambient environment — inside a
254
+ * Worker, its own vars — and it is read for one thing: the `BASE_URL` a feature's provisioning stamped. So the
255
+ * same scaffolded line gives auth's base URL, email's links and payments' return URLs a feature's real
256
+ * `workers.dev` origin, rather than `http://localhost`, with nothing added to the adopter's config.
191
257
  */
192
- export function originFor(environment: string | undefined, domains: WorkerDomains | undefined): string {
193
- return resolveOrigin(environment, domains).origin;
258
+ export function originFor(
259
+ environment: string | undefined,
260
+ domains: WorkerDomains | undefined,
261
+ env: AmbientEnv = ambientEnv(),
262
+ ): string {
263
+ return resolveOrigin(environment, domains, env[BASE_URL_VAR]).origin;
194
264
  }