@substrat-run/adapter-cloudflare 0.119.0 → 0.121.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/control-plane-do.d.ts +83 -17
- package/dist/control-plane-do.d.ts.map +1 -1
- package/dist/control-plane-do.js +141 -44
- package/dist/control-plane-do.js.map +1 -1
- package/dist/host.d.ts +96 -4
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +431 -76
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/kick-coalescer-do.d.ts +57 -0
- package/dist/kick-coalescer-do.d.ts.map +1 -0
- package/dist/kick-coalescer-do.js +106 -0
- package/dist/kick-coalescer-do.js.map +1 -0
- package/dist/route-resolver.d.ts +4 -3
- package/dist/route-resolver.d.ts.map +1 -1
- package/dist/route-resolver.js +5 -4
- package/dist/route-resolver.js.map +1 -1
- package/dist/scope-do.d.ts +7 -1
- package/dist/scope-do.d.ts.map +1 -1
- package/dist/scope-do.js +69 -12
- package/dist/scope-do.js.map +1 -1
- package/package.json +7 -5
package/dist/index.d.ts
CHANGED
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
* driving `drainDue`/`runDueSchedules` per scope (#461)
|
|
15
15
|
*/
|
|
16
16
|
export { CloudflareScopeHost } from './host.js';
|
|
17
|
-
export type { CloudflareScopeHostOptions, ConnectorDelegation, EventDrainDelegation, PeerSwitchDelegation, SystemSwitchDelegation, } from './host.js';
|
|
17
|
+
export type { CloudflareScopeHostOptions, ConnectorDelegation, EventDrainDelegation, PeerSwitchDelegation, ImportCursorDelegation, 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';
|
|
21
21
|
export { doScopedSql } from './sql.js';
|
|
22
22
|
export { createDoTupleChecker } from './checker.js';
|
|
23
23
|
export { definePlatformSweeperDO, PLATFORM_SWEEPER_NAME } from './platform-sweeper-do.js';
|
|
24
|
+
export { defineKickCoalescerDO, kickCoalescerName, CROSS_VERTICAL_KICK_WINDOW_MS, type KickCoalescerConfig, type KickCoalescerDo, type KickOutcome, type KickProducer, } from './kick-coalescer-do.js';
|
|
24
25
|
export type { PlatformSweeperDoConfig, PlatformSweepOutcome } from './platform-sweeper-do.js';
|
|
25
26
|
export { defineScopeSweeperDO, SCOPE_SWEEPER_NAME } from './scope-sweeper-do.js';
|
|
26
27
|
export type { ScopeSweeperDo, ScopeSweeperDoConfig, ScopeSweepHost, ScopeSweepOutcome, ScopeSweepReport, } from './scope-sweeper-do.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,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;
|
|
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,EACtB,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;AAE1F,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,6BAA6B,EAC7B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAChC,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
CHANGED
|
@@ -20,6 +20,8 @@ export { OperationQueue } from './serialization.js';
|
|
|
20
20
|
export { doScopedSql } from './sql.js';
|
|
21
21
|
export { createDoTupleChecker } from './checker.js';
|
|
22
22
|
export { definePlatformSweeperDO, PLATFORM_SWEEPER_NAME } from './platform-sweeper-do.js';
|
|
23
|
+
// #1705 PR 2: the global bound on the router's cross-vertical kick, one object per producer.
|
|
24
|
+
export { defineKickCoalescerDO, kickCoalescerName, CROSS_VERTICAL_KICK_WINDOW_MS, } from './kick-coalescer-do.js';
|
|
23
25
|
export { defineScopeSweeperDO, SCOPE_SWEEPER_NAME } from './scope-sweeper-do.js';
|
|
24
26
|
export { createD1TenantStores, d1TenantRelationalStore, tenantStoreDatabaseName, } from './d1.js';
|
|
25
27
|
export { blobStoreBucketName, createR2BlobStores, r2TenantBlobStore, } from './r2.js';
|
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;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAShD,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,6FAA6F;AAC7F,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,6BAA6B,GAK9B,MAAM,wBAAwB,CAAC;AAEhC,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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { DurableObject } from 'cloudflare:workers';
|
|
2
|
+
import type { ScopeId, TenantId } from '@substrat-run/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* How long one producer's cross-vertical kicks coalesce (#1705 PR 2): after a pass STARTS, the
|
|
5
|
+
* next may start no sooner than this. A burst inside the window costs the pass that started it
|
|
6
|
+
* plus one trailing pass at the window's end, fleet-wide. It is not per isolate, because one
|
|
7
|
+
* Durable Object per producer holds the bit.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CROSS_VERTICAL_KICK_WINDOW_MS = 5000;
|
|
10
|
+
/** What one kick did: started a pass, joined the one running, or left it for the window's end. */
|
|
11
|
+
export type KickOutcome = 'ran' | 'coalesced' | 'deferred';
|
|
12
|
+
/** The producer a kick names: the scope the router resolved, and its tenant. Nothing else. */
|
|
13
|
+
export interface KickProducer {
|
|
14
|
+
tenantId: TenantId;
|
|
15
|
+
scopeId: ScopeId;
|
|
16
|
+
}
|
|
17
|
+
/** The RPC surface a `defineKickCoalescerDO` class exposes over its stub. */
|
|
18
|
+
export interface KickCoalescerDo {
|
|
19
|
+
kick(tenantId: TenantId, scopeId: ScopeId): Promise<KickOutcome>;
|
|
20
|
+
}
|
|
21
|
+
export interface KickCoalescerConfig<Env> {
|
|
22
|
+
/** Default {@link CROSS_VERTICAL_KICK_WINDOW_MS}. */
|
|
23
|
+
windowMs?: number;
|
|
24
|
+
/**
|
|
25
|
+
* One pass for this producer. CODE-TIME, closed over like `definePlatformSweeperDO`'s
|
|
26
|
+
* `sweep`, since a Durable Object cannot receive a closure over RPC. It is where the
|
|
27
|
+
* authority lives: the deployment runs `runCrossVerticalFrom` here with the same reach and
|
|
28
|
+
* gates as its sweep, so this object decides only WHEN, never what or for whom.
|
|
29
|
+
*/
|
|
30
|
+
run(env: Env, producer: KickProducer): Promise<void>;
|
|
31
|
+
/** A pass that threw. Never rethrown: a lost kick costs latency, and the sweep is the backstop. */
|
|
32
|
+
onError?(err: unknown, env: Env): void;
|
|
33
|
+
}
|
|
34
|
+
/** The one instance per producer: `ns.get(ns.idFromName(kickCoalescerName(tenantId, scopeId)))`. */
|
|
35
|
+
export declare function kickCoalescerName(tenantId: TenantId, scopeId: ScopeId): string;
|
|
36
|
+
/**
|
|
37
|
+
* `defineKickCoalescerDO` — the global bound on the router kick (#1705 PR 2).
|
|
38
|
+
*
|
|
39
|
+
* The kick is raised by a response header that tenant code sets, so a vertical can raise it on
|
|
40
|
+
* every response it serves. Each one is a producer-scoped cross-vertical pass: a directory read,
|
|
41
|
+
* registry reads, and up to `maxConsumers × (1 + 2 × sources)` `/internal` calls. The phase caps
|
|
42
|
+
* one pass, not passes per unit of time. This object is that second cap, and it holds nothing
|
|
43
|
+
* else: no authority and no data, only a start time and a dirty bit.
|
|
44
|
+
*
|
|
45
|
+
* - A kick with no pass running and none started within the window starts one, and waits for it.
|
|
46
|
+
* - A kick while a pass runs marks the producer dirty and returns at once. When the pass ends,
|
|
47
|
+
* a dirty producer gets one trailing pass at the window's end, by alarm.
|
|
48
|
+
* - A kick inside the window marks it dirty and returns at once. The same alarm runs the
|
|
49
|
+
* trailing pass.
|
|
50
|
+
*
|
|
51
|
+
* So passes for one producer start at least `windowMs` apart. A burst of N kicks costs one pass
|
|
52
|
+
* plus one trailing pass, and nothing a tenant sends can raise that. The trailing pass is what
|
|
53
|
+
* keeps coalescing lossless: an event committed after the first pass read its outbox is still
|
|
54
|
+
* moved within one window, not left for the next sweep.
|
|
55
|
+
*/
|
|
56
|
+
export declare function defineKickCoalescerDO<Env>(config: KickCoalescerConfig<Env>): new (ctx: DurableObjectState, env: Env) => DurableObject<Env> & KickCoalescerDo;
|
|
57
|
+
//# sourceMappingURL=kick-coalescer-do.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kick-coalescer-do.d.ts","sourceRoot":"","sources":["../src/kick-coalescer-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AAEnD,kGAAkG;AAClG,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC;AAE3D,8FAA8F;AAC9F,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,mBAAmB,CAAC,GAAG;IACtC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,mGAAmG;IACnG,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;CACxC;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAE9E;AAUD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EACvC,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,GAC/B,KAAK,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,KAAK,aAAa,CAAC,GAAG,CAAC,GAAG,eAAe,CAwEjF"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { DurableObject } from 'cloudflare:workers';
|
|
2
|
+
/**
|
|
3
|
+
* How long one producer's cross-vertical kicks coalesce (#1705 PR 2): after a pass STARTS, the
|
|
4
|
+
* next may start no sooner than this. A burst inside the window costs the pass that started it
|
|
5
|
+
* plus one trailing pass at the window's end, fleet-wide. It is not per isolate, because one
|
|
6
|
+
* Durable Object per producer holds the bit.
|
|
7
|
+
*/
|
|
8
|
+
export const CROSS_VERTICAL_KICK_WINDOW_MS = 5_000;
|
|
9
|
+
/** The one instance per producer: `ns.get(ns.idFromName(kickCoalescerName(tenantId, scopeId)))`. */
|
|
10
|
+
export function kickCoalescerName(tenantId, scopeId) {
|
|
11
|
+
return `${tenantId}:${scopeId}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* `defineKickCoalescerDO` — the global bound on the router kick (#1705 PR 2).
|
|
15
|
+
*
|
|
16
|
+
* The kick is raised by a response header that tenant code sets, so a vertical can raise it on
|
|
17
|
+
* every response it serves. Each one is a producer-scoped cross-vertical pass: a directory read,
|
|
18
|
+
* registry reads, and up to `maxConsumers × (1 + 2 × sources)` `/internal` calls. The phase caps
|
|
19
|
+
* one pass, not passes per unit of time. This object is that second cap, and it holds nothing
|
|
20
|
+
* else: no authority and no data, only a start time and a dirty bit.
|
|
21
|
+
*
|
|
22
|
+
* - A kick with no pass running and none started within the window starts one, and waits for it.
|
|
23
|
+
* - A kick while a pass runs marks the producer dirty and returns at once. When the pass ends,
|
|
24
|
+
* a dirty producer gets one trailing pass at the window's end, by alarm.
|
|
25
|
+
* - A kick inside the window marks it dirty and returns at once. The same alarm runs the
|
|
26
|
+
* trailing pass.
|
|
27
|
+
*
|
|
28
|
+
* So passes for one producer start at least `windowMs` apart. A burst of N kicks costs one pass
|
|
29
|
+
* plus one trailing pass, and nothing a tenant sends can raise that. The trailing pass is what
|
|
30
|
+
* keeps coalescing lossless: an event committed after the first pass read its outbox is still
|
|
31
|
+
* moved within one window, not left for the next sweep.
|
|
32
|
+
*/
|
|
33
|
+
export function defineKickCoalescerDO(config) {
|
|
34
|
+
const windowMs = config.windowMs ?? CROSS_VERTICAL_KICK_WINDOW_MS;
|
|
35
|
+
return class KickCoalescerDO extends DurableObject {
|
|
36
|
+
/** The in-flight pass, when one is running. */
|
|
37
|
+
#running = null;
|
|
38
|
+
async kick(tenantId, scopeId) {
|
|
39
|
+
const prior = await this.ctx.storage.get('state');
|
|
40
|
+
const state = prior ?? { producer: { tenantId, scopeId }, lastStartedAt: 0, dirty: false };
|
|
41
|
+
if (this.#running) {
|
|
42
|
+
await this.ctx.storage.put('state', { ...state, dirty: true });
|
|
43
|
+
return 'coalesced';
|
|
44
|
+
}
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
if (now - state.lastStartedAt < windowMs) {
|
|
47
|
+
await this.ctx.storage.put('state', { ...state, dirty: true });
|
|
48
|
+
await this.#armFor(state.lastStartedAt);
|
|
49
|
+
return 'deferred';
|
|
50
|
+
}
|
|
51
|
+
await this.#pass(state);
|
|
52
|
+
return 'ran';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The window's end: the trailing pass if a kick arrived that no pass has covered, and
|
|
56
|
+
* otherwise the end of this object. Its storage is deleted, so a producer that kicked once
|
|
57
|
+
* leaves nothing behind. That waits for the window's end, so a kick after the delete may run
|
|
58
|
+
* at once without breaking the bound.
|
|
59
|
+
*/
|
|
60
|
+
async alarm() {
|
|
61
|
+
const state = await this.ctx.storage.get('state');
|
|
62
|
+
if (!state || this.#running)
|
|
63
|
+
return;
|
|
64
|
+
// The window holds even against an early alarm: re-arm for its end rather than act.
|
|
65
|
+
if (Date.now() - state.lastStartedAt < windowMs) {
|
|
66
|
+
await this.#armFor(state.lastStartedAt);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (state.dirty) {
|
|
70
|
+
await this.#pass(state);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
await this.ctx.storage.deleteAlarm();
|
|
74
|
+
await this.ctx.storage.deleteAll();
|
|
75
|
+
}
|
|
76
|
+
async #pass(state) {
|
|
77
|
+
const startedAt = Date.now();
|
|
78
|
+
await this.ctx.storage.put('state', { ...state, lastStartedAt: startedAt, dirty: false });
|
|
79
|
+
this.#running = (async () => {
|
|
80
|
+
try {
|
|
81
|
+
await config.run(this.env, state.producer);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
config.onError?.(err, this.env);
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
try {
|
|
88
|
+
await this.#running;
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
this.#running = null;
|
|
92
|
+
// Always, at this window's end: the alarm runs the trailing pass if a kick arrived since
|
|
93
|
+
// this one started, and clears this object's storage if none did.
|
|
94
|
+
await this.#armFor(startedAt);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Arm the trailing pass for the end of the window that started at `startedAt`. */
|
|
98
|
+
async #armFor(startedAt) {
|
|
99
|
+
const at = startedAt + windowMs;
|
|
100
|
+
const existing = await this.ctx.storage.getAlarm();
|
|
101
|
+
if (existing === null || existing > at)
|
|
102
|
+
await this.ctx.storage.setAlarm(at);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=kick-coalescer-do.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kick-coalescer-do.js","sourceRoot":"","sources":["../src/kick-coalescer-do.ts"],"names":[],"mappings":"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"}
|
package/dist/route-resolver.d.ts
CHANGED
|
@@ -41,9 +41,10 @@ export declare const normalizeHostname: (hostname: string) => string;
|
|
|
41
41
|
* carve-out `resolveIdentity` has (K-24). Only `active` bindings resolve, so a
|
|
42
42
|
* hostname still validating DNS or one whose certificate failed is simply unknown.
|
|
43
43
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* The directory requires an active hostname, correctly paired active scope and
|
|
45
|
+
* active owning tenant (#1713). CP-less verticals rely on this request-path gate;
|
|
46
|
+
* CP-backed `getScope` retains its own check. No lifecycle state crosses the wire.
|
|
47
|
+
* Direct/background calls and already-dispatched requests remain outside this gate.
|
|
47
48
|
*
|
|
48
49
|
* Uncached, per request, on purpose: K-26 defers cache invalidation to open
|
|
49
50
|
* question 5 rather than answering it twice, because a cached route that keeps
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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;;;;;;;;;;;;;;;GAeG;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"}
|
package/dist/route-resolver.js
CHANGED
|
@@ -2,7 +2,7 @@ import { callDepthMessage, callsDeclares, PEER_CALL_DEPTH_MAX, previewCallerMess
|
|
|
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) {
|
|
5
|
-
// No status check here: `readRoute`
|
|
5
|
+
// No status check here: `readRoute` gates hostname, scope and tenant lifecycle in SQL, the same
|
|
6
6
|
// way adapter-sqlite's `resolveHostname` does. One place decides what resolves.
|
|
7
7
|
if (!row)
|
|
8
8
|
return undefined;
|
|
@@ -54,9 +54,10 @@ export const normalizeHostname = (hostname) => hostname.toLowerCase();
|
|
|
54
54
|
* carve-out `resolveIdentity` has (K-24). Only `active` bindings resolve, so a
|
|
55
55
|
* hostname still validating DNS or one whose certificate failed is simply unknown.
|
|
56
56
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
57
|
+
* The directory requires an active hostname, correctly paired active scope and
|
|
58
|
+
* active owning tenant (#1713). CP-less verticals rely on this request-path gate;
|
|
59
|
+
* CP-backed `getScope` retains its own check. No lifecycle state crosses the wire.
|
|
60
|
+
* Direct/background calls and already-dispatched requests remain outside this gate.
|
|
60
61
|
*
|
|
61
62
|
* Uncached, per request, on purpose: K-26 defers cache invalidation to open
|
|
62
63
|
* question 5 rather than answering it twice, because a cached route that keeps
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-resolver.js","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,qBAAqB,GAGtB,MAAM,yBAAyB,CAAC;AAwCjC;yDACyD;AACzD,MAAM,UAAU,aAAa,CAAC,GAA6B;IACzD,
|
|
1
|
+
{"version":3,"file":"route-resolver.js","sourceRoot":"","sources":["../src/route-resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/scope-do.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DurableObject } from 'cloudflare:workers';
|
|
2
2
|
import { type WireFailure } from '@substrat-run/contracts';
|
|
3
|
-
import { type ModuleRegistration, type OperationHandler } from '@substrat-run/kernel';
|
|
3
|
+
import { type SwitchSql, type ModuleRegistration, type OperationHandler } from '@substrat-run/kernel';
|
|
4
4
|
/**
|
|
5
5
|
* `defineScopeDO` — one Durable Object per scope, the CF analogue of a single
|
|
6
6
|
* `SqliteScopeHost` scope runtime (D-14). It closes over a CODE-TIME module set
|
|
@@ -42,6 +42,12 @@ export type CapabilityAttachmentReply<T> = {
|
|
|
42
42
|
} | {
|
|
43
43
|
failure: WireFailure;
|
|
44
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* The kernel's two-method SQL handle (`SwitchSql`) over a Durable Object's storage — what the
|
|
47
|
+
* shared switch rules (#1666) and the directory's switch record (#1674) run through. One
|
|
48
|
+
* wrapper for both DOs, as the pure adapter has one `switchSqlOf`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function switchSqlOver(sql: SqlStorage): SwitchSql;
|
|
45
51
|
export declare function splitSqlStatements(sql: string): string[];
|
|
46
52
|
export declare function defineScopeDO(modules: ModuleRegistration[], bareOps: Record<string, OperationHandler<never, unknown>>): new (ctx: DurableObjectState, env: ScopeDoEnv) => DurableObject;
|
|
47
53
|
//# sourceMappingURL=scope-do.d.ts.map
|
package/dist/scope-do.d.ts.map
CHANGED
|
@@ -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;AACnD,OAAO,EAWL,KAAK,WAAW,EAqCjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,
|
|
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,EAiCL,KAAK,SAAS,EAkBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAgEtB,MAAM,sBAAsB,CAAC;AA+E9B;;;;;;;;;;;;;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;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,CAOxD;AAED,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,CAkgJjE"}
|
package/dist/scope-do.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DurableObject } from 'cloudflare:workers';
|
|
2
2
|
import { ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, domainEvent, domainEventInput, eventId, instant, objectRef, toWireFailure, grantRefFromProof, principalId, scopeId as scopeIdOf, tenantId as tenantIdOf, platformRequestInput, platformRequestId, MAX_PENDING_PLATFORM_REQUESTS, MAX_PENDING_SWEEP_RUNS, SWEEP_RUNS_KIND, SCOPE_TABLE_PAGE_MAX, SCOPE_QUERY_ROW_MAX, listLimitOf, requestFingerprint, substratError, assertReplayableDump, REDRAIN_BATCH, } from '@substrat-run/contracts';
|
|
3
|
-
import { ulid, createUlid, assertAllowed, ConnectionSealingKeyUnavailableError, noSealingKeyMessage, sealTo, assertReadOnlyQuery, entitlementDenial, platformRequestHistoryQuery, platformRequestOf, PLATFORM_REQUEST_COLUMNS, PLATFORM_REQUEST_REDACTION_SQL, platformRequestRedactionParams, platformRequestRedactionQuery, intentPayloadCarriesSubject, redactSubjectJobRuns, JOB_RUN_PATCH_SQL, JOB_STEP_RECORD_SQL, DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, seatScopeTuple, effectiveRoleGrantQuery, switchSystemSchedules, peerGrantsStatus, systemGrantsStatus, systemScheduleState, systemSwitchedOff, denialListQuery, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialSummaryBuckets, PermissionDenied, assertImpersonationWrites, assertModuleEnqueueableKind, impersonationStampOf, createAtomic, NotSearchable, isSearchIndexTable, searchIndexDdl,
|
|
3
|
+
import { ulid, createUlid, assertAllowed, ConnectionSealingKeyUnavailableError, noSealingKeyMessage, sealTo, assertReadOnlyQuery, entitlementDenial, platformRequestHistoryQuery, platformRequestOf, PLATFORM_REQUEST_COLUMNS, PLATFORM_REQUEST_REDACTION_SQL, platformRequestRedactionParams, platformRequestRedactionQuery, intentPayloadCarriesSubject, redactSubjectJobRuns, JOB_RUN_PATCH_SQL, JOB_STEP_RECORD_SQL, DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, seatScopeTuple, effectiveRoleGrantQuery, switchSystemSchedules, peerGrantsStatus, systemGrantsStatus, systemScheduleState, systemSwitchedOff, denialListQuery, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialSummaryBuckets, PermissionDenied, assertImpersonationWrites, assertModuleEnqueueableKind, impersonationStampOf, createAtomic, NotSearchable, isSearchIndexTable, searchIndexDdl, searchIndexPlans, NotListable, listIndexPlans, moduleMigrations, listQuery, cursorOf, searchLimit, searchMatchExpression, searchQuery, IDEMPOTENCY_DDL, assertIdempotencyKey, assertPermissionKey, idempotencyLookupQuery, idempotencyPruneStatement, idempotencyRecordStatement, idempotencyOptedOutMessage, replayFor, entityVersionQuery, entityVersionOf, assertIfMatch, OUTBOX_ENTITY_INDEX, SCHEDULE_STATE_DDL, SCHEDULE_STATE_REBUILD, scheduleStateHasKind, VERTICAL_EVENTS_DDL, EXPORT_HOPS_SQL, IMPORT_CURSORS_SQL, IMPORT_CURSOR_OF_SQL, OUTBOX_MARK_SQL, exportedSinceQuery, IMPORT_CURSOR_ADVANCE_SQL, IMPORT_RECORD_SQL, moveImportCursor, CrossVerticalRegistry, exportReadPlan, exportReadQuery, planExportBatch, withheldNote, JOB_RUN_DDL, jobRunListLimit, } from '@substrat-run/kernel';
|
|
4
4
|
import { isUpgradeRequest, readSubscription, LIVE_FANOUT_LIMIT, LIVE_MODE_HEADER, LIVE_PRINCIPAL_HEADER, LIVE_SCOPE_HEADER, LIVE_SUBSCRIBE_PATH, LIVE_TENANT_HEADER, } from './live-reads.js';
|
|
5
5
|
import { OperationQueue } from './serialization.js';
|
|
6
6
|
import { doScopedSql, doSpineSql } from './sql.js';
|
|
@@ -414,6 +414,19 @@ function cellToJson(v) {
|
|
|
414
414
|
*/
|
|
415
415
|
const IS_CREATE_TRIGGER = /^\s*CREATE\s+(TEMP\s+|TEMPORARY\s+)?TRIGGER\b/i;
|
|
416
416
|
const ENDS_WITH_END = /\bEND\s*$/i;
|
|
417
|
+
/**
|
|
418
|
+
* The kernel's two-method SQL handle (`SwitchSql`) over a Durable Object's storage — what the
|
|
419
|
+
* shared switch rules (#1666) and the directory's switch record (#1674) run through. One
|
|
420
|
+
* wrapper for both DOs, as the pure adapter has one `switchSqlOf`.
|
|
421
|
+
*/
|
|
422
|
+
export function switchSqlOver(sql) {
|
|
423
|
+
return {
|
|
424
|
+
all: (q, ...params) => sql.exec(q, ...params).toArray(),
|
|
425
|
+
run: (q, ...params) => {
|
|
426
|
+
sql.exec(q, ...params);
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
}
|
|
417
430
|
export function splitSqlStatements(sql) {
|
|
418
431
|
const out = [];
|
|
419
432
|
let cur = '';
|
|
@@ -601,11 +614,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
601
614
|
this.crossVertical.register(manifest, registration.imports);
|
|
602
615
|
this.modules.set(manifest.id, {
|
|
603
616
|
id: manifest.id,
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
...searchIndexMigrations(manifest.id, manifest.searchables),
|
|
607
|
-
...listIndexMigrations(manifest.id, manifest.lists),
|
|
608
|
-
],
|
|
617
|
+
// The order the kernel writes once (#1677): authored, then search, then list indexes.
|
|
618
|
+
migrations: moduleMigrations(registration),
|
|
609
619
|
consumers: Object.entries(registration.consumers ?? {}).map(([eventType, handler]) => ({
|
|
610
620
|
eventType,
|
|
611
621
|
handler,
|
|
@@ -889,6 +899,35 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
889
899
|
}));
|
|
890
900
|
return { consumes, cursors };
|
|
891
901
|
}
|
|
902
|
+
/**
|
|
903
|
+
* #1705 PR 2: does this DO hold a scope PROVISIONED here for `tenantId`?
|
|
904
|
+
*
|
|
905
|
+
* A CP-less deployment has no directory to ask whether it serves a scope. What it does
|
|
906
|
+
* have is what provisioning wrote: `provisionScopeLocal` projects the vertical's role
|
|
907
|
+
* definitions under the tenant (`_substrat_roles`), and a restore re-projects them. A scope
|
|
908
|
+
* this deployment never provisioned has none of that. Its DO is empty, and a cross-vertical
|
|
909
|
+
* verb answering from it is a wrong answer rather than a failure: a watermark of "never
|
|
910
|
+
* read", or a delivery journaled into a scope that is not the install. A scope provisioned
|
|
911
|
+
* for ANOTHER tenant has roles under that tenant's id only, so the same read is K-3's pair
|
|
912
|
+
* check too.
|
|
913
|
+
*
|
|
914
|
+
* Read without migrating, so asking about a foreign scope leaves its DO as empty as it found it.
|
|
915
|
+
*/
|
|
916
|
+
async servesTenant(tenantId) {
|
|
917
|
+
const hasRoles = this.sql.exec(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = '_substrat_roles'`).toArray().length > 0;
|
|
918
|
+
if (!hasRoles)
|
|
919
|
+
return false;
|
|
920
|
+
return this.sql.exec('SELECT 1 FROM _substrat_roles WHERE tenant_id = ? LIMIT 1', tenantId).toArray().length > 0;
|
|
921
|
+
}
|
|
922
|
+
/** #1705 PR 2: the outbox's insertion mark (`OUTBOX_MARK_SQL`). */
|
|
923
|
+
outboxMark() {
|
|
924
|
+
return Number(this.sql.exec(OUTBOX_MARK_SQL).toArray()[0]?.mark ?? 0);
|
|
925
|
+
}
|
|
926
|
+
/** #1705 PR 2: exported-type rows added above `mark`. */
|
|
927
|
+
exportedSince(types, mark) {
|
|
928
|
+
const q = exportedSinceQuery(types, mark);
|
|
929
|
+
return Number(this.sql.exec(q.sql, ...q.params).toArray()[0]?.n ?? 0);
|
|
930
|
+
}
|
|
892
931
|
/**
|
|
893
932
|
* #1705: apply a batch another vertical exported. The pure adapter's `deliverToPeer`
|
|
894
933
|
* body, on this scope's queue: the compare-and-set on the watermark, a dead letter per
|
|
@@ -1459,6 +1498,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
1459
1498
|
* which is the floor this whole surface sits on.
|
|
1460
1499
|
*/
|
|
1461
1500
|
const liveSince = this.liveHighWaterMark();
|
|
1501
|
+
// #1705 PR 2: the outbox's insertion mark, so the envelope can say whether this
|
|
1502
|
+
// invoke (or a consumer in its tail) committed an exported type. Only in a deployment
|
|
1503
|
+
// that exports something, and never for a read-only session, which commits nothing.
|
|
1504
|
+
const exportTypes = impersonation?.mode === 'read-only' ? [] : this.crossVertical.exportTypes();
|
|
1505
|
+
const exportMark = exportTypes.length > 0 ? this.outboxMark() : null;
|
|
1462
1506
|
let result;
|
|
1463
1507
|
let committedVersion = null;
|
|
1464
1508
|
// #116: set when this invocation was answered from a recording rather
|
|
@@ -1594,9 +1638,14 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
1594
1638
|
// call's own work — the same tail its consumers' emits are stamped in.
|
|
1595
1639
|
if (!replayed)
|
|
1596
1640
|
await this.settleCommitted(tenantId, scopeId, liveSince, this.invocationId);
|
|
1641
|
+
// After the tail, so an exported type a consumer emitted in it counts too.
|
|
1642
|
+
const exported = exportMark !== null && !replayed ? this.exportedSince(exportTypes, exportMark) : 0;
|
|
1597
1643
|
return {
|
|
1598
1644
|
result,
|
|
1599
1645
|
platformRequests: signals.platformRequests,
|
|
1646
|
+
// #1705 PR 2: the coordinator fires `onExportedEvents` from this. Omitted at 0, so
|
|
1647
|
+
// the envelope of a deployment that exports nothing is byte-for-byte what it was.
|
|
1648
|
+
...(exported > 0 ? { exported } : {}),
|
|
1600
1649
|
...(impersonation ? { impersonation: { honoured: true } } : {}),
|
|
1601
1650
|
// #1672: the acknowledgement the coordinator's skew check reads — see `invoke`.
|
|
1602
1651
|
...(capabilitySession !== undefined ? { capability: { honoured: true } } : {}),
|
|
@@ -2166,12 +2215,7 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2166
2215
|
}
|
|
2167
2216
|
/** The kernel's schedule-switch SQL (#1666), over this DO's storage. */
|
|
2168
2217
|
switchSql() {
|
|
2169
|
-
return
|
|
2170
|
-
all: (sql, ...params) => this.sql.exec(sql, ...params).toArray(),
|
|
2171
|
-
run: (sql, ...params) => {
|
|
2172
|
-
this.sql.exec(sql, ...params);
|
|
2173
|
-
},
|
|
2174
|
-
};
|
|
2218
|
+
return switchSqlOver(this.sql);
|
|
2175
2219
|
}
|
|
2176
2220
|
/**
|
|
2177
2221
|
* Where a module's schedules stand on this scope (#383, #1666) — the kernel's
|
|
@@ -2215,6 +2259,19 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2215
2259
|
async switchSystemSchedules(moduleId, scopeId, to, at) {
|
|
2216
2260
|
return this.queue.enqueue(() => this.ctx.storage.transactionSync(() => switchSystemSchedules(this.switchSql(), { moduleId, scopeId, to, at })));
|
|
2217
2261
|
}
|
|
2262
|
+
/**
|
|
2263
|
+
* The replay lever on this scope (#1705 PR 3): the kernel's `moveImportCursor`, queued with
|
|
2264
|
+
* every `importApply` on this scope and run as one `transactionSync`. A delivery on the same
|
|
2265
|
+
* edge is therefore wholly before the move, or refused by its compare-and-set after it.
|
|
2266
|
+
* Migrated first: the rows a replay moves aside go to `_substrat_import_replays`.
|
|
2267
|
+
*/
|
|
2268
|
+
async importCursorMove(input) {
|
|
2269
|
+
await this.ensureMigrations();
|
|
2270
|
+
// The consumer's own running imports decide whether the edge exists: read here, in the
|
|
2271
|
+
// deployment whose handlers would run, never from the platform's request.
|
|
2272
|
+
const imports = this.crossVertical.consumes();
|
|
2273
|
+
return this.queue.enqueue(() => this.ctx.storage.transactionSync(() => moveImportCursor(this.switchSql(), { ...input, imports })));
|
|
2274
|
+
}
|
|
2218
2275
|
/**
|
|
2219
2276
|
* Move one PEER's kill switch on this scope (#1706) — the kernel's `switchPeer`, which is
|
|
2220
2277
|
* the schedule switch's statement with a `vertical:` subject. Queued, one transaction.
|