@substrat-run/adapter-cloudflare 0.118.0 → 0.119.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/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * driving `drainDue`/`runDueSchedules` per scope (#461)
15
15
  */
16
16
  export { CloudflareScopeHost } from './host.js';
17
- export type { CloudflareScopeHostOptions, ConnectorDelegation, EventDrainDelegation, SystemSwitchDelegation, } from './host.js';
17
+ export type { CloudflareScopeHostOptions, ConnectorDelegation, EventDrainDelegation, PeerSwitchDelegation, SystemSwitchDelegation, } from './host.js';
18
18
  export { defineScopeDO } from './scope-do.js';
19
19
  export { ControlPlaneDO } from './control-plane-do.js';
20
20
  export { OperationQueue } from './serialization.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjF,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjF,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAOhD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAQjF,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAQhD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAQjF,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type RouteTarget } from '@substrat-run/contracts';
1
+ import { type PeerCaller, type RouteTarget } from '@substrat-run/contracts';
2
2
  /**
3
3
  * Hostname → route target, for the router worker (K-26).
4
4
  *
@@ -24,6 +24,9 @@ export interface RouteRowLike {
24
24
  * `outbound` array lifted from the resolved version's manifest in the same read.
25
25
  * Null = a pre-#303 manifest (or no version), which dispatches unenforced. */
26
26
  outbound_json?: string | null;
27
+ /** The dispatched code's declared outgoing peer calls (#1706) as JSON text, on the
28
+ * same terms as `outbound_json`: null for a version pushed before the declaration. */
29
+ calls_json?: string | null;
27
30
  }
28
31
  export type RouteResolver = (hostname: string) => Promise<RouteTarget | undefined>;
29
32
  /** A hostname row → what the router dispatches on. Shared with `CloudflareScopeHost`
@@ -47,4 +50,59 @@ export declare const normalizeHostname: (hostname: string) => string;
47
50
  * serving a suspended tenant blunts suspension — which §7 calls a live weapon.
48
51
  */
49
52
  export declare function createRouteResolver(controlPlane: DurableObjectNamespace): RouteResolver;
53
+ /** `peerCallTarget`'s answer, as the router reads it. */
54
+ export interface PeerCallTargetRowLike {
55
+ caller: {
56
+ state: 'ok' | 'unknown' | 'not-primary' | 'inactive';
57
+ status: string | null;
58
+ };
59
+ outcome: 'resolved' | 'not-installed' | 'ambiguous';
60
+ count: number;
61
+ target: {
62
+ scope_id: string;
63
+ tenant_id: string;
64
+ vertical: string | null;
65
+ deployment_ref: string | null;
66
+ outbound_json: string | null;
67
+ calls_json: string | null;
68
+ } | null;
69
+ }
70
+ /**
71
+ * What the router does with a peer call: dispatch it to one instance, or refuse it with a
72
+ * reason a builder can act on. A discriminated union, so a caller cannot read a refusal as a
73
+ * destination — the shape `Decision` and `Coverage` use elsewhere, for that reason.
74
+ */
75
+ export type PeerCallDecision = {
76
+ outcome: 'dispatch';
77
+ /** The target instance and the script it runs — what `DISPATCH.get` takes. */
78
+ tenantId: string;
79
+ scopeId: string;
80
+ vertical: string;
81
+ deploymentRef: string;
82
+ /** The TARGET's own dispatch parameters, one hop deeper than the caller's. */
83
+ outboundHosts: string[] | null;
84
+ calls: string[] | null;
85
+ depth: number;
86
+ } | {
87
+ outcome: 'refused';
88
+ code: 'not_found' | 'conflict' | 'forbidden' | 'unavailable';
89
+ message: string;
90
+ };
91
+ /**
92
+ * Decide ONE peer call, over the directory (#1706). Pure but for the single read, so the
93
+ * order of the gates is readable in one place — and each is a refusal a test can name:
94
+ *
95
+ * 1. **The depth**, first: a chain already at the bound is refused before any read, so a loop
96
+ * costs one dispatch rather than a directory round trip per hop.
97
+ * 2. **The caller declared this target** (`substrat.calls`). A version pushed before the
98
+ * declaration existed carries `null` and is unenforced, exactly as a pre-#303 `outbound` is.
99
+ * 3. **The caller is who the platform says it is**: its scope record still names the vertical
100
+ * the dispatch ran as, in this tenant. Read here rather than taken from routing, so this
101
+ * path does not inherit #1713.
102
+ * 4. **The caller is a live primary instance** — not suspended, archived, a fork or a preview.
103
+ * 5. **The target resolves** to exactly one live primary instance in the SAME tenant, by the
104
+ * kernel's one rule. Never guessed when a tenant runs two.
105
+ * 6. **The target has a script to dispatch.**
106
+ */
107
+ export declare function createPeerCallResolver(controlPlane: DurableObjectNamespace): (caller: PeerCaller, target: string) => Promise<PeerCallDecision>;
50
108
  //# sourceMappingURL=route-resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"route-resolver.d.ts","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAExE;;;;;;;;;;;GAWG;AAEH,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;mFAE+E;IAC/E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAOD,MAAM,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;AAEnF;yDACyD;AACzD,wBAAgB,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CA2BpF;AAED,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,aAAc,MAAM,KAAG,MAAgC,CAAC;AAEtF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,sBAAsB,GAAG,aAAa,CAgBvF"}
