@substrat-run/adapter-cloudflare 0.149.0 → 0.151.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 +8 -0
- package/dist/host.js.map +1 -1
- package/dist/scope-do.d.ts.map +1 -1
- package/dist/scope-do.js +68 -8
- package/dist/scope-do.js.map +1 -1
- package/package.json +12 -12
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,
|
|
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,CAq0O7E"}
|
package/dist/scope-do.js
CHANGED
|
@@ -2,12 +2,12 @@ import { REWIND_REFUSED } from './rewind-refusal.js';
|
|
|
2
2
|
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
|
-
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,
|
|
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
6
|
import { isUpgradeRequest, readSubscription, LIVE_DECIDE_ATTEMPTS, LIVE_FANOUT_LIMIT, LIVE_MODE_HEADER, 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, } 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';
|
|
@@ -355,6 +355,9 @@ const KERNEL_DDL = `
|
|
|
355
355
|
-- #2314: the orphan sweep's tombstones, shared from @substrat-run/kernel. An id here
|
|
356
356
|
-- never takes an attachment row again: the insert path refuses it.
|
|
357
357
|
${ATTACHMENT_CONDEMNED_DDL}
|
|
358
|
+
-- #2350: the orphan sweep's dry-run licence, shared from @substrat-run/kernel. Store-local:
|
|
359
|
+
-- never dumped, and every load drops it.
|
|
360
|
+
${ATTACHMENT_SWEEP_LICENCE_DDL}
|
|
358
361
|
-- #901: an entity's version is the ULID of the last event about it (a state move
|
|
359
362
|
-- excepted, #2191), so the newest id per (entity_type, entity_id) is the read. The id
|
|
360
363
|
-- column sits last so SQLite walks the matched range backwards instead of aggregating.
|
|
@@ -729,6 +732,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
729
732
|
purgeSchedules = new Map();
|
|
730
733
|
/** #116: the operations that declared `idempotency: false` — refusals, not participants. */
|
|
731
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();
|
|
732
737
|
modules = new Map();
|
|
733
738
|
/** #1705: what this deployment exports to other verticals and imports from them. */
|
|
734
739
|
crossVertical = new CrossVerticalRegistry();
|
|
@@ -985,8 +990,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
985
990
|
`${[...unboundOptOuts].sort().join(', ')} — an opt-out on nothing reads as an ` +
|
|
986
991
|
'exclusion someone decided, of an operation that does not exist');
|
|
987
992
|
}
|
|
993
|
+
const checkHeld = checkHeldOperationsOf(registration.operations);
|
|
988
994
|
for (const [name, handler] of Object.entries(registration.operations?.handlers ?? {})) {
|
|
989
995
|
this.defineOperation(name, handler);
|
|
996
|
+
if (checkHeld.has(name) && this.operations.has(name))
|
|
997
|
+
this.operationCheckHeld.add(name);
|
|
990
998
|
// The schema follows the HANDLER, not the name: a withdrawn operation
|
|
991
999
|
// never binds, and has nothing to parse for.
|
|
992
1000
|
const schema = declaredInputs[name];
|
|
@@ -1006,6 +1014,10 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
1006
1014
|
defineOperation(name, handler) {
|
|
1007
1015
|
if (this.withdrawn.has(name))
|
|
1008
1016
|
return; // withdrawn by another manifest — never binds
|
|
1017
|
+
// The coordinator and the pure host refuse a repeat the same way (`bindOperation`): a second
|
|
1018
|
+
// registration would otherwise replace the first without a word.
|
|
1019
|
+
if (this.operations.has(name))
|
|
1020
|
+
throw new Error(`operation already defined: ${name}`);
|
|
1009
1021
|
this.operations.set(name, handler);
|
|
1010
1022
|
}
|
|
1011
1023
|
// -- RPC surface ----------------------------------------------------------
|
|
@@ -2057,7 +2069,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2057
2069
|
? withheldKeysFor(this.purgeOnlyKeys.get(systemDoor.moduleId), target, purging)
|
|
2058
2070
|
: undefined;
|
|
2059
2071
|
await this.revision.transaction(async () => {
|
|
2060
|
-
const
|
|
2072
|
+
const checks = { calls: 0 };
|
|
2073
|
+
const ctx = this.operationContext(principal, tenantId, scopeId, undefined, connectionId, systemDoor, signals, impersonation, operation, capabilityId, minted, undefined, peerSubject, undefined, withheld, checks);
|
|
2061
2074
|
// #116: a retry is answered from the recording, and nothing else runs
|
|
2062
2075
|
// — not the guards, not the handler, not the permission check inside
|
|
2063
2076
|
// it. Keyed by SUBJECT, so a caller only ever reaches its own
|
|
@@ -2090,7 +2103,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2090
2103
|
const stamps = watchUpdatedStamps(doSpineSql(this.sql), this.updatedStampPlans);
|
|
2091
2104
|
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);
|
|
2092
2105
|
await this.runGuards(operation, ctx, parsed);
|
|
2106
|
+
// #2387: the handler's own checks only — the pure adapter's reset, for its reason.
|
|
2107
|
+
checks.calls = 0;
|
|
2093
2108
|
result = await handler(ctx, parsed);
|
|
2109
|
+
// #2387: the pure adapter's record, through the same kernel function.
|
|
2110
|
+
noteUncheckedCompletion(ctx, operation, checks, this.operationCheckHeld.has(operation));
|
|
2094
2111
|
stamps?.assertHeld(ctx, operation);
|
|
2095
2112
|
if (guardedRef && invokeOptions?.ifMatch !== undefined) {
|
|
2096
2113
|
assertIfMatch(guardedRef, invokeOptions.ifMatch, seen ?? null);
|
|
@@ -2887,14 +2904,46 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2887
2904
|
throw misrouted;
|
|
2888
2905
|
await this.refuseOrphanJudgement(tenantId, vouched);
|
|
2889
2906
|
// The verdict alone (no ids, the host's first call) changes nothing: no migration, no repair.
|
|
2890
|
-
|
|
2907
|
+
// A destructive pass's verdict also asks for this store's own dry-run licence (#2350), so a
|
|
2908
|
+
// pass with nothing to condemn is refused all the same.
|
|
2909
|
+
if (ids.length === 0) {
|
|
2910
|
+
if (condemn)
|
|
2911
|
+
await this.queue.enqueue(async () => refuseUnlicensedOrphanSweep(doSpineSql(this.sql), now));
|
|
2891
2912
|
return [];
|
|
2913
|
+
}
|
|
2892
2914
|
await this.ensureMigrations();
|
|
2893
2915
|
return this.queue.enqueue(async () => {
|
|
2894
2916
|
await this.refuseOrphanJudgement(tenantId, vouched);
|
|
2895
2917
|
if (!condemn)
|
|
2896
2918
|
return rowlessAttachmentIds(doSpineSql(this.sql), ids);
|
|
2897
|
-
return this.revision.transaction(async () =>
|
|
2919
|
+
return this.revision.transaction(async () => condemnLicensedOrphanAttachments(doSpineSql(this.sql), ids, now));
|
|
2920
|
+
});
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
/**
|
|
2924
|
+
* #2350: the licence half of a pass, behind the same refusals as the judgement. `record` keeps
|
|
2925
|
+
* what a dry run listed as this store's licence; `read` answers the ids it lists; `consume` takes
|
|
2926
|
+
* ids out of it (what a destructive pass deleted, and what is gone some other way). Each write
|
|
2927
|
+
* happens only when it changes the licence, so a dry run that keeps finding the same orphans
|
|
2928
|
+
* leaves the write revision where it was. Only `read` answers ids; the others answer none.
|
|
2929
|
+
*/
|
|
2930
|
+
orphanSweepLicenceReply(op, ids, now, tenantId, vouched = false, expectedVersionId) {
|
|
2931
|
+
return replyOf(async () => {
|
|
2932
|
+
const misrouted = orphanSweepVersionRefusal(this.env.SUBSTRAT_VERSION_ID ?? null, expectedVersionId, op !== 'record');
|
|
2933
|
+
if (misrouted)
|
|
2934
|
+
throw misrouted;
|
|
2935
|
+
await this.ensureMigrations();
|
|
2936
|
+
return this.queue.enqueue(async () => {
|
|
2937
|
+
await this.refuseOrphanJudgement(tenantId, vouched);
|
|
2938
|
+
if (op === 'read')
|
|
2939
|
+
return licensedOrphanIds(doSpineSql(this.sql));
|
|
2940
|
+
await this.revision.transaction(async () => {
|
|
2941
|
+
if (op === 'record')
|
|
2942
|
+
recordOrphanSweepLicence(doSpineSql(this.sql), ids, now);
|
|
2943
|
+
else
|
|
2944
|
+
consumeOrphanSweepLicence(doSpineSql(this.sql), ids);
|
|
2945
|
+
});
|
|
2946
|
+
return [];
|
|
2898
2947
|
});
|
|
2899
2948
|
});
|
|
2900
2949
|
}
|
|
@@ -4907,7 +4956,10 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
4907
4956
|
// in a dump (`exportDumpStamped` hands the stamp over beside one); every load writes its own.
|
|
4908
4957
|
const cursor = name === '_substrat_meta'
|
|
4909
4958
|
? this.sql.exec(`SELECT * FROM "${name}" WHERE key NOT IN (${STORE_LOCAL_META_KEYS.map(() => '?').join(', ')})`, ...STORE_LOCAL_META_KEYS)
|
|
4910
|
-
: this
|
|
4959
|
+
: // #2350: the orphan sweep's licence is this store's own, so its rows never leave in a dump.
|
|
4960
|
+
name === ATTACHMENT_SWEEP_LICENCE_TABLE
|
|
4961
|
+
? this.sql.exec(`SELECT * FROM "${name}" WHERE 0`)
|
|
4962
|
+
: this.sql.exec(`SELECT * FROM "${name}"`);
|
|
4911
4963
|
const columns = cursor.columnNames;
|
|
4912
4964
|
const rows = Array.from(cursor.raw(), (row) => row);
|
|
4913
4965
|
return { name, ddl: sql, columns, rows };
|
|
@@ -5270,6 +5322,10 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
5270
5322
|
// from before a suspension does not lift it; a copy keeps only its own.
|
|
5271
5323
|
settleLifecycleAfterLoad(this.switchSql(), lifecycleBefore, markCopy === true || isCopyLoad(destScopeId, sourceScopeId));
|
|
5272
5324
|
reconcileAttachmentText(doSpineSql(this.sql), ulid, now);
|
|
5325
|
+
// #2350: the orphan sweep's licence describes this store's last dry run, never the dump's.
|
|
5326
|
+
// A dump does not carry it; a hand-made one that does is dropped here all the same, so a
|
|
5327
|
+
// loaded store's next pass is a dry run.
|
|
5328
|
+
clearOrphanSweepLicence(doSpineSql(this.sql));
|
|
5273
5329
|
// Re-point the restored grants at THIS scope (after the spine exists, so a dump
|
|
5274
5330
|
// that carried no tuples table still finds one here).
|
|
5275
5331
|
if (destScopeId) {
|
|
@@ -5881,7 +5937,9 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
5881
5937
|
/** #2055: the delivery a consumer's or an import's context runs for; absent otherwise. */
|
|
5882
5938
|
delivery,
|
|
5883
5939
|
/** #119: keys this context's checks refuse whatever the subject holds (`purgeOnlyKeysOf`). */
|
|
5884
|
-
withheld
|
|
5940
|
+
withheld,
|
|
5941
|
+
/** #2387: where this invocation's checks are counted; absent where nothing reads the count. */
|
|
5942
|
+
checks) {
|
|
5885
5943
|
const checker = this.checker;
|
|
5886
5944
|
const relations = this.relations;
|
|
5887
5945
|
const searchPlans = this.searchPlans;
|
|
@@ -5938,7 +5996,7 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
5938
5996
|
// Lifted so `grant` reuses the SAME check the operation itself passes —
|
|
5939
5997
|
// a delegation check that could differ from the operation's would be a
|
|
5940
5998
|
// second opinion about what the caller holds.
|
|
5941
|
-
const
|
|
5999
|
+
const decideUncounted = async (unparsed, entity) => {
|
|
5942
6000
|
// #1642: parsed before the system actor's early return, which never reaches
|
|
5943
6001
|
// the checker — a cast key would otherwise become that path's proof relation.
|
|
5944
6002
|
const permission = assertPermissionKey(unparsed);
|
|
@@ -5967,6 +6025,8 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
5967
6025
|
}
|
|
5968
6026
|
return decision;
|
|
5969
6027
|
};
|
|
6028
|
+
// #2387: every check this context makes is counted, the kernel's own verbs' included.
|
|
6029
|
+
const runCheck = checks ? countChecks(decideUncounted, checks) : decideUncounted;
|
|
5970
6030
|
const runCanAssign = async (roleKey) => {
|
|
5971
6031
|
const bound = await this.assignmentBound(subject, tenantId, scopeId, roleKey);
|
|
5972
6032
|
if (!bound) {
|