@substrat-run/adapter-cloudflare 0.124.0 → 0.125.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/host.d.ts.map +1 -1
- package/dist/host.js +5 -3
- package/dist/host.js.map +1 -1
- package/dist/live-reads.d.ts +7 -9
- package/dist/live-reads.d.ts.map +1 -1
- package/dist/live-reads.js +7 -7
- package/dist/live-reads.js.map +1 -1
- package/dist/scope-do.d.ts.map +1 -1
- package/dist/scope-do.js +27 -1
- package/dist/scope-do.js.map +1 -1
- package/package.json +6 -6
package/dist/live-reads.d.ts
CHANGED
|
@@ -39,8 +39,12 @@ export declare const LIVE_SCOPE_HEADER = "x-substrat-live-scope";
|
|
|
39
39
|
* is how somebody reports "live updates are broken" two months later and nobody can
|
|
40
40
|
* establish whether they ever worked on that hostname. One header makes the fallback a
|
|
41
41
|
* fact the client can log, display, and report.
|
|
42
|
+
*
|
|
43
|
+
* Defined in the kernel (#1859), because the pure host's `501` names it too and a
|
|
44
|
+
* vertical's dev server should not import this adapter to spell it. Re-exported here so
|
|
45
|
+
* `host.ts` and `scope-do.ts` keep reading every wire name from this one file.
|
|
42
46
|
*/
|
|
43
|
-
export
|
|
47
|
+
export { LIVE_MODE_HEADER, type LiveRefusal } from '@substrat-run/kernel';
|
|
44
48
|
/**
|
|
45
49
|
* Cloudflare's own per-request marker for orange-to-orange routing.
|
|
46
50
|
*
|
|
@@ -58,12 +62,6 @@ export declare const LIVE_MODE_HEADER = "x-substrat-live";
|
|
|
58
62
|
* cheaper than a matrix and correct on the request after the tenant changes their DNS.
|
|
59
63
|
*/
|
|
60
64
|
export declare const O2O_HEADER = "cf-connecting-o2o";
|
|
61
|
-
/** Why a subscription was refused — the value of `LIVE_MODE_HEADER` on a refusal. */
|
|
62
|
-
export type LiveRefusal =
|
|
63
|
-
/** This connection cannot carry a WebSocket; the client should keep polling. */
|
|
64
|
-
'poll'
|
|
65
|
-
/** The request was not an upgrade at all — a programming error at the caller. */
|
|
66
|
-
| 'not-an-upgrade';
|
|
67
65
|
/**
|
|
68
66
|
* What a subscribed socket remembers about itself across a hibernation.
|
|
69
67
|
*
|
|
@@ -103,8 +101,8 @@ export declare function readSubscription(attachment: unknown): LiveSubscription
|
|
|
103
101
|
* reaching it means something unusual happened rather than something normal being cut off.
|
|
104
102
|
*/
|
|
105
103
|
export declare const LIVE_FANOUT_LIMIT = 200;
|
|
106
|
-
/** Is this request asking to be upgraded to a WebSocket? */
|
|
107
|
-
export
|
|
104
|
+
/** Is this request asking to be upgraded to a WebSocket? Defined in the kernel (#1859). */
|
|
105
|
+
export { isUpgradeRequest } from '@substrat-run/kernel';
|
|
108
106
|
/**
|
|
109
107
|
* Is this request arriving over an orange-to-orange hop?
|
|
110
108
|
*
|
package/dist/live-reads.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-reads.d.ts","sourceRoot":"","sources":["../src/live-reads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAE9E;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AACjE,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAC3D,eAAO,MAAM,iBAAiB,0BAA0B,CAAC;AAEzD
|
|
1
|
+
{"version":3,"file":"live-reads.d.ts","sourceRoot":"","sources":["../src/live-reads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAE9E;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AACjE,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAC3D,eAAO,MAAM,iBAAiB,0BAA0B,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE1E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,sBAAsB,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAa7E;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,2FAA2F;AAC3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE1D"}
|
package/dist/live-reads.js
CHANGED
|
@@ -27,8 +27,12 @@ export const LIVE_SCOPE_HEADER = 'x-substrat-live-scope';
|
|
|
27
27
|
* is how somebody reports "live updates are broken" two months later and nobody can
|
|
28
28
|
* establish whether they ever worked on that hostname. One header makes the fallback a
|
|
29
29
|
* fact the client can log, display, and report.
|
|
30
|
+
*
|
|
31
|
+
* Defined in the kernel (#1859), because the pure host's `501` names it too and a
|
|
32
|
+
* vertical's dev server should not import this adapter to spell it. Re-exported here so
|
|
33
|
+
* `host.ts` and `scope-do.ts` keep reading every wire name from this one file.
|
|
30
34
|
*/
|
|
31
|
-
export
|
|
35
|
+
export { LIVE_MODE_HEADER } from '@substrat-run/kernel';
|
|
32
36
|
/**
|
|
33
37
|
* Cloudflare's own per-request marker for orange-to-orange routing.
|
|
34
38
|
*
|
|
@@ -87,12 +91,8 @@ export function readSubscription(attachment) {
|
|
|
87
91
|
* reaching it means something unusual happened rather than something normal being cut off.
|
|
88
92
|
*/
|
|
89
93
|
export const LIVE_FANOUT_LIMIT = 200;
|
|
90
|
-
/** Is this request asking to be upgraded to a WebSocket? */
|
|
91
|
-
export
|
|
92
|
-
// Case-insensitive: the header is `Upgrade: websocket` by the RFC, but the token is
|
|
93
|
-
// compared case-insensitively there too, and browsers are not the only clients.
|
|
94
|
-
return (request.headers.get('Upgrade') ?? '').toLowerCase() === 'websocket';
|
|
95
|
-
}
|
|
94
|
+
/** Is this request asking to be upgraded to a WebSocket? Defined in the kernel (#1859). */
|
|
95
|
+
export { isUpgradeRequest } from '@substrat-run/kernel';
|
|
96
96
|
/**
|
|
97
97
|
* Is this request arriving over an orange-to-orange hop?
|
|
98
98
|
*
|
package/dist/live-reads.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-reads.js","sourceRoot":"","sources":["../src/live-reads.ts"],"names":[],"mappings":"AAaA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAC3D,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AAEzD
|
|
1
|
+
{"version":3,"file":"live-reads.js","sourceRoot":"","sources":["../src/live-reads.ts"],"names":[],"mappings":"AAaA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAC3D,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,gBAAgB,EAAoB,MAAM,sBAAsB,CAAC;AAE1E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAmB9C;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAmB;IAClD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACvE,MAAM,CAAC,GAAG,UAA8D,CAAC;IACzE,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACvE,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACnE,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO;QACL,SAAS,EAAE,CAAC,CAAC,SAAwB;QACrC,QAAQ,EAAE,CAAC,CAAC,QAAoB;QAChC,OAAO,EAAE,CAAC,CAAC,OAAkB;QAC7B,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC,2FAA2F;AAC3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC;AACjD,CAAC"}
|
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":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,
|
|
1
|
+
{"version":3,"file":"scope-do.d.ts","sourceRoot":"","sources":["../src/scope-do.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAYL,KAAK,WAAW,EAqCjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAmCL,KAAK,SAAS,EAmBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAoEtB,MAAM,sBAAsB,CAAC;AAiF9B;;;;;;;;;;;;;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,CA86JjE"}
|
package/dist/scope-do.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { REWIND_REFUSED } from './rewind-refusal.js';
|
|
2
2
|
import { DurableObject } from 'cloudflare:workers';
|
|
3
|
-
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 { ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, domainEvent, domainEventInput, eventId, instant, objectRef, entityObjectRef, 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';
|
|
4
4
|
import { ulid, DO_SQL_LIMITS, 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, switchRecordedOff, 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, emittedSinceQuery, emittedReportOf, EMITTED_REPORT_CAP, IMPORT_CURSOR_ADVANCE_SQL, IMPORT_RECORD_SQL, moveImportCursor, CrossVerticalRegistry, exportReadPlan, exportReadQuery, planExportBatch, withheldNote, JOB_RUN_DDL, jobRunListLimit, } from '@substrat-run/kernel';
|
|
5
5
|
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';
|
|
6
6
|
import { OperationQueue } from './serialization.js';
|
|
@@ -556,8 +556,20 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
556
556
|
lastFailure = null;
|
|
557
557
|
/** Passes of `applyPendingMigrations` that had work to do — see `migrationAttemptsOnInstance`. */
|
|
558
558
|
migrationRuns = 0;
|
|
559
|
+
/**
|
|
560
|
+
* TEST-ONLY (#1860): no production code reads this. An exact `'ping'` is answered
|
|
561
|
+
* by `setWebSocketAutoResponse` without reaching `webSocketMessage` at all, and
|
|
562
|
+
* this count is how a test proves that from outside the object — read through
|
|
563
|
+
* `runInDurableObject` — rather than assuming the runtime's documented behaviour.
|
|
564
|
+
*/
|
|
565
|
+
webSocketMessagesHandled = 0;
|
|
559
566
|
constructor(ctx, env) {
|
|
560
567
|
super(ctx, env);
|
|
568
|
+
// #1860: the client's 45s keep-alive (demos/ticket0/app/src/feed.ts) answered at
|
|
569
|
+
// the runtime level, before this object wakes for it. Without this, every idle
|
|
570
|
+
// subscriber's ping still reaches `webSocketMessage` and pins the DO in memory —
|
|
571
|
+
// exactly the hibernation cost `acceptWebSocket` (below) exists to avoid.
|
|
572
|
+
ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair('ping', 'pong'));
|
|
561
573
|
this.sql = ctx.storage.sql;
|
|
562
574
|
for (const stmt of splitSqlStatements(KERNEL_DDL)) {
|
|
563
575
|
this.sql.exec(stmt);
|
|
@@ -1827,8 +1839,14 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
1827
1839
|
* Deliberately NOT a place to let a client narrow or widen what it receives: a
|
|
1828
1840
|
* filter the client chooses is a filter the client can choose wrongly, and the
|
|
1829
1841
|
* only filter that matters here is the one it does not control.
|
|
1842
|
+
*
|
|
1843
|
+
* #1860: an exact `'ping'` is now answered by `setWebSocketAutoResponse` in the
|
|
1844
|
+
* constructor, at the runtime level, without waking this object — so this branch no
|
|
1845
|
+
* longer runs for it. Kept as the documented fallback for a client on an older
|
|
1846
|
+
* build, or a hop where the runtime's auto-response is unavailable.
|
|
1830
1847
|
*/
|
|
1831
1848
|
webSocketMessage(ws, message) {
|
|
1849
|
+
this.webSocketMessagesHandled++;
|
|
1832
1850
|
if (message === 'ping')
|
|
1833
1851
|
ws.send('pong');
|
|
1834
1852
|
}
|
|
@@ -4070,6 +4088,7 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
4070
4088
|
*/
|
|
4071
4089
|
grant: async (principal, permission, entity) => {
|
|
4072
4090
|
assertImpersonationWrites(impersonation, 'ctx.grant');
|
|
4091
|
+
entityObjectRef(entity, 'ctx.grant'); // #1856: a tuple the walk can read back
|
|
4073
4092
|
const held = await runCheck(permission, entity);
|
|
4074
4093
|
if (!held.allowed) {
|
|
4075
4094
|
throw new PermissionDenied(`cannot grant '${permission}' on ${entity.entityType}:${entity.entityId} — ` +
|
|
@@ -4077,6 +4096,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
4077
4096
|
}
|
|
4078
4097
|
sql.exec(`INSERT OR IGNORE INTO _substrat_tuples (subject, relation, object) VALUES (?, ?, ?)`, `principal:${principal}`, `granted:${permission}`, `${entity.entityType}:${entity.entityId}`);
|
|
4079
4098
|
},
|
|
4099
|
+
/**
|
|
4100
|
+
* Deliberately NOT the #1856 grammar check `grant` and `link` make: a revoke writes
|
|
4101
|
+
* nothing the walk must read back, and a grant stored before that check existed must
|
|
4102
|
+
* stay removable.
|
|
4103
|
+
*/
|
|
4080
4104
|
revoke: async (principal, permission, entity) => {
|
|
4081
4105
|
assertImpersonationWrites(impersonation, 'ctx.revoke');
|
|
4082
4106
|
const held = await runCheck(permission, entity);
|
|
@@ -4105,6 +4129,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
4105
4129
|
}),
|
|
4106
4130
|
link: (child, parent) => {
|
|
4107
4131
|
assertImpersonationWrites(impersonation, 'ctx.link');
|
|
4132
|
+
entityObjectRef(child, 'ctx.link'); // #1856: an edge the walk can read back
|
|
4133
|
+
entityObjectRef(parent, 'ctx.link');
|
|
4108
4134
|
const allowed = relations.get(child.entityType);
|
|
4109
4135
|
if (!allowed?.has(parent.entityType)) {
|
|
4110
4136
|
throw new Error(`undeclared entity relation: ${child.entityType} → ${parent.entityType} ` +
|