1
+ {"version":3,"file":"route-resolver.d.ts","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;GAWG;AAEH,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;mFAE+E;IAC/E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;2FACuF;IACvF,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAOD,MAAM,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;AAEnF;yDACyD;AACzD,wBAAgB,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAuCpF;AAED,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,aAAc,MAAM,KAAG,MAAgC,CAAC;AAEtF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,sBAAsB,GAAG,aAAa,CAgBvF;AAgBD,yDAAyD;AACzD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE;QAAE,KAAK,EAAE,IAAI,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACxF,OAAO,EAAE,UAAU,GAAG,eAAe,GAAG,WAAW,CAAC;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,GAAG,IAAI,CAAC;CACV;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACxB;IACE,OAAO,EAAE,UAAU,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAY1G;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,sBAAsB,GACnC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAsEnE"}
@@ -1,4 +1,4 @@
1
- import { routeTarget } from '@substrat-run/contracts';
1
+ import { callDepthMessage, callsDeclares, PEER_CALL_DEPTH_MAX, previewCallerMessage, routeTarget, undeclaredCallMessage, } from '@substrat-run/contracts';
2
2
  /** A hostname row → what the router dispatches on. Shared with `CloudflareScopeHost`
3
3
  * so the two cannot drift on what "resolvable" means. */
4
4
  export function toRouteTarget(row) {
@@ -21,6 +21,19 @@ export function toRouteTarget(row) {
21
21
  // Malformed JSON never breaks routing — the request still dispatches, unenforced.
22
22
  }
23
23
  }
24
+ // #1706: the declared outgoing peer calls, lifted from the same manifest on the same
25
+ // terms — null for a version that predates the declaration, which is unenforced.
26
+ let calls = null;
27
+ if (row.calls_json) {
28
+ try {
29
+ const parsed = JSON.parse(row.calls_json);
30
+ if (Array.isArray(parsed))
31
+ calls = parsed.filter((v) => typeof v === 'string');
32
+ }
33
+ catch {
34
+ // Malformed JSON never breaks routing, exactly as above.
35
+ }
36
+ }
24
37
  return routeTarget.parse({
25
38
  tenantId: row.tenant_id,
26
39
  scopeId: row.scope_id,
@@ -29,6 +42,7 @@ export function toRouteTarget(row) {
29
42
  surface: row.surface,
30
43
  region: row.region,
31
44
  outboundHosts,
45
+ calls,
32
46
  });
33
47
  }
34
48
  /** DNS is case-insensitive, so the map is normalized and lookups must match. */
