@substrat-run/adapter-cloudflare 0.150.0 → 0.152.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 +4 -7
- package/dist/host.js.map +1 -1
- package/dist/live-reads.d.ts +11 -1
- package/dist/live-reads.d.ts.map +1 -1
- package/dist/live-reads.js +33 -1
- package/dist/live-reads.js.map +1 -1
- package/dist/scope-do.d.ts.map +1 -1
- package/dist/scope-do.js +41 -20
- package/dist/scope-do.js.map +1 -1
- package/package.json +12 -12
package/dist/live-reads.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Nothing in this module reaches the network or the database. It is names and shapes.
|
|
11
11
|
*/
|
|
12
|
-
import { type EntityRef, type PrincipalId, type ScopeId, type TenantId } from '@substrat-run/contracts';
|
|
12
|
+
import { type EntityRef, type ErrorCode, type LiveRefusal, type PrincipalId, type ScopeId, type TenantId } from '@substrat-run/contracts';
|
|
13
13
|
import { type CheckedWithin, type VouchedWithin } from '@substrat-run/kernel';
|
|
14
14
|
/**
|
|
15
15
|
* The path the coordinator fetches on the scope stub to open a subscription.
|
|
@@ -97,6 +97,16 @@ export declare function decodeLiveWithin(header: string): LiveWithin | undefined
|
|
|
97
97
|
* one file.
|
|
98
98
|
*/
|
|
99
99
|
export { LIVE_CLOSE, LIVE_MODE_HEADER, type LiveRefusal } from '@substrat-run/contracts';
|
|
100
|
+
/** `liveRefusal` for a status the taxonomy has no code for (404, 426, 501): the `about:blank` form. */
|
|
101
|
+
export declare function liveRefusalStatus(status: number, detail: string, mode?: LiveRefusal): Response;
|
|
102
|
+
/**
|
|
103
|
+
* A refusal that is the taxonomy's own (`forbidden`, `internal`). `internal` never carries
|
|
104
|
+
* its `detail` on the wire: a 500 here is this package's bug, not the client's, so the
|
|
105
|
+
* sentence goes to the log instead, where a coordinator/DO skew can still be told apart.
|
|
106
|
+
* The sentences are fixed strings naming the assertion that failed — never a value, an id
|
|
107
|
+
* or a header's content.
|
|
108
|
+
*/
|
|
109
|
+
export declare function liveRefusal(code: ErrorCode, detail: string, mode?: LiveRefusal): Response;
|
|
100
110
|
/**
|
|
101
111
|
* How many live sockets one principal may hold on one scope (#938). A tab holds one per
|
|
102
112
|
* feed (the desk's, and one per open conversation in ticket0's portal), and each socket is
|
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,
|
|
1
|
+
{"version":3,"file":"live-reads.d.ts","sourceRoot":"","sources":["../src/live-reads.ts"],"names":[],"mappings":"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"}
|
package/dist/live-reads.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Nothing in this module reaches the network or the database. It is names and shapes.
|
|
11
11
|
*/
|
|
12
|
-
import { permissionKey, substratError, } from '@substrat-run/contracts';
|
|
12
|
+
import { LIVE_MODE_HEADER, permissionKey, problemForStatus, PROBLEM_CONTENT_TYPE, substratError, toProblem, } from '@substrat-run/contracts';
|
|
13
13
|
import { isCheckedWithin, isVouchedWithin } from '@substrat-run/kernel';
|
|
14
14
|
/**
|
|
15
15
|
* The path the coordinator fetches on the scope stub to open a subscription.
|
|
@@ -130,6 +130,38 @@ export function decodeLiveWithin(header) {
|
|
|
130
130
|
* one file.
|
|
131
131
|
*/
|
|
132
132
|
export { LIVE_CLOSE, LIVE_MODE_HEADER } from '@substrat-run/contracts';
|
|
133
|
+
/**
|
|
134
|
+
* A refusal on this surface, answered as the problem document it is (#113).
|
|
135
|
+
*
|
|
136
|
+
* The door (`host.ts`) and the scope's `fetch` (`scope-do.ts`) both refuse with a
|
|
137
|
+
* `Response`, because a refusal here is a fact about the connection and not a throw, so the
|
|
138
|
+
* media type and the `LIVE_MODE_HEADER` pairing live in one place. `mode` is the value a
|
|
139
|
+
* client keys its fallback on; a refusal that is nobody's fallback (the DO's own 404, a 500
|
|
140
|
+
* that is this package's bug) carries none. Status, sentence and header values are the
|
|
141
|
+
* callers' own and are unchanged from the `text/plain` answers this replaces.
|
|
142
|
+
*/
|
|
143
|
+
function serveLiveRefusal(body, mode) {
|
|
144
|
+
return new Response(JSON.stringify(body), {
|
|
145
|
+
status: body.status,
|
|
146
|
+
headers: { 'content-type': PROBLEM_CONTENT_TYPE, ...(mode === undefined ? {} : { [LIVE_MODE_HEADER]: mode }) },
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/** `liveRefusal` for a status the taxonomy has no code for (404, 426, 501): the `about:blank` form. */
|
|
150
|
+
export function liveRefusalStatus(status, detail, mode) {
|
|
151
|
+
return serveLiveRefusal(problemForStatus(status, detail), mode);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A refusal that is the taxonomy's own (`forbidden`, `internal`). `internal` never carries
|
|
155
|
+
* its `detail` on the wire: a 500 here is this package's bug, not the client's, so the
|
|
156
|
+
* sentence goes to the log instead, where a coordinator/DO skew can still be told apart.
|
|
157
|
+
* The sentences are fixed strings naming the assertion that failed — never a value, an id
|
|
158
|
+
* or a header's content.
|
|
159
|
+
*/
|
|
160
|
+
export function liveRefusal(code, detail, mode) {
|
|
161
|
+
if (code === 'internal')
|
|
162
|
+
console.error('substrat: live-read refused:', detail);
|
|
163
|
+
return serveLiveRefusal(toProblem(substratError(code, detail)), mode);
|
|
164
|
+
}
|
|
133
165
|
/**
|
|
134
166
|
* How many live sockets one principal may hold on one scope (#938). A tab holds one per
|
|
135
167
|
* feed (the desk's, and one per open conversation in ticket0's portal), and each socket is
|
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;;;;;;;;;;GAUG;AACH,OAAO,EACL,aAAa,EACb,aAAa,
|
|
1
|
+
{"version":3,"file":"live-reads.js","sourceRoot":"","sources":["../src/live-reads.ts"],"names":[],"mappings":"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"}
|
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":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA8DnD,OAAO,EA2DL,KAAK,SAAS,EAsBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAkHtB,MAAM,sBAAsB,CAAC;AAoD9B,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAwBL,kBAAkB,
|
|
1
|
+
{"version":3,"file":"scope-do.d.ts","sourceRoot":"","sources":["../src/scope-do.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA8DnD,OAAO,EA2DL,KAAK,SAAS,EAsBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAkHtB,MAAM,sBAAsB,CAAC;AAoD9B,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAwBL,kBAAkB,EAgFnB,MAAM,sBAAsB,CAAC;AA0B9B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAoFD,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAwkB5E;;;GAGG;AACH,MAAM,MAAM,yBAAyB,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;AAmBtD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,CAOxD;AAED,gHAAgH;AAChH,OAAO,EAAE,kBAAkB,EAAE,CAAC;AA2B9B,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,CAAC,UAAU,CAAC,CA00O7E"}
|
package/dist/scope-do.js
CHANGED
|
@@ -3,11 +3,11 @@ import { SYSTEM_DOOR_MOVED } from './system-door.js';
|
|
|
3
3
|
import { DurableObject } from 'cloudflare:workers';
|
|
4
4
|
import { ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, domainEvent, domainEventInput, eventId, instant, objectRef, entityObjectRef, assertModuleEmittableType, assertKernelAuthoredType, toWireFailure, grantRefFromProof, principalId, principalBecomeCapabilityInput, 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, pageOf, countedPageOf, requestFingerprint, substratError, errorCodeOf, assertReplayableDump, REDRAIN_BATCH, } from '@substrat-run/contracts';
|
|
5
5
|
import { ulid, DO_SQL_LIMITS, unknownRoleError, createUlid, assertAllowed, ConnectionSealingKeyUnavailableError, noSealingKeyMessage, sealTo, assertReadOnlyQuery, entitlementDenial, platformRequestHistoryQuery, platformRequestOf, PLATFORM_REQUEST_COLUMNS, PLATFORM_REQUEST_REDACTION_SQL, platformRequestRedactionParams, platformRequestRedactionQuery, intentPayloadCarriesSubject, redactSubjectJobRuns, eraseSubjectFromModules, moduleErasurePlan, redactSubjectScopeText, assertRowLimit, assertRowOffset, JOB_RUN_PATCH_SQL, JOB_RUN_CLAIM_SQL, JOB_RUN_RENEW_SQL, JOB_RUN_BEGIN_SQL, JOB_RUN_MISS_SQL, JOB_RUN_MISS_SETTLE_SQL, admissionMissOutcome, JOB_LEASE_EXPIRED_NOTE, JOB_STEP_RECORD_SQL, DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, seatScopeTuple, delegatedRevokeSql, writeExplicitTupleIn, grantEntityShapeIn, topUpEntityGrantShapes, applyScopeRoleChange, changeScopeRole, revokeScopeRoles, scopeRoleHolders, effectiveRoleGrantQuery, switchRecordedOff, switchSystemSchedules, peerGrantsStatus, systemGrantsStatus, systemScheduleState, systemSwitchedOff, denialListQuery, refusalListQuery, mapRefusalRow, denialSummaryQuery, denialTotalsQuery, DENIAL_WINDOW_QUERY, mapDenialRow, mapDenialSummaryBuckets, PermissionDenied, assertImpersonationWrites, assertModuleEnqueueableKind, impersonationStampOf, createAtomic, NotSearchable, isSearchIndexTable, searchIndexPlans, NotListable, listIndexPlans, moduleMigrations, MIGRATION_DIGEST_FENCE_DDL, MIGRATION_DIGEST_MARK_LEGACY, assertJournalDumpCoherent, assertMigrationSql, migrationDivergence, migrationFailedError, migrationSetDivergence, migrationSteps, planMigrations, listQuery, cursorOf, searchLimit, searchMatchExpression, searchQuery, ATTACHMENT_TEXT_DDL, ATTACHMENT_CONDEMNED_DDL, ATTACHMENT_SWEEP_LICENCE_DDL, ATTACHMENT_SWEEP_LICENCE_TABLE, clearOrphanSweepLicence, condemnLicensedOrphanAttachments, consumeOrphanSweepLicence, licensedOrphanIds, recordOrphanSweepLicence, refuseUnlicensedOrphanSweep, refuseCondemnedAttachment, refuseCondemnedInDump, rowlessAttachmentIds, attachmentRecordOfRow, enqueueAttachmentText, reconcileAttachmentText, queueAttachmentTextBackfill, startAttachmentTextBackfill, recordAttachmentText, searchAttachments, IDEMPOTENCY_DDL, REFUSALS_TABLE_DDL, REFUSALS_INDEX, refusalInsert, refusalOf, markGuardRefusal, REFUSALS_REBUILD, refusalsAdmitGuards, 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, emptyImportResult, 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, JOB_RUN_DUE_AT, jobRunListLimit, SYSTEM_DOOR_WAIT, ancestorsWithin, } from '@substrat-run/kernel';
|
|
6
|
-
import { isUpgradeRequest, readSubscription, LIVE_DECIDE_ATTEMPTS, LIVE_FANOUT_LIMIT,
|
|
6
|
+
import { isUpgradeRequest, readSubscription, LIVE_DECIDE_ATTEMPTS, LIVE_FANOUT_LIMIT, LIVE_PRINCIPAL_HEADER, LIVE_SCOPE_HEADER, LIVE_SUBSCRIBE_PATH, LIVE_TENANT_HEADER, LIVE_WITHIN_HEADER, LIVE_EXPIRES_HEADER, LIVE_CLOSE, LIVE_SOCKETS_PER_PRINCIPAL, decodeLiveWithin, liveInstant, liveRefusal, liveRefusalStatus, } from './live-reads.js';
|
|
7
7
|
import { replyOf } from './do-reply.js';
|
|
8
8
|
import { OperationQueue } from './serialization.js';
|
|
9
9
|
import { assertNoWorkerdStorage, doScopedSql, doBuiltColumnsOf, doRedactionSql, doSpineSql } from './sql.js';
|
|
10
|
-
import { actorOf, admitPeer, boundToPeerDeclarations, collectPeers, switchPeer, peerSubjectRef, subjectGrantState, assertNoSecret, CAPABILITY_DDL, UPLOAD_LINK_DDL, createAttachmentVerbs, inspectUploadLink, redeemUploadLinkInTransaction, COPY_ORIGIN_DDL, ENTITY_STATE_MOVES_DDL, SWITCH_FENCES_DDL, TABLE_OWNERS_DDL, assertMigrationLeavesLedgerAlone, recordOwnershipSteps, runMigrationStatements, splitSqlStatements, executableSqlStatements, blankSqlComments, CAPABILITY_EXCHANGE_OPERATION, CAPABILITY_BECOME_MINT_OPERATION, becomeMintCheck, mintBecomeCapabilityAsPrincipal, revokeBecomeCapabilityAsPrincipal, readBecomeLinkStates, ENTITY_UNBIND_OPERATION, allowedFor, unbindEntityHolderBounded, capabilityAttachmentWriteRefused, createCapabilityVerbs, createEntityEdgeVerbs, createEntityStateVerbs, createTrashedReads, CONTINUATION_POSITION_CAP, visibleContinuation, searchStateWhere, uncheckedView, addStatePlans, addUpdatedStampPlans, watchUpdatedStamps, assertNoCallerPurge, isUnreachableParent, PURGE_BATCH, heldPurgePass, lifecycleRefusal, purgeHeldBy, purgeDueOf, purgeOnlyKeysOf, runPurgePass, refuseTrashedTarget, assertBoundOperations, registerTrashTargets, withheldKeysFor, statefulTablesOf, afterMigration, afterRuntimeDdl, derivesAnything, repairDerivedObjects, StateColumnLost, exchangeCapability, guardSecrets, mintBecomeCapability, redactSecrets, redactSecretText, moduleLog, asyncInvocationId, asyncLinePass, resolveCapabilitySession, revokeCapabilityAsPlatform, readCapabilityPage, domainEventOf, facetEvents, readDeadLetters, readLifecycleFlow, readOperationSeries, readHistory, readInvocation, readUndrainedOutbox, walkEventCause, walkEventEffects, } from '@substrat-run/kernel';
|
|
10
|
+
import { actorOf, admitPeer, boundToPeerDeclarations, collectPeers, switchPeer, peerSubjectRef, subjectGrantState, assertNoSecret, CAPABILITY_DDL, UPLOAD_LINK_DDL, createAttachmentVerbs, inspectUploadLink, redeemUploadLinkInTransaction, COPY_ORIGIN_DDL, ENTITY_STATE_MOVES_DDL, SWITCH_FENCES_DDL, TABLE_OWNERS_DDL, assertMigrationLeavesLedgerAlone, recordOwnershipSteps, runMigrationStatements, splitSqlStatements, executableSqlStatements, blankSqlComments, CAPABILITY_EXCHANGE_OPERATION, CAPABILITY_BECOME_MINT_OPERATION, becomeMintCheck, mintBecomeCapabilityAsPrincipal, revokeBecomeCapabilityAsPrincipal, readBecomeLinkStates, ENTITY_UNBIND_OPERATION, allowedFor, unbindEntityHolderBounded, capabilityAttachmentWriteRefused, createCapabilityVerbs, createEntityEdgeVerbs, createEntityStateVerbs, createTrashedReads, CONTINUATION_POSITION_CAP, visibleContinuation, searchStateWhere, uncheckedView, addStatePlans, addUpdatedStampPlans, watchUpdatedStamps, assertNoCallerPurge, isUnreachableParent, PURGE_BATCH, heldPurgePass, lifecycleRefusal, purgeHeldBy, purgeDueOf, purgeOnlyKeysOf, runPurgePass, refuseTrashedTarget, assertBoundOperations, checkHeldOperationsOf, countChecks, noteUncheckedCompletion, registerTrashTargets, withheldKeysFor, statefulTablesOf, afterMigration, afterRuntimeDdl, derivesAnything, repairDerivedObjects, StateColumnLost, exchangeCapability, guardSecrets, mintBecomeCapability, redactSecrets, redactSecretText, moduleLog, asyncInvocationId, asyncLinePass, resolveCapabilitySession, revokeCapabilityAsPlatform, readCapabilityPage, domainEventOf, facetEvents, readDeadLetters, readLifecycleFlow, readOperationSeries, readHistory, readInvocation, readUndrainedOutbox, walkEventCause, walkEventEffects, } from '@substrat-run/kernel';
|
|
11
11
|
import { COPY_RESTORE_FENCE_LAPSED, copyRestoreFenceLapsed, orphanSweepVersionRefusal } from '@substrat-run/kernel';
|
|
12
12
|
import { createDoTupleChecker, createLocalControlPlaneReader, scopeTupleReader } from './checker.js';
|
|
13
13
|
import { settlePlatformRequestIn } from '@substrat-run/kernel';
|
|
@@ -732,6 +732,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
732
732
|
purgeSchedules = new Map();
|
|
733
733
|
/** #116: the operations that declared `idempotency: false` — refusals, not participants. */
|
|
734
734
|
operationIdempotencyOptOut = new Set();
|
|
735
|
+
/** #2387: the operations held to a `ctx.check` — the pure adapter's set, from the same kernel read. */
|
|
736
|
+
operationCheckHeld = new Set();
|
|
735
737
|
modules = new Map();
|
|
736
738
|
/** #1705: what this deployment exports to other verticals and imports from them. */
|
|
737
739
|
crossVertical = new CrossVerticalRegistry();
|
|
@@ -857,6 +859,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
857
859
|
// -- module registration (port of SqliteScopeHost.registerModule) ---------
|
|
858
860
|
registerModule(registration) {
|
|
859
861
|
const manifest = registration.manifest;
|
|
862
|
+
// #2412: one id, one registration — the refusal the coordinator and the pure host make, so a
|
|
863
|
+
// module list they would turn away cannot start here.
|
|
864
|
+
if (this.modules.has(manifest.id)) {
|
|
865
|
+
throw new Error(`module already registered: ${manifest.id}`);
|
|
866
|
+
}
|
|
860
867
|
// #1835: the binder's own value, or nothing registers — as in the pure adapter.
|
|
861
868
|
assertBoundOperations(manifest.id, registration.operations);
|
|
862
869
|
// #119: refused before anything is recorded, as in the pure adapter.
|
|
@@ -958,14 +965,20 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
958
965
|
}
|
|
959
966
|
this.liveTargets.set(target.entityType, target.readPermission);
|
|
960
967
|
}
|
|
968
|
+
// #2412: a module's own handler must not be silently unbound by its own manifest. The check
|
|
969
|
+
// sits inside the loop, so names earlier in the list are already deleted when it throws —
|
|
970
|
+
// as on the other two hosts, and harmless because the constructor throw discards the instance.
|
|
971
|
+
const ownOps = new Set(Object.keys(registration.operations?.handlers ?? {}));
|
|
961
972
|
for (const name of manifest.withdraws ?? []) {
|
|
973
|
+
if (ownOps.has(name)) {
|
|
974
|
+
throw new Error(`${manifest.id} withdraws its own operation: ${name} (a module cannot withdraw itself — just don't register it)`);
|
|
975
|
+
}
|
|
962
976
|
this.withdrawn.set(name, manifest.id);
|
|
963
977
|
this.operations.delete(name);
|
|
964
978
|
}
|
|
965
979
|
// #893: a schema declared for an operation this module does not bind
|
|
966
980
|
// enforces nothing while reading as coverage — refused, as in the pure adapter.
|
|
967
981
|
const declaredInputs = registration.operations?.inputs ?? {};
|
|
968
|
-
const ownOps = new Set(Object.keys(registration.operations?.handlers ?? {}));
|
|
969
982
|
const unbound = Object.keys(declaredInputs).filter((name) => !ownOps.has(name));
|
|
970
983
|
if (unbound.length > 0) {
|
|
971
984
|
throw new Error(`${manifest.id} declares operations.inputs for unbound operation(s): ` +
|
|
@@ -988,8 +1001,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
988
1001
|
`${[...unboundOptOuts].sort().join(', ')} — an opt-out on nothing reads as an ` +
|
|
989
1002
|
'exclusion someone decided, of an operation that does not exist');
|
|
990
1003
|
}
|
|
1004
|
+
const checkHeld = checkHeldOperationsOf(registration.operations);
|
|
991
1005
|
for (const [name, handler] of Object.entries(registration.operations?.handlers ?? {})) {
|
|
992
1006
|
this.defineOperation(name, handler);
|
|
1007
|
+
if (checkHeld.has(name) && this.operations.has(name))
|
|
1008
|
+
this.operationCheckHeld.add(name);
|
|
993
1009
|
// The schema follows the HANDLER, not the name: a withdrawn operation
|
|
994
1010
|
// never binds, and has nothing to parse for.
|
|
995
1011
|
const schema = declaredInputs[name];
|
|
@@ -1009,6 +1025,10 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
1009
1025
|
defineOperation(name, handler) {
|
|
1010
1026
|
if (this.withdrawn.has(name))
|
|
1011
1027
|
return; // withdrawn by another manifest — never binds
|
|
1028
|
+
// The coordinator and the pure host refuse a repeat the same way (`bindOperation`): a second
|
|
1029
|
+
// registration would otherwise replace the first without a word.
|
|
1030
|
+
if (this.operations.has(name))
|
|
1031
|
+
throw new Error(`operation already defined: ${name}`);
|
|
1012
1032
|
this.operations.set(name, handler);
|
|
1013
1033
|
}
|
|
1014
1034
|
// -- RPC surface ----------------------------------------------------------
|
|
@@ -2060,7 +2080,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2060
2080
|
? withheldKeysFor(this.purgeOnlyKeys.get(systemDoor.moduleId), target, purging)
|
|
2061
2081
|
: undefined;
|
|
2062
2082
|
await this.revision.transaction(async () => {
|
|
2063
|
-
const
|
|
2083
|
+
const checks = { calls: 0 };
|
|
2084
|
+
const ctx = this.operationContext(principal, tenantId, scopeId, undefined, connectionId, systemDoor, signals, impersonation, operation, capabilityId, minted, undefined, peerSubject, undefined, withheld, checks);
|
|
2064
2085
|
// #116: a retry is answered from the recording, and nothing else runs
|
|
2065
2086
|
// — not the guards, not the handler, not the permission check inside
|
|
2066
2087
|
// it. Keyed by SUBJECT, so a caller only ever reaches its own
|
|
@@ -2093,7 +2114,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2093
2114
|
const stamps = watchUpdatedStamps(doSpineSql(this.sql), this.updatedStampPlans);
|
|
2094
2115
|
await refuseTrashedTarget({ sql: doSpineSql(this.sql), plans: this.statePlans, check: ctx.check, now: ctx.now() }, operation, target, parsed, purging ? { gate: this.purgeGateFacts(systemDoor.moduleId, tenantId) } : undefined);
|
|
2095
2116
|
await this.runGuards(operation, ctx, parsed);
|
|
2117
|
+
// #2387: the handler's own checks only — the pure adapter's reset, for its reason.
|
|
2118
|
+
checks.calls = 0;
|
|
2096
2119
|
result = await handler(ctx, parsed);
|
|
2120
|
+
// #2387: the pure adapter's record, through the same kernel function.
|
|
2121
|
+
noteUncheckedCompletion(ctx, operation, checks, this.operationCheckHeld.has(operation));
|
|
2097
2122
|
stamps?.assertHeld(ctx, operation);
|
|
2098
2123
|
if (guardedRef && invokeOptions?.ifMatch !== undefined) {
|
|
2099
2124
|
assertIfMatch(guardedRef, invokeOptions.ifMatch, seen ?? null);
|
|
@@ -2261,13 +2286,10 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2261
2286
|
if (url.pathname !== LIVE_SUBSCRIBE_PATH) {
|
|
2262
2287
|
// The DO has exactly one fetch surface. Anything else reaching here is a
|
|
2263
2288
|
// coordinator bug, and a 404 says so without guessing at an intent.
|
|
2264
|
-
return
|
|
2289
|
+
return liveRefusalStatus(404, 'this scope has no such surface');
|
|
2265
2290
|
}
|
|
2266
2291
|
if (!isUpgradeRequest(request)) {
|
|
2267
|
-
return
|
|
2268
|
-
status: 426,
|
|
2269
|
-
headers: { [LIVE_MODE_HEADER]: 'not-an-upgrade' },
|
|
2270
|
-
});
|
|
2292
|
+
return liveRefusalStatus(426, 'live reads are a WebSocket surface', 'not-an-upgrade');
|
|
2271
2293
|
}
|
|
2272
2294
|
const principal = request.headers.get(LIVE_PRINCIPAL_HEADER);
|
|
2273
2295
|
const tenantId = request.headers.get(LIVE_TENANT_HEADER);
|
|
@@ -2277,9 +2299,7 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2277
2299
|
// cannot be evaluated, and the only safe thing to do with a channel we cannot
|
|
2278
2300
|
// filter is to refuse to open it. 500, not 400: the caller is the coordinator
|
|
2279
2301
|
// in this same package, so a missing assertion is OUR bug, not the client's.
|
|
2280
|
-
return
|
|
2281
|
-
status: 500,
|
|
2282
|
-
});
|
|
2302
|
+
return liveRefusal('internal', 'live reads require an asserted principal, tenant and scope');
|
|
2283
2303
|
}
|
|
2284
2304
|
// A narrowing the coordinator sent but this end cannot read is refused, never
|
|
2285
2305
|
// dropped: dropping it would open the whole scope's feed — to a vouched
|
|
@@ -2287,13 +2307,13 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2287
2307
|
const withinHeader = request.headers.get(LIVE_WITHIN_HEADER);
|
|
2288
2308
|
const within = withinHeader === null ? undefined : decodeLiveWithin(withinHeader);
|
|
2289
2309
|
if (withinHeader !== null && !within) {
|
|
2290
|
-
return
|
|
2310
|
+
return liveRefusal('internal', 'live reads: unreadable within narrowing');
|
|
2291
2311
|
}
|
|
2292
2312
|
// The same for an expiry: dropping it would keep the socket open past its session.
|
|
2293
2313
|
const expiresHeader = request.headers.get(LIVE_EXPIRES_HEADER);
|
|
2294
2314
|
const expiresAt = expiresHeader === null ? undefined : liveInstant(expiresHeader);
|
|
2295
2315
|
if (expiresHeader !== null && !expiresAt) {
|
|
2296
|
-
return
|
|
2316
|
+
return liveRefusal('internal', 'live reads: unreadable expiry');
|
|
2297
2317
|
}
|
|
2298
2318
|
// A subscriber arriving before the scope's migrations have run would be told
|
|
2299
2319
|
// about events against a schema it cannot read back through. Same gate every
|
|
@@ -2317,10 +2337,7 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2317
2337
|
const expired = expiresAt !== undefined && expiresAt <= new Date().toISOString();
|
|
2318
2338
|
if (expired ||
|
|
2319
2339
|
(within?.checked !== undefined && !(await this.mayWatchRoot(() => this.liveContext(subscriber), within)))) {
|
|
2320
|
-
return
|
|
2321
|
-
status: 403,
|
|
2322
|
-
headers: { [LIVE_MODE_HEADER]: 'forbidden' },
|
|
2323
|
-
});
|
|
2340
|
+
return liveRefusal('forbidden', 'live reads: the subscriber may not watch this root', 'forbidden');
|
|
2324
2341
|
}
|
|
2325
2342
|
const pair = new WebSocketPair();
|
|
2326
2343
|
const [client, server] = Object.values(pair);
|
|
@@ -5923,7 +5940,9 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
5923
5940
|
/** #2055: the delivery a consumer's or an import's context runs for; absent otherwise. */
|
|
5924
5941
|
delivery,
|
|
5925
5942
|
/** #119: keys this context's checks refuse whatever the subject holds (`purgeOnlyKeysOf`). */
|
|
5926
|
-
withheld
|
|
5943
|
+
withheld,
|
|
5944
|
+
/** #2387: where this invocation's checks are counted; absent where nothing reads the count. */
|
|
5945
|
+
checks) {
|
|
5927
5946
|
const checker = this.checker;
|
|
5928
5947
|
const relations = this.relations;
|
|
5929
5948
|
const searchPlans = this.searchPlans;
|
|
@@ -5980,7 +5999,7 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
5980
5999
|
// Lifted so `grant` reuses the SAME check the operation itself passes —
|
|
5981
6000
|
// a delegation check that could differ from the operation's would be a
|
|
5982
6001
|
// second opinion about what the caller holds.
|
|
5983
|
-
const
|
|
6002
|
+
const decideUncounted = async (unparsed, entity) => {
|
|
5984
6003
|
// #1642: parsed before the system actor's early return, which never reaches
|
|
5985
6004
|
// the checker — a cast key would otherwise become that path's proof relation.
|
|
5986
6005
|
const permission = assertPermissionKey(unparsed);
|
|
@@ -6009,6 +6028,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
6009
6028
|
}
|
|
6010
6029
|
return decision;
|
|
6011
6030
|
};
|
|
6031
|
+
// #2387: every check this context makes is counted, the kernel's own verbs' included.
|
|
6032
|
+
const runCheck = checks ? countChecks(decideUncounted, checks) : decideUncounted;
|
|
6012
6033
|
const runCanAssign = async (roleKey) => {
|
|
6013
6034
|
const bound = await this.assignmentBound(subject, tenantId, scopeId, roleKey);
|
|
6014
6035
|
if (!bound) {
|