@substrat-run/adapter-cloudflare 0.38.0 → 0.40.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 +13 -13
- package/dist/control-plane-do.d.ts.map +1 -1
- package/dist/control-plane-do.js +114 -32
- package/dist/control-plane-do.js.map +1 -1
- package/dist/host.d.ts +4 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +70 -24
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/scope-do.d.ts.map +1 -1
- package/dist/scope-do.js +12 -3
- package/dist/scope-do.js.map +1 -1
- package/dist/scope-sweeper-do.d.ts +139 -0
- package/dist/scope-sweeper-do.d.ts.map +1 -0
- package/dist/scope-sweeper-do.js +193 -0
- package/dist/scope-sweeper-do.js.map +1 -0
- package/package.json +4 -4
package/dist/host.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ConnectionId, type ModuleId, type EntitlementGrant, type ProjectedIdentityLink, type PlatformActorId, type PrincipalId, type ResolvedIdentity, type QueryScopeInput, type ReadScopeTableInput, type RoleDefinition, type ScopeDump, type ScopeDumpTable, type ScopeId, type PlatformRequest, type PlatformRequestId, type PlatformRequestStatus, type ScopeTable, type ScopeQueryResult, type ScopeTablePage, type TenantId, type TenantStoreHandle } from '@substrat-run/contracts';
|
|
2
|
-
import { type ExecutorDeadLetter, type ExecutorDrainReport, type ExecutorHandler, type ExecutorRetryPolicy, type MigrateScopeOutcome, type MigrationFrontier, type ConnectorHandler, type ConnectorOptions, type FetchLike, type SecretBox, type HostAdmin, type ModuleRegistration, type OperationHandler, type PermissionChecker, type ProvisionScopeInput, type ScheduleRegistration, type ScheduleRunReport, type ScopeHost, type ScopeStub, type TenantRelationalStore, type TenantStoreProvisionInput } from '@substrat-run/kernel';
|
|
2
|
+
import { type ExecutorDeadLetter, type ExecutorDrainReport, type ExecutorHandler, type ExecutorRetryPolicy, type MigrateScopeOutcome, type MigrationFrontier, type ConnectorHandler, type ConnectorOptions, type FetchLike, type SecretBox, type HostAdmin, type ModuleRegistration, type OperationHandler, type PermissionChecker, type ProvisionScopeInput, type ScheduleRegistration, type ScheduleRunReport, type ScopeHost, type ScopeStub, type ScopeStubOptions, type TenantRelationalStore, type TenantStoreProvisionInput } from '@substrat-run/kernel';
|
|
3
3
|
import { type D1TenantStores } from './d1.js';
|
|
4
4
|
export interface CloudflareScopeHostOptions {
|
|
5
5
|
scope: DurableObjectNamespace;
|
|
@@ -54,6 +54,8 @@ export declare class CloudflareScopeHost implements ScopeHost {
|
|
|
54
54
|
readonly admin: HostAdmin;
|
|
55
55
|
private readonly scopeNs;
|
|
56
56
|
private readonly cp;
|
|
57
|
+
/** No control plane bound — `this.cp` is the throwing null object (Phase 3, CP-less). */
|
|
58
|
+
private readonly cpLess;
|
|
57
59
|
/** Project + evaluate permissions scope-locally (scope-local-permissions.md). */
|
|
58
60
|
private readonly scopeLocalPermissions;
|
|
59
61
|
private readonly moduleIds;
|
|
@@ -246,7 +248,7 @@ export declare class CloudflareScopeHost implements ScopeHost {
|
|
|
246
248
|
* has taken, instead of keeping a stale `schema_version` that renders as healthy.
|
|
247
249
|
*/
|
|
248
250
|
private migrateAndRecord;
|
|
249
|
-
getScope(principal: PrincipalId, tenantId: TenantId, scopeId: ScopeId): Promise<ScopeStub>;
|
|
251
|
+
getScope(principal: PrincipalId, tenantId: TenantId, scopeId: ScopeId, options?: ScopeStubOptions): Promise<ScopeStub>;
|
|
250
252
|
/**
|
|
251
253
|
* A scope stub whose authority is a CONNECTION (#97).
|
|
252
254
|
*
|
package/dist/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA,OAAO,EAsCL,KAAK,YAAY,EAEjB,KAAK,QAAQ,EAUb,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
|
package/dist/host.js
CHANGED
|
@@ -69,6 +69,8 @@ export class CloudflareScopeHost {
|
|
|
69
69
|
admin;
|
|
70
70
|
scopeNs;
|
|
71
71
|
cp;
|
|
72
|
+
/** No control plane bound — `this.cp` is the throwing null object (Phase 3, CP-less). */
|
|
73
|
+
cpLess;
|
|
72
74
|
/** Project + evaluate permissions scope-locally (scope-local-permissions.md). */
|
|
73
75
|
scopeLocalPermissions;
|
|
74
76
|
// Registration-mechanics bookkeeping (validation only — the DO executes).
|
|
@@ -112,6 +114,7 @@ export class CloudflareScopeHost {
|
|
|
112
114
|
this.fetchImpl = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
113
115
|
this.scopeLocalPermissions = options.scopeLocalPermissions ?? false;
|
|
114
116
|
this.scopeNs = options.scope;
|
|
117
|
+
this.cpLess = !options.controlPlane;
|
|
115
118
|
this.cp = options.controlPlane
|
|
116
119
|
? options.controlPlane.get(options.controlPlane.idFromName('control-plane'))
|
|
117
120
|
: nullControlPlane();
|
|
@@ -678,12 +681,12 @@ export class CloudflareScopeHost {
|
|
|
678
681
|
throw err;
|
|
679
682
|
}
|
|
680
683
|
}
|
|
681
|
-
async getScope(principal, tenantId, scopeId) {
|
|
684
|
+
async getScope(principal, tenantId, scopeId, options) {
|
|
682
685
|
// Lifecycle gates (control-plane.md §4.1/§4.2), the K-3 fail-closed path,
|
|
683
686
|
// evaluated durably in the ControlPlaneDO. A throw propagates here.
|
|
684
687
|
await this.cp.validateScopeAccess(tenantId, scopeId);
|
|
685
688
|
await this.migrateAndRecord(scopeId);
|
|
686
|
-
return this.buildStub(tenantId, scopeId, principal);
|
|
689
|
+
return this.buildStub(tenantId, scopeId, principal, undefined, undefined, options);
|
|
687
690
|
}
|
|
688
691
|
/**
|
|
689
692
|
* A scope stub whose authority is a CONNECTION (#97).
|
|
@@ -741,10 +744,15 @@ export class CloudflareScopeHost {
|
|
|
741
744
|
if (!schedules || schedules.length === 0)
|
|
742
745
|
return report;
|
|
743
746
|
// Only run on a live scope of this tenant; a scope archived between the sweep's
|
|
744
|
-
// enumeration and here simply has nothing due.
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
747
|
+
// enumeration and here simply has nothing due. A CP-less host has no directory
|
|
748
|
+
// to ask (#461) — it already trusts the router-asserted (tenant, scope) for the
|
|
749
|
+
// whole request path, and lifecycle for its scopes lives wherever provisioning
|
|
750
|
+
// does, so the grant check below is the only gate it can and does enforce.
|
|
751
|
+
if (!this.cpLess) {
|
|
752
|
+
const rec = await this.cp.getScopeRecord(tenantId, scopeId);
|
|
753
|
+
if (!rec || rec.status !== 'active')
|
|
754
|
+
return report;
|
|
755
|
+
}
|
|
748
756
|
const stub = this.scopeStub(scopeId);
|
|
749
757
|
// The grant IS the switch (#383): run only where the scope holds a live
|
|
750
758
|
// `system:<moduleId>` grant. Skips a foreign-vertical scope and a per-tenant
|
|
@@ -779,7 +787,7 @@ export class CloudflareScopeHost {
|
|
|
779
787
|
return report;
|
|
780
788
|
}
|
|
781
789
|
/** The stub body, shared by the principal, connection, and system doors. */
|
|
782
|
-
buildStub(tenantId, scopeId, principal, connectionId, systemModuleId) {
|
|
790
|
+
buildStub(tenantId, scopeId, principal, connectionId, systemModuleId, options) {
|
|
783
791
|
const stub = this.scopeStub(scopeId);
|
|
784
792
|
const cp = this.cp;
|
|
785
793
|
const operationEntitlement = this.operationEntitlement;
|
|
@@ -802,9 +810,13 @@ export class CloudflareScopeHost {
|
|
|
802
810
|
if (requiredKey && !(await cp.tenantHoldsEntitlement(tenantId, requiredKey))) {
|
|
803
811
|
return Promise.reject(new Error(`operation not entitled: ${operation} — tenant does not hold '${requiredKey}'`));
|
|
804
812
|
}
|
|
805
|
-
const
|
|
813
|
+
const envelope = await stub.invoke(operation, input, asPrincipalId, tenantId, scopeId, connectionId, requiredKey, systemModuleId);
|
|
806
814
|
await this.drainExecutors(tenantId, scopeId);
|
|
807
|
-
|
|
815
|
+
// #458: the operation committed having enqueued platform intents — tell the
|
|
816
|
+
// caller's harness so it can flag the response for the router kick (#381).
|
|
817
|
+
if (envelope.platformRequests > 0)
|
|
818
|
+
options?.onPlatformRequests?.(envelope.platformRequests);
|
|
819
|
+
return envelope.result;
|
|
808
820
|
},
|
|
809
821
|
};
|
|
810
822
|
}
|
|
@@ -933,7 +945,13 @@ export class CloudflareScopeHost {
|
|
|
933
945
|
await this.fanOut(tenantId); // role definitions are projected into the tenant's scopes
|
|
934
946
|
},
|
|
935
947
|
listRoles: async (actor, filter) => {
|
|
936
|
-
const rows = await this.cp.listRoles({
|
|
948
|
+
const rows = await this.cp.listRoles({
|
|
949
|
+
tenantId: filter?.tenantId,
|
|
950
|
+
source: filter?.source,
|
|
951
|
+
limit: filter?.limit,
|
|
952
|
+
cursor: filter?.cursor,
|
|
953
|
+
order: filter?.order,
|
|
954
|
+
});
|
|
937
955
|
await this.recordAccess(actor, 'listRoles', { tenantId: filter?.tenantId ?? null }, filter, rows.length);
|
|
938
956
|
// Parsed, not cast — the same parse the pure adapter does, which is what
|
|
939
957
|
// makes the shared contract suite mean anything.
|
|
@@ -1110,6 +1128,9 @@ export class CloudflareScopeHost {
|
|
|
1110
1128
|
tenantId: filter?.tenantId,
|
|
1111
1129
|
scopeId: filter?.scopeId,
|
|
1112
1130
|
status: filter?.status,
|
|
1131
|
+
limit: filter?.limit,
|
|
1132
|
+
cursor: filter?.cursor,
|
|
1133
|
+
order: filter?.order,
|
|
1113
1134
|
});
|
|
1114
1135
|
await this.recordAccess(actor, 'listHostnames', { tenantId: filter?.tenantId ?? null, scopeId: filter?.scopeId ?? null }, filter, rows.length);
|
|
1115
1136
|
return rows.map(mapHostname);
|
|
@@ -1132,6 +1153,10 @@ export class CloudflareScopeHost {
|
|
|
1132
1153
|
installSpec.provides = parsed.provides;
|
|
1133
1154
|
if (parsed.requires)
|
|
1134
1155
|
installSpec.requires = parsed.requires;
|
|
1156
|
+
// Declared provisioner intent (#455) — the request half of the tenant-provisioner
|
|
1157
|
+
// capability; the grant is its own column, never part of this refreshable bag.
|
|
1158
|
+
if (parsed.provisions)
|
|
1159
|
+
installSpec.provisions = parsed.provisions;
|
|
1135
1160
|
const installSpecJson = Object.keys(installSpec).length ? JSON.stringify(installSpec) : null;
|
|
1136
1161
|
const existing = await this.cp.readVertical(parsed.slug);
|
|
1137
1162
|
if (existing) {
|
|
@@ -1157,9 +1182,9 @@ export class CloudflareScopeHost {
|
|
|
1157
1182
|
await this.cp.insertVertical(parsed.slug, parsed.name, parsed.source, parsed.ownerTenant, envSpecJson, installSpecJson, parsed.listed ? 1 : 0, new Date().toISOString());
|
|
1158
1183
|
await this.recordAdmin(actor, 'registerVertical', { tenantId: null }, null, parsed);
|
|
1159
1184
|
},
|
|
1160
|
-
listVerticals: async (actor) => {
|
|
1161
|
-
const rows = await this.cp.listVerticals();
|
|
1162
|
-
await this.recordAccess(actor, 'listVerticals', {}, null, rows.length);
|
|
1185
|
+
listVerticals: async (actor, page) => {
|
|
1186
|
+
const rows = await this.cp.listVerticals(page);
|
|
1187
|
+
await this.recordAccess(actor, 'listVerticals', {}, page ?? null, rows.length);
|
|
1163
1188
|
return rows.map(mapVertical);
|
|
1164
1189
|
},
|
|
1165
1190
|
publishVersion: async (actor, input) => {
|
|
@@ -1188,8 +1213,8 @@ export class CloudflareScopeHost {
|
|
|
1188
1213
|
admission: selfAdmits ? 'admitted' : 'pending',
|
|
1189
1214
|
});
|
|
1190
1215
|
},
|
|
1191
|
-
listVersions: async (actor, verticalSlug) => {
|
|
1192
|
-
const rows = await this.cp.listVersions(verticalSlug);
|
|
1216
|
+
listVersions: async (actor, verticalSlug, page) => {
|
|
1217
|
+
const rows = await this.cp.listVersions(verticalSlug, page);
|
|
1193
1218
|
await this.recordAccess(actor, 'listVersions', {}, { verticalSlug }, rows.length);
|
|
1194
1219
|
return rows.map(mapVersion);
|
|
1195
1220
|
},
|
|
@@ -1351,8 +1376,8 @@ export class CloudflareScopeHost {
|
|
|
1351
1376
|
}
|
|
1352
1377
|
await this.recordAdmin(actor, 'promoteVersion', { tenantId: null, vertical: verticalSlug }, outgoing ? { versionId: outgoing.id, version: outgoing.version } : null, { channel, versionId, version: incoming.version, acknowledged: ack });
|
|
1353
1378
|
},
|
|
1354
|
-
listChannels: async (actor, verticalSlug) => {
|
|
1355
|
-
const rows = await this.cp.listChannels(verticalSlug);
|
|
1379
|
+
listChannels: async (actor, verticalSlug, page) => {
|
|
1380
|
+
const rows = await this.cp.listChannels(verticalSlug, page);
|
|
1356
1381
|
// The serving script runs ONE version (#286); surface it on the prod row so a
|
|
1357
1382
|
// failed in-place serve (channel moved, serve did not) reads honestly instead of
|
|
1358
1383
|
// claiming the new version is live (#321).
|
|
@@ -1366,8 +1391,8 @@ export class CloudflareScopeHost {
|
|
|
1366
1391
|
servingVersionId: r.channel === 'prod' ? serving : null,
|
|
1367
1392
|
}));
|
|
1368
1393
|
},
|
|
1369
|
-
listChannelHistory: async (actor, verticalSlug, channel) => {
|
|
1370
|
-
const rows = await this.cp.listChannelHistory(verticalSlug, channel);
|
|
1394
|
+
listChannelHistory: async (actor, verticalSlug, channel, page) => {
|
|
1395
|
+
const rows = await this.cp.listChannelHistory(verticalSlug, channel, page);
|
|
1371
1396
|
await this.recordAccess(actor, 'listChannelHistory', {}, { verticalSlug, channel }, rows.length);
|
|
1372
1397
|
return rows.map((r) => channelHistoryEntry.parse({
|
|
1373
1398
|
id: r.id,
|
|
@@ -1543,10 +1568,10 @@ export class CloudflareScopeHost {
|
|
|
1543
1568
|
const before = await this.cp.reapTenant(tenantId);
|
|
1544
1569
|
await this.recordAdmin(actor, 'reapTenant', { tenantId }, { status: before }, { status: 'reaped' });
|
|
1545
1570
|
},
|
|
1546
|
-
listTenants: async (actor) => {
|
|
1547
|
-
const tenants = (await this.cp.listTenants()).map((t) => tenantSchema.parse(t));
|
|
1571
|
+
listTenants: async (actor, page) => {
|
|
1572
|
+
const tenants = (await this.cp.listTenants(page)).map((t) => tenantSchema.parse(t));
|
|
1548
1573
|
// Enumerating every tenant on the platform is the read this log exists for.
|
|
1549
|
-
await this.recordAccess(actor, 'listTenants', {}, null, tenants.length);
|
|
1574
|
+
await this.recordAccess(actor, 'listTenants', {}, page ?? null, tenants.length);
|
|
1550
1575
|
return tenants;
|
|
1551
1576
|
},
|
|
1552
1577
|
getTenant: async (actor, tenantId) => {
|
|
@@ -1563,6 +1588,9 @@ export class CloudflareScopeHost {
|
|
|
1563
1588
|
: [filter.status]
|
|
1564
1589
|
: undefined,
|
|
1565
1590
|
vertical: filter?.vertical,
|
|
1591
|
+
limit: filter?.limit,
|
|
1592
|
+
cursor: filter?.cursor,
|
|
1593
|
+
order: filter?.order,
|
|
1566
1594
|
});
|
|
1567
1595
|
await this.recordAccess(actor, 'listScopes', { tenantId: filter?.tenantId ?? null }, filter, rows.length);
|
|
1568
1596
|
return rows.map(mapScope);
|
|
@@ -1808,8 +1836,8 @@ export class CloudflareScopeHost {
|
|
|
1808
1836
|
return; // idempotent, and a no-op is not audited
|
|
1809
1837
|
await this.recordAdmin(actor, 'revokeConnection', { tenantId: row.tenant_id, vertical: row.vertical }, { status: row.status }, { id, provider: row.provider, status: 'revoked', revokedAt: now });
|
|
1810
1838
|
},
|
|
1811
|
-
openConnection: async (tenantId, vertical, provider) => {
|
|
1812
|
-
const row = await this.cp.readLiveConnection(tenantId, vertical, provider);
|
|
1839
|
+
openConnection: async (tenantId, vertical, provider, externalAccountRef) => {
|
|
1840
|
+
const row = await this.cp.readLiveConnection(tenantId, vertical, provider, externalAccountRef);
|
|
1813
1841
|
if (!row)
|
|
1814
1842
|
return undefined;
|
|
1815
1843
|
const secret = connectionSecret.parse(JSON.parse(await this.secretBox.open({ keyId: row.key_id, ciphertext: row.ciphertext })));
|
|
@@ -1885,6 +1913,8 @@ export class CloudflareScopeHost {
|
|
|
1885
1913
|
tenantId: filter?.tenantId,
|
|
1886
1914
|
method: filter?.method,
|
|
1887
1915
|
limit: filter?.limit,
|
|
1916
|
+
cursor: filter?.cursor,
|
|
1917
|
+
order: filter?.order,
|
|
1888
1918
|
});
|
|
1889
1919
|
// Reading the access log is itself a read. Recorded before returning, so
|
|
1890
1920
|
// the row describing this call is not in its own result.
|
|
@@ -2065,6 +2095,22 @@ export class CloudflareScopeHost {
|
|
|
2065
2095
|
object: `scope:${input.scopeId}`,
|
|
2066
2096
|
expires_at: null,
|
|
2067
2097
|
},
|
|
2098
|
+
// #461: each registered module's SCHEDULE grants (#383) ride the same unit —
|
|
2099
|
+
// the CP-less mirror of `provisionScope`'s writeTuple loop. Without them the
|
|
2100
|
+
// grant-is-the-switch check makes every schedule a silent no-op (`fired: 0`,
|
|
2101
|
+
// no error — the #49 unfalsifiable zero).
|
|
2102
|
+
...[...this.moduleSchedules].flatMap(([modId, schedules]) => {
|
|
2103
|
+
const perms = new Set();
|
|
2104
|
+
for (const s of schedules)
|
|
2105
|
+
for (const p of s.permissions)
|
|
2106
|
+
perms.add(p);
|
|
2107
|
+
return [...perms].map((perm) => ({
|
|
2108
|
+
subject: `system:${modId}`,
|
|
2109
|
+
relation: `granted:${perm}`,
|
|
2110
|
+
object: `scope:${input.scopeId}`,
|
|
2111
|
+
expires_at: null,
|
|
2112
|
+
}));
|
|
2113
|
+
}),
|
|
2068
2114
|
],
|
|
2069
2115
|
// #406: identity links, delivered by the platform with provisioning exactly as
|
|
2070
2116
|
// entitlements are (#310). Preserve-on-undefined, so an absent field never wipes
|