@@ -63,4 +77,100 @@ export function createRouteResolver(controlPlane) {
63
77
  return toRouteTarget(await cp.readRoute(normalizeHostname(hostname)));
64
78
  };
65
79
  }
80
+ const jsonList = (raw) => {
81
+ if (!raw)
82
+ return null;
83
+ try {
84
+ const parsed = JSON.parse(raw);
85
+ return Array.isArray(parsed) ? parsed.filter((v) => typeof v === 'string') : null;
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ };
91
+ /**
92
+ * Decide ONE peer call, over the directory (#1706). Pure but for the single read, so the
93
+ * order of the gates is readable in one place — and each is a refusal a test can name:
94
+ *
95
+ * 1. **The depth**, first: a chain already at the bound is refused before any read, so a loop
96
+ * costs one dispatch rather than a directory round trip per hop.
97
+ * 2. **The caller declared this target** (`substrat.calls`). A version pushed before the
98
+ * declaration existed carries `null` and is unenforced, exactly as a pre-#303 `outbound` is.
99
+ * 3. **The caller is who the platform says it is**: its scope record still names the vertical
100
+ * the dispatch ran as, in this tenant. Read here rather than taken from routing, so this
101
+ * path does not inherit #1713.
102
+ * 4. **The caller is a live primary instance** — not suspended, archived, a fork or a preview.
103
+ * 5. **The target resolves** to exactly one live primary instance in the SAME tenant, by the
104
+ * kernel's one rule. Never guessed when a tenant runs two.
105
+ * 6. **The target has a script to dispatch.**
106
+ */
107
+ export function createPeerCallResolver(controlPlane) {
108
+ return async (caller, target) => {
109
+ if (caller.depth >= PEER_CALL_DEPTH_MAX) {
110
+ return { outcome: 'refused', code: 'forbidden', message: callDepthMessage(caller.depth) };
111
+ }
112
+ if (!callsDeclares(caller.calls, target)) {
113
+ return {
114
+ outcome: 'refused',
115
+ code: 'forbidden',
116
+ message: undeclaredCallMessage(caller.vertical, target),
117
+ };
118
+ }
119
+ // Per request, never held: a stub belongs to the request that created it (see above).
120
+ const cp = controlPlane.get(controlPlane.idFromName('control-plane'));
121
+ const row = await cp.peerCallTarget(caller.tenantId, caller.scopeId, caller.vertical, target);
122
+ if (row.caller.state === 'unknown') {
123
+ return {
124
+ outcome: 'refused',
125
+ code: 'forbidden',
126
+ message: `scope ${caller.scopeId} is not an instance of '${caller.vertical}' in this tenant`,
127
+ };
128
+ }
129
+ if (row.caller.state === 'not-primary') {
130
+ return { outcome: 'refused', code: 'forbidden', message: previewCallerMessage(caller.vertical) };
131
+ }
132
+ if (row.caller.state === 'inactive') {
133
+ return {
134
+ outcome: 'refused',
135
+ code: 'forbidden',
136
+ message: `'${caller.vertical}' may not call other verticals from a ${row.caller.status ?? 'non-active'} ` +
137
+ 'scope — only a live primary instance acts as its vertical',
138
+ };
139
+ }
140
+ // Ambiguity first: an ambiguous answer carries no target either, so testing for a missing
141
+ // target before the count would report "not installed" for a tenant that runs two.
142
+ if (row.outcome === 'ambiguous') {
143
+ return {
144
+ outcome: 'refused',
145
+ code: 'conflict',
146
+ message: `this tenant runs ${row.count} instances of '${target}' — a call cannot pick one; ` +
147
+ 'bind the instance first',
148
+ };
149
+ }
150
+ if (row.outcome === 'not-installed' || !row.target) {
151
+ return {
152
+ outcome: 'refused',
153
+ code: 'not_found',
154
+ message: `vertical '${target}' is not installed in this tenant`,
155
+ };
156
+ }
157
+ if (!row.target.deployment_ref) {
158
+ return {
159
+ outcome: 'refused',
160
+ code: 'unavailable',
161
+ message: `vertical '${target}' has no deployed version in this tenant`,
162
+ };
163
+ }
164
+ return {
165
+ outcome: 'dispatch',
166
+ tenantId: row.target.tenant_id,
167
+ scopeId: row.target.scope_id,
168
+ vertical: target,
169
+ deploymentRef: row.target.deployment_ref,
170
+ outboundHosts: jsonList(row.target.outbound_json),
171
+ calls: jsonList(row.target.calls_json),
172
+ depth: caller.depth + 1,
173
+ };
174
+ };
175
+ }
66
176
  //# sourceMappingURL=route-resolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"route-resolver.js","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,yBAAyB,CAAC;AAqCxE;yDACyD;AACzD,MAAM,UAAU,aAAa,CAAC,GAA6B;IACzD,mFAAmF;IACnF,gFAAgF;IAChF,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,mFAAmF;IACnF,iFAAiF;IACjF,+EAA+E;IAC/E,IAAI,aAAa,GAAoB,IAAI,CAAC;IAC1C,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAY,CAAC;YACxD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,kFAAkF;QACpF,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAC;QACvB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,YAAY,EAAE,GAAG,CAAC,aAAa;QAC/B,aAAa,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;QACzC,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,aAAa;KACd,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;AAEtF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAoC;IACtE,OAAO,KAAK,EAAE,QAAgB,EAAE,EAAE;QAChC,oEAAoE;QACpE,EAAE;QACF,+EAA+E;QAC/E,kFAAkF;QAClF,8EAA8E;QAC9E,gFAAgF;QAChF,gFAAgF;QAChF,EAAE;QACF,kFAAkF;QAClF,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CACzB,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,CACZ,CAAC;QAC/B,OAAO,aAAa,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"route-resolver.js","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { DurableObject } from 'cloudflare:workers';
2
+ import { type WireFailure } from '@substrat-run/contracts';
2
3
  import { type ModuleRegistration, type OperationHandler } from '@substrat-run/kernel';
3
4
  /**
4
5
  * `defineScopeDO` — one Durable Object per scope, the CF analogue of a single
@@ -31,6 +32,16 @@ export interface ScopeDoEnv {
31
32
  */
32
33
  SUBSTRAT_VERSION_ID?: string;
33
34
  }
