@substrat-run/adapter-cloudflare 0.130.1 → 0.131.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.
@@ -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,EAcL,KAAK,WAAW,EAqCjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAmCL,KAAK,SAAS,EAmBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAuEtB,MAAM,sBAAsB,CAAC;AAsF9B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAwbD;;;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,CAi/JjE"}
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,EAcL,KAAK,WAAW,EAsCjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAoCL,KAAK,SAAS,EAmBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAuEtB,MAAM,sBAAsB,CAAC;AAsF9B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAwbD;;;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,CAkkKjE"}
package/dist/scope-do.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { REWIND_REFUSED } from './rewind-refusal.js';
2
2
  import { DurableObject } from 'cloudflare:workers';
3
3
  import { ATTACHMENT_ADDED, ATTACHMENT_REMOVED, attachmentRecord, domainEvent, domainEventInput, eventId, instant, objectRef, entityObjectRef, assertModuleEmittableType, assertKernelAuthoredType, 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
- 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, REFUSALS_DDL, refusalInsert, refusedTransitionOf, 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';
4
+ 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, 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, REFUSALS_DDL, refusalInsert, refusedTransitionOf, 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';
7
7
  import { doScopedSql, doBuiltColumnsOf, doSpineSql } from './sql.js';
@@ -2201,6 +2201,28 @@ export function defineScopeDO(modules, bareOps) {
2201
2201
  }
2202
2202
  return record;
2203
2203
  }
2204
+ /** Authorize a job's read as its registered module, never as a person. */
2205
+ async systemAttachmentAuthorize(attachmentId, moduleId, tenantId, scopeId) {
2206
+ await this.ensureMigrations();
2207
+ if (!this.modules.has(moduleId)) {
2208
+ throw toRpcError(substratError('not_found', `module not registered in this scope: ${moduleId}`));
2209
+ }
2210
+ const record = this.attachmentRow(attachmentId);
2211
+ if (!record)
2212
+ return null;
2213
+ const gate = this.attachmentGate(record.entity.entityType);
2214
+ try {
2215
+ const ctx = this.operationContext(this.systemPrincipal, tenantId, scopeId, undefined, undefined, moduleId, undefined, undefined, 'attachments.open');
2216
+ assertAllowed(await ctx.check(gate.read, record.entity));
2217
+ }
2218
+ catch (err) {
2219
+ if (err instanceof PermissionDenied) {
2220
+ this.recordDenial({ kind: 'system', id: moduleId }, tenantId, 'attachments.open', err, null);
2221
+ }
2222
+ throw toRpcError(err);
2223
+ }
2224
+ return record;
2225
+ }
2204
2226
  /** Remove an attachment's metadata fact: write gate + delete + `attachment.removed`. */
2205
2227
  async attachmentRemove(attachmentId, principal, tenantId, scopeId, connectionId) {
2206
2228
  await this.ensureMigrations();
@@ -2402,6 +2424,40 @@ export function defineScopeDO(modules, bareOps) {
2402
2424
  return permissions.map((permission) => ({ permission, held: !missing.has(permission) }));
2403
2425
  });
2404
2426
  }
2427
+ /**
2428
+ * `ctx.canAssign`'s bound for a principal the host names (#1931), queued like `peerCovers`
2429
+ * so no invoke's open transaction is read half-done. `null` when the tenant defines no such
2430
+ * role: a typed error thrown here would reach the host flattened, so the host types it.
2431
+ */
2432
+ async canAssignFor(tenantId, scopeId, principal, roleKey) {
2433
+ await this.ensureMigrations();
2434
+ return this.queue.enqueue(() => this.assignmentBound({ kind: 'principal', id: principal }, tenantId, scopeId, roleKey));
2435
+ }
2436
+ /** Check and grant in one serialized scope task; a refusal never writes a tuple. */
2437
+ async assignScopeRoleBoundedFor(tenantId, scopeId, caller, assignee, roleKey) {
2438
+ await this.ensureMigrations();
2439
+ return this.queue.enqueue(async () => {
2440
+ const bound = await this.assignmentBound({ kind: 'principal', id: caller }, tenantId, scopeId, roleKey);
2441
+ if (bound?.covered) {
2442
+ this.sql.exec(`INSERT OR REPLACE INTO _substrat_tuples (subject, relation, object, expires_at)
2443
+ VALUES (?, ?, ?, NULL)`, `principal:${assignee}`, `role:${roleKey}`, `scope:${scopeId}`);
2444
+ }
2445
+ return bound;
2446
+ });
2447
+ }
2448
+ /**
2449
+ * §5.1's assignment bound, resolved against the SAME role table the checker
2450
+ * expands — the tenant's projected role, not a vertical's compile-time `ROLES`
2451
+ * array, because the projected role is what assignment would actually confer.
2452
+ * The one resolution both `ctx.canAssign` and `canAssignFor` answer from; `null`
2453
+ * when the tenant defines no such role.
2454
+ */
2455
+ async assignmentBound(subject, tenantId, scopeId, roleKey) {
2456
+ const role = await this.controlPlaneReader().getRole(tenantId, roleKey);
2457
+ if (!role)
2458
+ return null;
2459
+ return this.checker.covers(subject, role.permissions, { tenantId, scopeId });
2460
+ }
2405
2461
  /**
2406
2462
  * Every module this scope holds or has held system authority for, and where each
2407
2463
  * stands (#1674) — the kernel's `systemGrantsStatus`, over this DO's own storage. A
@@ -3991,17 +4047,12 @@ export function defineScopeDO(modules, bareOps) {
3991
4047
  }
3992
4048
  return decision;
3993
4049
  };
3994
- /**
3995
- * §5.1's assignment bound, resolved against the SAME role table the checker
3996
- * expands — the tenant's projected role, not a vertical's compile-time `ROLES`
3997
- * array, because the projected role is what assignment would actually confer.
3998
- */
3999
4050
  const runCanAssign = async (roleKey) => {
4000
- const role = await this.controlPlaneReader().getRole(tenantId, roleKey);
4001
- if (!role) {
4002
- throw substratError('not_found', `no such role in this tenant: ${roleKey}`);
4051
+ const bound = await this.assignmentBound(subject, tenantId, scopeId, roleKey);
4052
+ if (!bound) {
4053
+ throw unknownRoleError(roleKey);
4003
4054
  }
4004
- return checker.covers(subject, role.permissions, { tenantId, scopeId });
4055
+ return bound;
4005
4056
  };
4006
4057
  // ctx.emit's writer, and the kernel's own events' (#1864): one path to the outbox, with the
4007
4058
  // reserved-type refusal applied to module code only. Never handed to module code as-is.