@substrat-run/control-plane-api 0.48.1 → 0.50.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.
@@ -0,0 +1,93 @@
1
+ /**
2
+ * The scope-backup write seam (#493) — where a reap's recoverable copy goes.
3
+ *
4
+ * A reap frees a scope's Durable Object storage because Cloudflare never garbage-
5
+ * collects a DO, and it is irreversible. Before #493 the operator had to REMEMBER to
6
+ * take a copy first, from a different surface; this seam is what makes "a reap always
7
+ * leaves a recoverable copy" a property of the route instead of a habit.
8
+ *
9
+ * Why a dump and not a snapshot fork. The obvious cheap move — `orchestratedSnapshot`
10
+ * before the reap — does not survive the case the flow exists for. A fork is provisioned
11
+ * INSIDE the vertical's own deployment and activated, so (a) its bytes live in the very
12
+ * deployment a retirement is about to delete, and (b) it counts as a live scope in
13
+ * `countScopesForVertical`, which means it re-blocks the `deleteVertical` the reap was
14
+ * clearing. A dump leaves the deployment entirely, and `POST …/restore` already loads one
15
+ * back, so export→store→restore is the round trip that actually closes.
16
+ *
17
+ * Provider-neutral by the same posture as `ObservabilityReader` and `DeployVerticalFn`:
18
+ * the contract lives here, an implementation lives in its own module (`r2-backups.ts` for
19
+ * Cloudflare R2), and the host injects one. A backup is addressed by (tenant, scope,
20
+ * capturedAt) rather than by a store-shaped key, so the key scheme stays the store's
21
+ * private business and no caller can build a path into someone else's tenant.
22
+ *
23
+ * Fidelity is deliberately FULL, never masked (#493). A masked dump has its PII redacted,
24
+ * so restoring one produces a structurally-valid but factually wrong scope — a backup that
25
+ * cannot restore is a false promise, and the promise is the whole point. This is not the
26
+ * §6 governed pull: the bytes go platform→platform and are never handed to a caller, which
27
+ * is why the export route's masking default does not apply here.
28
+ */
29
+ import type { DirectoryBackup, DirectoryDump, ScopeBackup, ScopeDump } from '@substrat-run/contracts';
30
+ export type { ScopeBackup, DirectoryBackup };
31
+ export interface ScopeBackupStore {
32
+ /**
33
+ * Store one full-fidelity dump and return its metadata. Must be durable before it
34
+ * returns: the reap's whole guarantee is that this resolved before any byte was wiped.
35
+ */
36
+ put(input: {
37
+ vertical: string | null;
38
+ dump: ScopeDump;
39
+ }): Promise<ScopeBackup>;
40
+ /** Every backup held for one scope, newest first. */
41
+ list(input: {
42
+ tenantId: string;
43
+ scopeId: string;
44
+ }): Promise<ScopeBackup[]>;
45
+ /** One backup's dump, by its capture time. Null when no such copy is held. */
46
+ get(input: {
47
+ tenantId: string;
48
+ scopeId: string;
49
+ capturedAt: string;
50
+ }): Promise<ScopeDump | null>;
51
+ }
52
+ /**
53
+ * The DIRECTORY-backup store (#40) — the platform's own copy, not a tenant's.
54
+ *
55
+ * A sibling seam rather than a widened `ScopeBackupStore`, because the two are the same
56
+ * mechanism serving different jobs and the difference is worth keeping in the types.
57
+ * A scope backup is taken at a MOMENT — before a reap, before a migration — and is
58
+ * addressed by the scope it came from. A directory backup is taken on a SCHEDULE, has
59
+ * no tenant to be addressed by, and is pruned to a retention window. Only this one
60
+ * needs `delete`, and only this one is ever written by a sweep with no operator behind
61
+ * it.
62
+ *
63
+ * What it defends against is also different, and the distinction is the whole design
64
+ * (#40's own analysis). Per-scope point-in-time recovery already covers corruption
65
+ * inside the account — ~30 days, continuous, and strictly better than a daily copy, so
66
+ * scheduled per-scope backups are deliberately NOT built. The directory is the case PITR
67
+ * cannot answer: it is one Durable Object, and a bug that deletes it outright leaves
68
+ * nothing to rewind. Copies live outside the DO for that reason.
69
+ *
70
+ * Honest scoping: with the store bound in the platform's OWN account (the shape shipped
71
+ * today), this survives losing the directory, not losing the account. The seam is
72
+ * provider-neutral so an off-account target is a drop-in — see control-plane.md §4.9.
73
+ */
74
+ export interface DirectoryBackupStore {
75
+ /**
76
+ * Store one full-fidelity directory dump and return its metadata. Durable before it
77
+ * returns, like the scope store's `put`.
78
+ */
79
+ put(input: {
80
+ dump: DirectoryDump;
81
+ }): Promise<DirectoryBackup>;
82
+ /** Every directory copy held, newest first. */
83
+ list(): Promise<DirectoryBackup[]>;
84
+ /** One copy's dump, by its capture time. Null when no such copy is held. */
85
+ get(input: {
86
+ capturedAt: string;
87
+ }): Promise<DirectoryDump | null>;
88
+ /** Drop one copy — how the retention window is enforced. Missing is not an error. */
89
+ delete(input: {
90
+ capturedAt: string;
91
+ }): Promise<void>;
92
+ }
93
+ //# sourceMappingURL=backups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backups.d.ts","sourceRoot":"","sources":["../src/backups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAKtG,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;AAE7C,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,GAAG,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/E,qDAAqD;IACrD,IAAI,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3E,8EAA8E;IAC9E,GAAG,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CAClG;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,GAAG,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,aAAa,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9D,+CAA+C;IAC/C,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACnC,4EAA4E;IAC5E,GAAG,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAClE,qFAAqF;IACrF,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The scope-backup write seam (#493) — where a reap's recoverable copy goes.
3
+ *
4
+ * A reap frees a scope's Durable Object storage because Cloudflare never garbage-
5
+ * collects a DO, and it is irreversible. Before #493 the operator had to REMEMBER to
6
+ * take a copy first, from a different surface; this seam is what makes "a reap always
7
+ * leaves a recoverable copy" a property of the route instead of a habit.
8
+ *
9
+ * Why a dump and not a snapshot fork. The obvious cheap move — `orchestratedSnapshot`
10
+ * before the reap — does not survive the case the flow exists for. A fork is provisioned
11
+ * INSIDE the vertical's own deployment and activated, so (a) its bytes live in the very
12
+ * deployment a retirement is about to delete, and (b) it counts as a live scope in
13
+ * `countScopesForVertical`, which means it re-blocks the `deleteVertical` the reap was
14
+ * clearing. A dump leaves the deployment entirely, and `POST …/restore` already loads one
15
+ * back, so export→store→restore is the round trip that actually closes.
16
+ *
17
+ * Provider-neutral by the same posture as `ObservabilityReader` and `DeployVerticalFn`:
18
+ * the contract lives here, an implementation lives in its own module (`r2-backups.ts` for
19
+ * Cloudflare R2), and the host injects one. A backup is addressed by (tenant, scope,
20
+ * capturedAt) rather than by a store-shaped key, so the key scheme stays the store's
21
+ * private business and no caller can build a path into someone else's tenant.
22
+ *
23
+ * Fidelity is deliberately FULL, never masked (#493). A masked dump has its PII redacted,
24
+ * so restoring one produces a structurally-valid but factually wrong scope — a backup that
25
+ * cannot restore is a false promise, and the promise is the whole point. This is not the
26
+ * §6 governed pull: the bytes go platform→platform and are never handed to a caller, which
27
+ * is why the export route's masking default does not apply here.
28
+ */
29
+ export {};
30
+ //# sourceMappingURL=backups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backups.js","sourceRoot":"","sources":["../src/backups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG"}
@@ -1 +1 @@
1
- {"version":3,"file":"cf-observability.d.ts","sourceRoot":"","sources":["../src/cf-observability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AA4BD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,sBAAsB,GAAG,mBAAmB,CAwH7F"}
1
+ {"version":3,"file":"cf-observability.d.ts","sourceRoot":"","sources":["../src/cf-observability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AA4BD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,sBAAsB,GAAG,mBAAmB,CA8I7F"}
@@ -61,60 +61,75 @@ export function createCfObservabilityReader(opts) {
61
61
  }))
62
62
  .sort((a, b) => b.requests - a.requests);
63
63
  },
