@substrat-run/adapter-cloudflare 0.133.0 → 0.134.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 +9 -1
- package/dist/control-plane-do.d.ts.map +1 -1
- package/dist/control-plane-do.js +52 -12
- package/dist/control-plane-do.js.map +1 -1
- package/dist/host.d.ts +17 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +73 -17
- package/dist/host.js.map +1 -1
- package/dist/scope-do.d.ts.map +1 -1
- package/dist/scope-do.js +70 -18
- package/dist/scope-do.js.map +1 -1
- package/dist/sql.d.ts +3 -1
- package/dist/sql.d.ts.map +1 -1
- package/dist/sql.js +4 -0
- package/dist/sql.js.map +1 -1
- package/package.json +8 -7
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,EAcL,KAAK,WAAW,EAsCjB,MAAM,yBAAyB,CAAC;AACjC,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,EAcL,KAAK,WAAW,EAsCjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAuCL,KAAK,SAAS,EAmBd,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EA+EtB,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;AA6bD;;;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,CAupKjE"}
|
package/dist/scope-do.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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, 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';
|
|
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, redactSubjectScopeText, assertRowLimit, assertRowOffset, 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, ATTACHMENT_TEXT_DDL, attachmentRecordOfRow, enqueueAttachmentText, reconcileAttachmentText, recordAttachmentText, searchAttachments, 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
|
-
import { doScopedSql, doBuiltColumnsOf, doSpineSql } from './sql.js';
|
|
7
|
+
import { doScopedSql, doBuiltColumnsOf, doRedactionSql, doSpineSql } from './sql.js';
|
|
8
8
|
import { actorOf, admitPeer, collectPeers, switchPeer, assertNoSecret, CAPABILITY_DDL, CAPABILITY_EXCHANGE_OPERATION, capabilityAttachmentWriteRefused, createCapabilityVerbs, createEntityEdgeVerbs, exchangeCapability, guardSecrets, mintBecomeCapability, redactSecrets, redactSecretText, moduleLog, resolveCapabilitySession, revokeCapabilityAsPlatform, domainEventOf, facetEvents, readDeadLetters, readLifecycleFlow, readHistory, readInvocation, readUndrainedOutbox, walkEventCause, walkEventEffects, } from '@substrat-run/kernel';
|
|
9
9
|
import { createDoTupleChecker, createLocalControlPlaneReader } from './checker.js';
|
|
10
10
|
import { assertNoSpineReference, assertSpineTablesBuilt, dumpRowsInsert, isSpineTable, repointScopeGrants, spineColumnAdditions } from '@substrat-run/kernel';
|
|
@@ -312,6 +312,9 @@ const KERNEL_DDL = `
|
|
|
312
312
|
);
|
|
313
313
|
CREATE INDEX IF NOT EXISTS _substrat_attachments_entity
|
|
314
314
|
ON _substrat_attachments (entity_type, entity_id);
|
|
315
|
+
-- #1575: attachment text and its FTS5 index, shared from @substrat-run/kernel. After
|
|
316
|
+
-- _substrat_attachments, whose delete trigger it adds.
|
|
317
|
+
${ATTACHMENT_TEXT_DDL}
|
|
315
318
|
-- #901: an entity's version is the ULID of the last event about it, so
|
|
316
319
|
-- MAX(id) per (entity_type, entity_id) is the read. The id column sits last so
|
|
317
320
|
-- SQLite walks to the end of the matched range instead of aggregating over it.
|
|
@@ -2089,19 +2092,7 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2089
2092
|
const row = this.sql
|
|
2090
2093
|
.exec('SELECT * FROM _substrat_attachments WHERE id = ?', attachmentId)
|
|
2091
2094
|
.toArray()[0];
|
|
2092
|
-
|
|
2093
|
-
return null;
|
|
2094
|
-
return attachmentRecord.parse({
|
|
2095
|
-
id: row.id,
|
|
2096
|
-
entity: { entityType: row.entity_type, entityId: row.entity_id },
|
|
2097
|
-
filename: row.filename,
|
|
2098
|
-
contentType: row.content_type,
|
|
2099
|
-
size: Number(row.size),
|
|
2100
|
-
sha256: row.sha256,
|
|
2101
|
-
visibility: row.visibility,
|
|
2102
|
-
createdBy: row.created_by,
|
|
2103
|
-
createdAt: row.created_at,
|
|
2104
|
-
});
|
|
2095
|
+
return row ? attachmentRecordOfRow(row) : null;
|
|
2105
2096
|
}
|
|
2106
2097
|
/** Record an uploaded attachment: write gate + row + `attachment.added`, one txn. */
|
|
2107
2098
|
async attachmentAdd(record, principal, tenantId, scopeId,
|
|
@@ -2131,6 +2122,9 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2131
2122
|
piiClass: 'none',
|
|
2132
2123
|
payload: { attachment: parsed },
|
|
2133
2124
|
});
|
|
2125
|
+
// #1575: queue its text extraction in the same transaction — a `pending` row
|
|
2126
|
+
// and a job run. Nothing is extracted here, so nothing here can fail the upload.
|
|
2127
|
+
enqueueAttachmentText(doSpineSql(this.sql), parsed.id, ulid(), new Date().toISOString());
|
|
2134
2128
|
});
|
|
2135
2129
|
}
|
|
2136
2130
|
catch (err) {
|
|
@@ -2263,6 +2257,49 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2263
2257
|
return record;
|
|
2264
2258
|
});
|
|
2265
2259
|
}
|
|
2260
|
+
// -- attachment text (#1575) ---------------------------------------------------
|
|
2261
|
+
/**
|
|
2262
|
+
* Extracted-text search as `ctx`'s subject: authorized first — the check `open` makes,
|
|
2263
|
+
* the target's read key on the owning entity — then matched over readable owners only
|
|
2264
|
+
* (`searchAttachments`). The term and the limit are judged here again, never trusted
|
|
2265
|
+
* from the coordinator.
|
|
2266
|
+
*/
|
|
2267
|
+
searchAttachmentsAs(ctx, term, limit) {
|
|
2268
|
+
return searchAttachments(doSpineSql(this.sql), { targets: this.attachmentTargets, check: (permission, entity) => ctx.check(permission, entity) }, term, limit);
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* #1575: `ScopeAttachments.search` for a principal or a connection. Its failure travels as
|
|
2272
|
+
* DATA, the capability verbs' envelope, because a throw across this RPC keeps only its
|
|
2273
|
+
* message — and the too-many-owners refusal's `reason` is what a UI explains it by.
|
|
2274
|
+
*/
|
|
2275
|
+
async attachmentSearch(term, limit, principal, tenantId, scopeId, connectionId) {
|
|
2276
|
+
await this.ensureMigrations();
|
|
2277
|
+
try {
|
|
2278
|
+
const ctx = this.operationContext(principal, tenantId, scopeId, undefined, connectionId, undefined, undefined, undefined, 'attachments.search');
|
|
2279
|
+
return { value: await this.searchAttachmentsAs(ctx, term, limit) };
|
|
2280
|
+
}
|
|
2281
|
+
catch (err) {
|
|
2282
|
+
return { failure: toWireFailure(err) };
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* #1575: the extraction job's read of one record. No gate, deliberately — extraction
|
|
2287
|
+
* is the kernel's own derivation and the coordinator is its only caller; what a person
|
|
2288
|
+
* learns is gated at search.
|
|
2289
|
+
*/
|
|
2290
|
+
async attachmentTextSource(attachmentId) {
|
|
2291
|
+
await this.ensureMigrations();
|
|
2292
|
+
return this.attachmentRow(attachmentId);
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* #1575: write one extraction outcome, guarded on the attachment still existing.
|
|
2296
|
+
* Through the queue, so it can never land inside an invoke's or an upload's open
|
|
2297
|
+
* transaction and roll back with it.
|
|
2298
|
+
*/
|
|
2299
|
+
async attachmentTextRecord(attachmentId, outcome) {
|
|
2300
|
+
await this.ensureMigrations();
|
|
2301
|
+
return this.queue.enqueue(async () => this.ctx.storage.transactionSync(() => recordAttachmentText(doSpineSql(this.sql), attachmentId, outcome, new Date().toISOString())));
|
|
2302
|
+
}
|
|
2266
2303
|
// -- attachments through a capability (#1686) -------------------------------
|
|
2267
2304
|
// The coordinator hashed the session token; only the hash arrives. Each verb resolves it
|
|
2268
2305
|
// INSIDE the queue, as `invoke` does, so nothing can revoke between the resolution and
|
|
@@ -2332,6 +2369,11 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
2332
2369
|
return record;
|
|
2333
2370
|
});
|
|
2334
2371
|
}
|
|
2372
|
+
/** #1575: extracted-text search as the capability — its keys, its subtree, its minter now. */
|
|
2373
|
+
async capabilityAttachmentSearch(term, limit, sessionHash, tenantId, scopeId) {
|
|
2374
|
+
await this.ensureMigrations();
|
|
2375
|
+
return this.asCapability(sessionHash, tenantId, scopeId, 'attachments.search', (ctx) => this.searchAttachmentsAs(ctx, term, limit));
|
|
2376
|
+
}
|
|
2335
2377
|
/**
|
|
2336
2378
|
* Refuse an upload or a remove through a capability, and record it. Throws for an
|
|
2337
2379
|
* unknown attachment id too — the same answer either way — but only a known target has
|
|
@@ -3284,8 +3326,10 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
3284
3326
|
.toArray().map((r) => r.name));
|
|
3285
3327
|
if (!known.has(table))
|
|
3286
3328
|
throw new Error(`unknown table '${table}'`);
|
|
3287
|
-
|
|
3288
|
-
|
|
3329
|
+
// The ceiling clamps; a bound SQLite would misread (NaN, non-finite, fractional,
|
|
3330
|
+
// negative) is refused instead of reaching LIMIT / OFFSET (#1632).
|
|
3331
|
+
const l = Math.min(assertRowLimit('limit', limit), SCOPE_TABLE_PAGE_MAX);
|
|
3332
|
+
const o = assertRowOffset('offset', offset);
|
|
3289
3333
|
const cursor = this.sql.exec(`SELECT * FROM "${table}" LIMIT ? OFFSET ?`, l, o);
|
|
3290
3334
|
const columns = cursor.columnNames;
|
|
3291
3335
|
const rows = Array.from(cursor.raw(), (row) => row.map(cellToJson));
|
|
@@ -3601,6 +3645,10 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
3601
3645
|
// not this one. Dropped, so a restore never carries a receipt over; the repair
|
|
3602
3646
|
// projection that follows writes this scope's own.
|
|
3603
3647
|
this.sql.exec(`DELETE FROM _substrat_meta WHERE key = 'provisioned_for'`);
|
|
3648
|
+
// #1575: attachment text is not in a dump, so the load left it as it was. Drop the
|
|
3649
|
+
// text of attachments the dump did not bring back, and queue extraction for those
|
|
3650
|
+
// it brought back without text — the bytes decide what that run finds.
|
|
3651
|
+
reconcileAttachmentText(doSpineSql(this.sql), ulid, new Date().toISOString());
|
|
3604
3652
|
// Re-point the restored grants at THIS scope (after the spine exists, so a dump
|
|
3605
3653
|
// that carried no tuples table still finds one here).
|
|
3606
3654
|
if (destScopeId) {
|
|
@@ -3747,12 +3795,16 @@ export function defineScopeDO(modules, bareOps) {
|
|
|
3747
3795
|
// A failed delivery's error text about one of those events (#1632) — keyed by event
|
|
3748
3796
|
// id, so the outbox predicate names it. Not a copy of the event; not counted.
|
|
3749
3797
|
this.sql.exec(DELIVERY_ERROR_REDACTION_SQL, REDACTED_DELIVERY_NOTE, REDACTED_DELIVERY_NOTE, subjectId);
|
|
3798
|
+
const sql = doRedactionSql(this.sql);
|
|
3750
3799
|
return {
|
|
3751
3800
|
events: doomed.length,
|
|
3752
3801
|
intents: this.redactSubjectIntents(subjectId, at),
|
|
3753
3802
|
// The job-run tables (#1632) — the kernel's walk, so the pure host runs the
|
|
3754
3803
|
// identical SQL.
|
|
3755
|
-
jobRuns: redactSubjectJobRuns(
|
|
3804
|
+
jobRuns: redactSubjectJobRuns(sql, subjectId, at),
|
|
3805
|
+
// The free-text copies (#1632), and the tombstoned intents the coordinator hands to
|
|
3806
|
+
// the directory half. Last, so those ids include every intent tombstoned above.
|
|
3807
|
+
...redactSubjectScopeText(sql, subjectId, at),
|
|
3756
3808
|
};
|
|
3757
3809
|
}
|
|
3758
3810
|
/**
|