35
+ /**
36
+ * What a capability attachment verb (#1686) answers: its value, or its failure as DATA —
37
+ * `invoke`'s envelope discipline, since a throw across the RPC keeps only its message.
38
+ */
39
+ export type CapabilityAttachmentReply<T> = {
40
+ value: T;
41
+ failure?: undefined;
42
+ } | {
43
+ failure: WireFailure;
44
+ };
34
45
  export declare function splitSqlStatements(sql: string): string[];
35
46
  export declare function defineScopeDO(modules: ModuleRegistration[], bareOps: Record<string, OperationHandler<never, unknown>>): new (ctx: DurableObjectState, env: ScopeDoEnv) => DurableObject;
36
47
  //# sourceMappingURL=scope-do.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope-do.d.ts","sourceRoot":"","sources":["../src/scope-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAkDnD,OAAO,EA+CL,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAkDtB,MAAM,sBAAsB,CAAC;AA+D9B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAkdD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAwDxD;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,GACxD,KAAK,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,UAAU,KAAK,aAAa,CAuiIjE"}
1
+ {"version":3,"file":"scope-do.d.ts","sourceRoot":"","sources":["../src/scope-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAWL,KAAK,WAAW,EAqCjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAmDL,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EA8DtB,MAAM,sBAAsB,CAAC;AA6E9B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAwaD;;;GAGG;AACH,MAAM,MAAM,yBAAyB,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAgDxG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAwDxD;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,GACxD,KAAK,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,UAAU,KAAK,aAAa,CA48IjE"}