64
- async recentLogs({ service, level, search, hours, limit }) {
65
- const to = Date.now();
66
- const filters = [];
67
- // `$metadata.service` is the script name in Workers Logs events the field
68
- // Cloudflare's own query examples filter on.
69
- if (service) {
70
- filters.push({ key: '$metadata.service', operation: 'eq', type: 'string', value: service });
64
+ async recentLogs({ services, level, search, hours, limit }) {
65
+ // One query per service, merged newest-first: the telemetry API's filters are
66
+ // single-valued equality, and an OR across script names is not a filter this
67
+ // API offers. The queries are independent, so they run concurrently and the
68
+ // merge (not the backend) enforces the overall `limit`.
69
+ if (services && services.length > 1) {
70
+ const pages = await Promise.all(services.map((s) => queryEvents(s, level, search, hours, limit)));
71
+ return pages
72
+ .flat()
73
+ .sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0))
74
+ .slice(0, limit);
71
75
  }
72
- if (level) {
73
- filters.push({ key: '$metadata.level', operation: 'eq', type: 'string', value: level });
74
- }
75
- if (search) {
76
- filters.push({ key: '$metadata.message', operation: 'includes', type: 'string', value: search });
77
- }
78
- const res = await authed(`https://api.cloudflare.com/client/v4/accounts/${opts.accountId}/workers/observability/telemetry/query`, {
79
- queryId: 'substrat-recent-logs',
80
- view: 'events',
81
- timeframe: { from: to - hours * 3_600_000, to },
82
- parameters: { datasets: ['cloudflare-workers'], filters, limit },
83
- limit,
84
- });
85
- const json = (await res.json());
86
- if (!res.ok || json.success === false) {
87
- const message = json.errors?.map((e) => e.message).join('; ') || `HTTP ${res.status}`;
88
- throw new Error(`Cloudflare telemetry query failed: ${message}`);
89
- }
90
- // The events view has nested the list one level deeper across API revisions —
91
- // accept both rather than pinning to whichever shape was current at writing.
92
- const outer = json.result?.events;
93
- const events = (Array.isArray(outer) ? outer : (outer?.events ?? []));
94
- const str = (v) => (typeof v === 'string' ? v : null);
95
- const num = (v) => (typeof v === 'number' ? v : null);
96
- return events.map((e) => {
97
- const metadata = (e['$metadata'] ?? {});
98
- const workers = (e['$workers'] ?? {});
99
- return {
100
- timestamp: num(e['timestamp']),
101
- level: str(metadata['level']),
102
- message: str(metadata['message']),
103
- service: str(metadata['service']) ?? str(workers['scriptName']),
104
- outcome: str(workers['outcome']),
105
- // `$metadata.trigger` reads like `<entrypoint>.<method>` (e.g. `default.importDump`);
106
- // fall back to the `$workers.event` sub-shape (`rpcMethod`) when it is absent.
107
- trigger: str(metadata['trigger']) ??
108
- str(workers['event']?.['rpcMethod']),
109
- eventType: str(workers['eventType']),
110
- entrypoint: str(workers['entrypoint']),
111
- requestId: str(metadata['requestId']) ?? str(workers['requestId']),
112
- cpuTimeMs: num(workers['cpuTimeMs']),
113
- wallTimeMs: num(workers['wallTimeMs']),
114
- raw: e,
115
- };
116
- });
76
+ return queryEvents(services?.[0], level, search, hours, limit);
117
77
  },
118
78
  };
79
+ /** One telemetry query — narrowed to a single service, or to none (the fleet view). */
80
+ async function queryEvents(service, level, search, hours, limit) {
81
+ const to = Date.now();
82
+ const filters = [];
83
+ // `$metadata.service` is the script name in Workers Logs events — the field
84
+ // Cloudflare's own query examples filter on.
85
+ if (service) {
86
+ filters.push({ key: '$metadata.service', operation: 'eq', type: 'string', value: service });
87
+ }
88
+ if (level) {
89
+ filters.push({ key: '$metadata.level', operation: 'eq', type: 'string', value: level });
90
+ }
91
+ if (search) {
92
+ filters.push({ key: '$metadata.message', operation: 'includes', type: 'string', value: search });
93
+ }
94
+ const res = await authed(`https://api.cloudflare.com/client/v4/accounts/${opts.accountId}/workers/observability/telemetry/query`, {
95
+ queryId: 'substrat-recent-logs',
96
+ view: 'events',
97
+ timeframe: { from: to - hours * 3_600_000, to },
98
+ parameters: { datasets: ['cloudflare-workers'], filters, limit },
99
+ limit,
100
+ });
101
+ const json = (await res.json());
102
+ if (!res.ok || json.success === false) {
103
+ const message = json.errors?.map((e) => e.message).join('; ') || `HTTP ${res.status}`;
104
+ throw new Error(`Cloudflare telemetry query failed: ${message}`);
105
+ }
106
+ // The events view has nested the list one level deeper across API revisions —
107
+ // accept both rather than pinning to whichever shape was current at writing.
108
+ const outer = json.result?.events;
109
+ const events = (Array.isArray(outer) ? outer : (outer?.events ?? []));
110
+ const str = (v) => (typeof v === 'string' ? v : null);
111
+ const num = (v) => (typeof v === 'number' ? v : null);
112
+ return events.map((e) => {
113
+ const metadata = (e['$metadata'] ?? {});
114
+ const workers = (e['$workers'] ?? {});
115
+ return {
116
+ timestamp: num(e['timestamp']),
117
+ level: str(metadata['level']),
118
+ message: str(metadata['message']),
119
+ service: str(metadata['service']) ?? str(workers['scriptName']),
120
+ outcome: str(workers['outcome']),
121
+ // `$metadata.trigger` reads like `<entrypoint>.<method>` (e.g. `default.importDump`);
122
+ // fall back to the `$workers.event` sub-shape (`rpcMethod`) when it is absent.
123
+ trigger: str(metadata['trigger']) ??
124
+ str(workers['event']?.['rpcMethod']),
125
+ eventType: str(workers['eventType']),
126
+ entrypoint: str(workers['entrypoint']),
127
+ requestId: str(metadata['requestId']) ?? str(workers['requestId']),
128
+ cpuTimeMs: num(workers['cpuTimeMs']),
129
+ wallTimeMs: num(workers['wallTimeMs']),
130
+ raw: e,
131
+ };
132
+ });
133
+ }
119
134
  }
120
135
  //# sourceMappingURL=cf-observability.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cf-observability.js","sourceRoot":"","sources":["../src/cf-observability.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cf-observability.js","sourceRoot":"","sources":["../src/cf-observability.ts"],"names":[],"mappings":"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"}
package/dist/deploy.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DeclaredBinding, DeployManifest } from '@substrat-run/contracts';
1
+ import type { AssetRouting, DeclaredBinding, DeployManifest } from '@substrat-run/contracts';
2
2
  /**
3
3
  * The deploy seam (self-serve-deploy.md). A `substrat push` uploads a *built* worker
4
4
  * bundle; this layer forwards it to the platform's runtime (a Workers-for-Platforms
@@ -21,6 +21,23 @@ import type { DeclaredBinding, DeployManifest } from '@substrat-run/contracts';
21
21
  */
22
22
  export { deployManifest, storedDeployManifest } from '@substrat-run/contracts';
23
23
  export type { DeclaredBinding, DeployManifest } from '@substrat-run/contracts';
24
+ /**
25
+ * One static file on its way to the runtime's asset store (#340). `content` is present on a
26
+ * PUSH (the builder just uploaded the bytes) and absent on a RE-serve — a promote re-uploads
27
+ * a version from its archive script (#286) and has only the retained manifest, which is
28
+ * enough whenever the runtime still holds the content-addressed bytes. An uploader that
29
+ * finds it needs bytes it was not given must say so; it must never quietly serve a version
30
+ * with some of its assets missing.
31
+ */
32
+ export interface AssetUpload {
33
+ path: string;
34
+ hash: string;
35
+ /** Byte length — part of the upload-session manifest, so it must be known even when the
36
+ * bytes themselves are not (a re-serve reads it back from the retained manifest). */
37
+ size: number;
38
+ contentType: string;
39
+ content?: Uint8Array;
40
+ }
24
41
  /** A built vertical, ready to upload. `modules` are the bundled ESM parts. */
25
42
  export interface VerticalBundle {
26
43
  entry: string;
@@ -36,6 +53,11 @@ export interface VerticalBundle {
36
53
  /** DO classes to migrate as SQLite (`new_sqlite_classes`). */
37
54
  doClasses: string[];
38
55
  bindings: DeclaredBinding[];
56
+ /** Static files served from the edge, with the routing config that decides how paths
57
+ * resolve against them (#340). Absent ⇒ the script serves no static assets. */
58
+ assets?: AssetRouting & {
59
+ files: AssetUpload[];
60
+ };
39
61
  }
40
62
  /**
41
63
  * How an upload treats an ALREADY-EXISTING script of the same name (#286). Absent ⇒
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE/E,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B;mFAC+E;IAC/E,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtE,8DAA8D;IAC9D,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,sFAAsF;IACtF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kEAAkE;IAClE,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAExC,QAAQ,CAAC,cAAc,EAAE,MAAM;IADjC,YACW,cAAc,EAAE,MAAM,EAC/B,OAAO,EAAE,MAAM,EAIhB;CACF;AAED,6GAA6G;AAC7G,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACnC,aAAa,EAAE,MAAM,KAClB,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;AAcxC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,cAAc,GAAG,IAAI,CA6B7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;0FAC0F;AAC1F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGxD"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;0FACsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B;mFAC+E;IAC/E,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtE,8DAA8D;IAC9D,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B;oFACgF;IAChF,MAAM,CAAC,EAAE,YAAY,GAAG;QAAE,KAAK,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;CAClD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,sFAAsF;IACtF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,kEAAkE;IAClE,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAExC,QAAQ,CAAC,cAAc,EAAE,MAAM;IADjC,YACW,cAAc,EAAE,MAAM,EAC/B,OAAO,EAAE,MAAM,EAIhB;CACF;AAED,6GAA6G;AAC7G,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACnC,aAAa,EAAE,MAAM,KAClB,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;AAcxC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,cAAc,GAAG,IAAI,CA6B7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;0FAC0F;AAC1F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGxD"}
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The scheduled directory backup (#40) — the platform's own disaster-recovery pass.
3
+ *
4
+ * `control-plane.md` names the stake without resolving it: *"The directory becomes a real
5
+ * database, with its own migrations and backup story… Losing it is losing the platform,
6
+ * not losing a cache."* Every OTHER database the platform holds is a scope, protected by
7
+ * ~30-day Durable Object point-in-time recovery — which is continuous, per-scope, and
8
+ * strictly better than any daily copy, so scheduled per-scope backups are deliberately not
9
+ * built here. The directory is the one database PITR cannot answer for: it is a single DO,
10
+ * and a control-plane bug that deletes it outright leaves nothing to rewind. So a copy
11
+ * lives OUTSIDE the DO, and this is what takes it.
12
+ *
13
+ * Driven by the same cron that drives the platform sweep, and the cadence is enforced HERE
14
+ * rather than by a second trigger. A quarter-hourly sweep asking "is a copy due?" and answering
15
+ * from the store is idempotent, survives a missed tick (the next pass takes it, late
16
+ * rather than never), and needs no durable "last run" state of its own — the newest stored
17
+ * copy IS that state. A dedicated daily trigger would have to be right about time zones,
18
+ * deploys and restarts to do the same job worse.
19
+ */
20
+ import type { DirectoryBackup, PlatformActorId } from '@substrat-run/contracts';
21
+ import type { HostAdmin } from '@substrat-run/kernel';
22
+ import type { DirectoryBackupStore } from './backups.js';
23
+ export interface DirectoryBackupOptions {
24
+ admin: HostAdmin;
25
+ store: DirectoryBackupStore;
26
+ /** The platform actor the export is audited under. */
27
+ actor: PlatformActorId;
28
+ /** Hours between copies (default 24). */
29
+ intervalHours?: number;
30
+ /** How many copies to keep (default 30). Older ones are deleted after a successful put. */
31
+ retain?: number;
32
+ /** Take a copy regardless of cadence — what the manual "back up now" route passes. */
33
+ force?: boolean;
34
+ /** Injected clock, for tests. */
35
+ now?: () => Date;
36
+ }
37
+ export interface DirectoryBackupResult {
38
+ /** The copy taken this pass, or null when the cadence guard skipped it. */
39
+ taken: DirectoryBackup | null;
40
+ /** When nothing was taken: the copy that was still fresh enough to skip for. */
41
+ skippedFor: string | null;
42
+ /** Copies deleted by the retention window this pass. */
43
+ pruned: number;
44
+ }
45
+ /**
46
+ * Take a directory backup if one is due, then prune to the retention window.
47
+ *
48
+ * Order matters and is the inverse of the reap's (#493). A reap stores BEFORE it wipes,
49
+ * because the wipe is what the copy protects against. Here the prune runs AFTER a
50
+ * successful put, so a failed capture can never be the thing that deletes the last good
51
+ * copy — the worst case is an extra copy kept, never a missing one.
52
+ *
53
+ * Throws whatever the export or the store threw. The caller (a cron pass) decides what a
54
+ * failure means; it must not be silent, which is why nothing is swallowed here.
55
+ */
56
+ export declare function backupDirectoryIfDue(options: DirectoryBackupOptions): Promise<DirectoryBackupResult>;
57
+ //# sourceMappingURL=directory-backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-backup.d.ts","sourceRoot":"","sources":["../src/directory-backup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAUzD,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,oBAAoB,CAAC;IAC5B,sDAAsD;IACtD,KAAK,EAAE,eAAe,CAAC;IACvB,yCAAyC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CA+BhC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The scheduled directory backup (#40) — the platform's own disaster-recovery pass.
3
+ *
4
+ * `control-plane.md` names the stake without resolving it: *"The directory becomes a real
5
+ * database, with its own migrations and backup story… Losing it is losing the platform,
6
+ * not losing a cache."* Every OTHER database the platform holds is a scope, protected by
7
+ * ~30-day Durable Object point-in-time recovery — which is continuous, per-scope, and
8
+ * strictly better than any daily copy, so scheduled per-scope backups are deliberately not
9
+ * built here. The directory is the one database PITR cannot answer for: it is a single DO,
10
+ * and a control-plane bug that deletes it outright leaves nothing to rewind. So a copy
11
+ * lives OUTSIDE the DO, and this is what takes it.
12
+ *
13
+ * Driven by the same cron that drives the platform sweep, and the cadence is enforced HERE
14
+ * rather than by a second trigger. A quarter-hourly sweep asking "is a copy due?" and answering
15
+ * from the store is idempotent, survives a missed tick (the next pass takes it, late
16
+ * rather than never), and needs no durable "last run" state of its own — the newest stored
17
+ * copy IS that state. A dedicated daily trigger would have to be right about time zones,
18
+ * deploys and restarts to do the same job worse.
19
+ */
20
+ /** One copy a day; the sweep runs far more often and skips in between. */
21
+ const DEFAULT_INTERVAL_HOURS = 24;
22
+ /**
23
+ * Thirty copies — a month of daily history, matching the DO PITR horizon so the two
24
+ * defences expire together rather than leaving a window covered by neither.
25
+ */
26
+ const DEFAULT_RETAIN = 30;
27
+ /**
28
+ * Take a directory backup if one is due, then prune to the retention window.
29
+ *
30
+ * Order matters and is the inverse of the reap's (#493). A reap stores BEFORE it wipes,
31
+ * because the wipe is what the copy protects against. Here the prune runs AFTER a
32
+ * successful put, so a failed capture can never be the thing that deletes the last good
33
+ * copy — the worst case is an extra copy kept, never a missing one.
34
+ *
35
+ * Throws whatever the export or the store threw. The caller (a cron pass) decides what a
36
+ * failure means; it must not be silent, which is why nothing is swallowed here.
37
+ */
38
+ export async function backupDirectoryIfDue(options) {
39
+ const now = options.now?.() ?? new Date();
40
+ const retain = options.retain ?? DEFAULT_RETAIN;
41
+ const intervalMs = (options.intervalHours ?? DEFAULT_INTERVAL_HOURS) * 3_600_000;
42
+ // The store IS the schedule's memory: newest copy, newest first (the store sorts).
43
+ const existing = await options.store.list();
44
+ const newest = existing[0];
45
+ if (!options.force && newest) {
46
+ const age = now.getTime() - new Date(newest.capturedAt).getTime();
47
+ // `age < 0` — a copy stamped in the future, from a clock skew or a hand-uploaded
48
+ // object — counts as fresh. Skipping is the conservative read: taking a copy is
49
+ // cheap, but treating a future timestamp as "infinitely overdue" would take one on
50
+ // every single pass until real time caught up.
51
+ if (age < intervalMs)
52
+ return { taken: null, skippedFor: newest.capturedAt, pruned: 0 };
53
+ }
54
+ const dump = await options.admin.exportDirectory(options.actor);
55
+ const taken = await options.store.put({ dump });
56
+ // Prune from a re-read list, not from `existing`: the copy just written has to be in
57
+ // the reckoning, or a retention window of N would keep N+1 forever.
58
+ let pruned = 0;
59
+ if (retain > 0) {
60
+ const all = await options.store.list();
61
+ for (const stale of all.slice(retain)) {
62
+ await options.store.delete({ capturedAt: stale.capturedAt });
63
+ pruned += 1;
64
+ }
65
+ }
66
+ return { taken, skippedFor: null, pruned };
67
+ }
68
+ //# sourceMappingURL=directory-backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-backup.js","sourceRoot":"","sources":["../src/directory-backup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,0EAA0E;AAC1E,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAClC;;;GAGG;AACH,MAAM,cAAc,GAAG,EAAE,CAAC;AA0B1B;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAA+B;IAE/B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;IAChD,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,sBAAsB,CAAC,GAAG,SAAS,CAAC;IAEjF,mFAAmF;IACnF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,MAAM,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;QAClE,iFAAiF;QACjF,gFAAgF;QAChF,mFAAmF;QACnF,+CAA+C;QAC/C,IAAI,GAAG,GAAG,UAAU;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACzF,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhD,qFAAqF;IACrF,oEAAoE;IACpE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACtC,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;YAC7D,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC"}
package/dist/index.d.ts CHANGED
@@ -18,4 +18,8 @@ export type { CustomHostnameProvisioner, CustomHostnameProvisionerOptions, Custo
18
18
  export type { ObservabilityReader, ServiceMetricsRow, RecentLogEvent } from './observability.js';
19
19
  export { createCfObservabilityReader } from './cf-observability.js';
20
20
  export type { CfObservabilityOptions } from './cf-observability.js';
21
+ export type { ScopeBackup, ScopeBackupStore, DirectoryBackup, DirectoryBackupStore, } from './backups.js';
22
+ export { createR2BackupStore, createR2DirectoryBackupStore } from './r2-backups.js';
23
+ export { backupDirectoryIfDue } from './directory-backup.js';
24
+ export type { DirectoryBackupOptions, DirectoryBackupResult } from './directory-backup.js';
21
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,2BAA2B,EAC3B,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrG,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrG,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAChG,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,+BAA+B,EAC/B,WAAW,EACX,cAAc,EACd,yBAAyB,EACzB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,yBAAyB,EACzB,gCAAgC,EAChC,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,2BAA2B,EAC3B,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrG,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrG,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAChG,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,+BAA+B,EAC/B,WAAW,EACX,cAAc,EACd,yBAAyB,EACzB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,yBAAyB,EACzB,gCAAgC,EAChC,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACpE,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAIpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -9,4 +9,9 @@ export { createWfpUploader, createWfpModulesFetcher, createWfpBindingsPatcher }
9
9
  export { blobStoreBindings, collectBlobStoreHandles, collectTenantStoreHandles, tenantStoreBindings, } from './tenant-stores.js';
10
10
  export { createCustomHostnameProvisioner, mapCfStatus, extractRecords, reconcilePendingHostnames, isCustomHostname, validateBindableHostname, } from './custom-hostnames.js';
11
11
  export { createCfObservabilityReader } from './cf-observability.js';
12
+ export { createR2BackupStore, createR2DirectoryBackupStore } from './r2-backups.js';
13
+ // #40 — the scheduled directory copy. Exported as a function the CP worker's cron calls,
14
+ // not as a route with a timer behind it: this package stays library-only, exactly as the
15
+ // platform-request drain does (the recurrence has to come from a deployment, #444).
16
+ export { backupDirectoryIfDue } from './directory-backup.js';
12
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,2BAA2B,EAC3B,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAUrG,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,GAUvB,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAQhG,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,+BAA+B,EAC/B,WAAW,EACX,cAAc,EACd,yBAAyB,EACzB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,2BAA2B,EAC3B,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAUrG,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,GAUvB,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAQhG,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,+BAA+B,EAC/B,WAAW,EACX,cAAc,EACd,yBAAyB,EACzB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAQpE,OAAO,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AACpF,yFAAyF;AACzF,yFAAyF;AACzF,oFAAoF;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/mask.d.ts CHANGED
@@ -1,4 +1,19 @@
1
1
  import type { ScopeDumpTable } from '@substrat-run/contracts';
2
2
  /** Mask one dump in place-shape (returns new arrays; never mutates the input). */
3
3
  export declare function maskDump(tables: ScopeDumpTable[]): ScopeDumpTable[];
4
+ /**
5
+ * The same heuristic applied to plain JSON records — the directory half of a tenant
6
+ * export (#36).
7
+ *
8
+ * A tenant export carries two kinds of thing: scope databases (table-shaped, masked by
9
+ * `maskDump` above) and directory records (object-shaped — a tenant's display name, an
10
+ * org's name, an identity link's external id, which is usually an email). Both halves
11
+ * must be masked by the SAME rule, or the default-masked promise is only half true and
12
+ * the leak is in the half nobody looked at.
13
+ *
14
+ * So this reuses `maskJsonValue` rather than growing a second heuristic: one PII column
15
+ * list, one recursive sweep, two entry points. Ids and timestamps pass through — the
16
+ * sweep targets free text, and ids are what keep an export intelligible.
17
+ */
18
+ export declare function maskRecords<T>(records: readonly T[]): T[];
4
19
  //# sourceMappingURL=mask.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mask.d.ts","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAoD9D,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAqBnE"}
1
+ {"version":3,"file":"mask.d.ts","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AA2D9D,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAqBnE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAEzD"}
package/dist/mask.js CHANGED
@@ -22,7 +22,14 @@
22
22
  */
23
23
  // Free-text/PII column names. `name` is included on purpose: entity names
24
24
  // (customers, properties, contacts) are customer data even when they look benign.
25
- const PII_COLUMN = /(^|_)(email|e?mail_address|phone|mobile|tel|address|street|city|postal|zip|ssn|personnummer|name|first_name|last_name|full_name|contact|note|notes|comment|comments|message|subject|body|description)($|_)/i;
25
+ //
26
+ // `external_id` earns its place from the platform's OWN schema (#36): an identity link's
27
+ // `externalId` is the provider's subject, which in practice is very often the person's
28
+ // email address — so a tenant export that swept only the obvious columns would hand out
29
+ // the one field most likely to name a human. It is the deliberately lossy direction of
30
+ // the trade: an opaque third-party id (a document ref, an upstream order number) gets
31
+ // masked too, which costs a masked pull some fidelity and costs a leak nothing.
32
+ const PII_COLUMN = /(^|_)(email|e?mail_address|phone|mobile|tel|address|street|city|postal|zip|ssn|personnummer|name|first_name|last_name|full_name|contact|external_id|note|notes|comment|comments|message|subject|body|description)($|_)/i;
26
33
  // Columns that carry JSON documents worth sweeping by key rather than blanking.
27
34
  const JSON_COLUMN = /(^|_)(payload|detail|details|data|before|after)($|_)/i;
28
35
  const MASKED = '[masked]';
@@ -68,4 +75,21 @@ export function maskDump(tables) {
68
75
  return { ...t, rows };
69
76
  });
70
77
  }
78
+ /**
79
+ * The same heuristic applied to plain JSON records — the directory half of a tenant
80
+ * export (#36).
81
+ *
82
+ * A tenant export carries two kinds of thing: scope databases (table-shaped, masked by
83
+ * `maskDump` above) and directory records (object-shaped — a tenant's display name, an
84
+ * org's name, an identity link's external id, which is usually an email). Both halves
85
+ * must be masked by the SAME rule, or the default-masked promise is only half true and
86
+ * the leak is in the half nobody looked at.
87
+ *
88
+ * So this reuses `maskJsonValue` rather than growing a second heuristic: one PII column
89
+ * list, one recursive sweep, two entry points. Ids and timestamps pass through — the
90
+ * sweep targets free text, and ids are what keep an export intelligible.
91
+ */
92
+ export function maskRecords(records) {
93
+ return records.map((r) => maskJsonValue(r, false));
94
+ }
71
95
  //# sourceMappingURL=mask.js.map
package/dist/mask.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mask.js","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,0EAA0E;AAC1E,kFAAkF;AAClF,MAAM,UAAU,GAAG,6MAA6M,CAAC;AAEjO,gFAAgF;AAChF,MAAM,WAAW,GAAG,uDAAuD,CAAC;AAE5E,MAAM,MAAM,GAAG,UAAU,CAAC;AAE1B,iFAAiF;AACjF,iFAAiF;AACjF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE,CAC3C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAAC;AAE/D,SAAS,aAAa,CAAC,KAAc,EAAE,UAAmB;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;IAChF,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YACtE,GAAG,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,EAAE,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,QAAQ,CAAC,MAAwB;IAC/C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACtB,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC9B,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YAClB,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC1C,IAAI,OAAO,CAAC,CAAC,CAAC;gBAAE,OAAO,MAAM,CAAC;YAC9B,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;gBAChE,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,IAAI,CAAC,CAAC,6DAA6D;gBAC5E,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CACH,CAAC;QACF,OAAO,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"mask.js","sourceRoot":"","sources":["../src/mask.ts"],"names":[],"mappings":"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"}