@bjornpagen/bumbledb-log 0.20.2 → 1.0.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/README.md +275 -114
- package/dist/admin.d.ts +24 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +12 -0
- package/dist/admin.js.map +1 -0
- package/dist/bridge.d.ts +30 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +92 -0
- package/dist/bridge.js.map +1 -0
- package/dist/codes.d.ts +11 -0
- package/dist/codes.d.ts.map +1 -0
- package/dist/codes.js +53 -0
- package/dist/codes.js.map +1 -0
- package/dist/command.d.ts +21 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +12 -0
- package/dist/command.js.map +1 -0
- package/dist/errors.d.ts +78 -197
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +144 -114
- package/dist/errors.js.map +1 -1
- package/dist/history.d.ts +22 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +12 -0
- package/dist/history.js.map +1 -0
- package/dist/identity.d.ts +144 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +223 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +24 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -21
- package/dist/index.js.map +1 -1
- package/dist/machine.d.ts +151 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +1128 -0
- package/dist/machine.js.map +1 -0
- package/dist/migration-ops.d.ts +20 -0
- package/dist/migration-ops.d.ts.map +1 -0
- package/dist/migration-ops.js +7 -0
- package/dist/migration-ops.js.map +1 -0
- package/dist/migrations/bin.d.ts +3 -0
- package/dist/migrations/bin.d.ts.map +1 -0
- package/dist/migrations/bin.js +43 -0
- package/dist/migrations/bin.js.map +1 -0
- package/dist/migrations/canonical.d.ts +40 -0
- package/dist/migrations/canonical.d.ts.map +1 -0
- package/dist/migrations/canonical.js +156 -0
- package/dist/migrations/canonical.js.map +1 -0
- package/dist/migrations/cli.d.ts +32 -0
- package/dist/migrations/cli.d.ts.map +1 -0
- package/dist/migrations/cli.js +147 -0
- package/dist/migrations/cli.js.map +1 -0
- package/dist/migrations/codec.d.ts +74 -0
- package/dist/migrations/codec.d.ts.map +1 -0
- package/dist/migrations/codec.js +2 -0
- package/dist/migrations/codec.js.map +1 -0
- package/dist/migrations/decode.d.ts +16 -0
- package/dist/migrations/decode.d.ts.map +1 -0
- package/dist/migrations/decode.js +302 -0
- package/dist/migrations/decode.js.map +1 -0
- package/dist/migrations/diff.d.ts +39 -0
- package/dist/migrations/diff.d.ts.map +1 -0
- package/dist/migrations/diff.js +385 -0
- package/dist/migrations/diff.js.map +1 -0
- package/dist/migrations/expr.d.ts +22 -0
- package/dist/migrations/expr.d.ts.map +1 -0
- package/dist/migrations/expr.js +228 -0
- package/dist/migrations/expr.js.map +1 -0
- package/dist/migrations/fail.d.ts +34 -0
- package/dist/migrations/fail.d.ts.map +1 -0
- package/dist/migrations/fail.js +69 -0
- package/dist/migrations/fail.js.map +1 -0
- package/dist/migrations/fsops.d.ts +37 -0
- package/dist/migrations/fsops.d.ts.map +1 -0
- package/dist/migrations/fsops.js +222 -0
- package/dist/migrations/fsops.js.map +1 -0
- package/dist/migrations/generate.d.ts +11 -0
- package/dist/migrations/generate.d.ts.map +1 -0
- package/dist/migrations/generate.js +479 -0
- package/dist/migrations/generate.js.map +1 -0
- package/dist/migrations/index.d.ts +25 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +6 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/intent.d.ts +86 -0
- package/dist/migrations/intent.d.ts.map +1 -0
- package/dist/migrations/intent.js +97 -0
- package/dist/migrations/intent.js.map +1 -0
- package/dist/migrations/lock.d.ts +27 -0
- package/dist/migrations/lock.d.ts.map +1 -0
- package/dist/migrations/lock.js +14 -0
- package/dist/migrations/lock.js.map +1 -0
- package/dist/migrations/native.d.ts +37 -0
- package/dist/migrations/native.d.ts.map +1 -0
- package/dist/migrations/native.js +135 -0
- package/dist/migrations/native.js.map +1 -0
- package/dist/migrations/repo.d.ts +38 -0
- package/dist/migrations/repo.d.ts.map +1 -0
- package/dist/migrations/repo.js +191 -0
- package/dist/migrations/repo.js.map +1 -0
- package/dist/migrations/theory.d.ts +21 -0
- package/dist/migrations/theory.d.ts.map +1 -0
- package/dist/migrations/theory.js +107 -0
- package/dist/migrations/theory.js.map +1 -0
- package/dist/migrations/types.d.ts +243 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +2 -0
- package/dist/migrations/types.js.map +1 -0
- package/dist/migrations/workflow.d.ts +11 -0
- package/dist/migrations/workflow.d.ts.map +1 -0
- package/dist/migrations/workflow.js +14 -0
- package/dist/migrations/workflow.js.map +1 -0
- package/dist/native.d.ts +600 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +8 -0
- package/dist/native.js.map +1 -0
- package/dist/options.d.ts +106 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +2 -0
- package/dist/options.js.map +1 -0
- package/dist/outcome.d.ts +291 -0
- package/dist/outcome.d.ts.map +1 -0
- package/dist/outcome.js +2 -0
- package/dist/outcome.js.map +1 -0
- package/dist/production.d.ts +12 -0
- package/dist/production.d.ts.map +1 -0
- package/dist/production.js +29 -0
- package/dist/production.js.map +1 -0
- package/dist/schema.d.ts +10 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +9 -0
- package/dist/schema.js.map +1 -0
- package/dist/surface.d.ts +80 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +2 -0
- package/dist/surface.js.map +1 -0
- package/dist/tenants.d.ts +20 -52
- package/dist/tenants.d.ts.map +1 -1
- package/dist/tenants.js +11 -330
- package/dist/tenants.js.map +1 -1
- package/pack-provenance.json +7 -0
- package/package.json +20 -23
- package/dist/braids.d.ts +0 -28
- package/dist/braids.d.ts.map +0 -1
- package/dist/braids.js +0 -45
- package/dist/braids.js.map +0 -1
- package/dist/bytes.d.ts +0 -26
- package/dist/bytes.d.ts.map +0 -1
- package/dist/bytes.js +0 -86
- package/dist/bytes.js.map +0 -1
- package/dist/chain.d.ts +0 -56
- package/dist/chain.d.ts.map +0 -1
- package/dist/chain.js +0 -137
- package/dist/chain.js.map +0 -1
- package/dist/codec.d.ts +0 -71
- package/dist/codec.d.ts.map +0 -1
- package/dist/codec.js +0 -179
- package/dist/codec.js.map +0 -1
- package/dist/descriptor.d.ts +0 -61
- package/dist/descriptor.d.ts.map +0 -1
- package/dist/descriptor.js +0 -160
- package/dist/descriptor.js.map +0 -1
- package/dist/keys.d.ts +0 -52
- package/dist/keys.d.ts.map +0 -1
- package/dist/keys.js +0 -166
- package/dist/keys.js.map +0 -1
- package/dist/manifest.d.ts +0 -42
- package/dist/manifest.d.ts.map +0 -1
- package/dist/manifest.js +0 -116
- package/dist/manifest.js.map +0 -1
- package/dist/replica.d.ts +0 -154
- package/dist/replica.d.ts.map +0 -1
- package/dist/replica.js +0 -820
- package/dist/replica.js.map +0 -1
- package/dist/store-s3.d.ts +0 -31
- package/dist/store-s3.d.ts.map +0 -1
- package/dist/store-s3.js +0 -299
- package/dist/store-s3.js.map +0 -1
- package/dist/store.d.ts +0 -129
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -577
- package/dist/store.js.map +0 -1
- package/dist/tilde-family.json +0 -21
- package/dist/vector.d.ts +0 -31
- package/dist/vector.d.ts.map +0 -1
- package/dist/vector.js +0 -87
- package/dist/vector.js.map +0 -1
- package/dist/writer.d.ts +0 -106
- package/dist/writer.d.ts.map +0 -1
- package/dist/writer.js +0 -677
- package/dist/writer.js.map +0 -1
package/dist/machine.js
ADDED
|
@@ -0,0 +1,1128 @@
|
|
|
1
|
+
import { Uuid } from "@bjornpagen/bumbledb";
|
|
2
|
+
import { policyWire } from "@bjornpagen/bumbledb/internal/log";
|
|
3
|
+
import { Effect, Result } from "effect";
|
|
4
|
+
import { certaintyOperation, closeReportOf, drainClose, logOperation, scopedResource } from "#bridge.ts";
|
|
5
|
+
import { closedHandle, invalidInput, logFailure } from "#errors.ts";
|
|
6
|
+
// ── Trusted-native decode: branding data from the typed addon boundary ─────
|
|
7
|
+
// The binding declaration is the trust boundary (as in the core's
|
|
8
|
+
// runtime-native.ts); user input never flows through these.
|
|
9
|
+
function identityOf(wire) {
|
|
10
|
+
return {
|
|
11
|
+
databaseId: wire.databaseId,
|
|
12
|
+
incarnationId: wire.incarnationId,
|
|
13
|
+
schemaId: wire.schemaId
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function stampOf(wire) {
|
|
17
|
+
return { seq: wire.seq, hash: wire.hash };
|
|
18
|
+
}
|
|
19
|
+
function stateOf(wire) {
|
|
20
|
+
return { incarnation: wire.incarnation, dataRevision: wire.dataRevision };
|
|
21
|
+
}
|
|
22
|
+
function freshnessOf(wire) {
|
|
23
|
+
if (wire.kind === "at-least") {
|
|
24
|
+
return { kind: "at-least", requested: stampOf(wire.requested) };
|
|
25
|
+
}
|
|
26
|
+
return { kind: wire.kind };
|
|
27
|
+
}
|
|
28
|
+
function refOf(wire) {
|
|
29
|
+
return {
|
|
30
|
+
identity: identityOf(wire.identity),
|
|
31
|
+
id: {
|
|
32
|
+
receiptEpoch: wire.receiptEpoch,
|
|
33
|
+
requestId: wire.requestId
|
|
34
|
+
},
|
|
35
|
+
digest: wire.digest
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function resultOf(wire) {
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const [key, value] of Object.entries(wire)) {
|
|
41
|
+
out[key] = value;
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
function outcomeOf(wire) {
|
|
46
|
+
switch (wire.kind) {
|
|
47
|
+
case "committed":
|
|
48
|
+
return {
|
|
49
|
+
kind: "committed",
|
|
50
|
+
changed: { added: wire.added, removed: wire.removed },
|
|
51
|
+
result: resultOf(wire.result)
|
|
52
|
+
};
|
|
53
|
+
case "no-change":
|
|
54
|
+
return { kind: "no-change", result: resultOf(wire.result) };
|
|
55
|
+
case "precondition-failed":
|
|
56
|
+
return {
|
|
57
|
+
kind: "precondition-failed",
|
|
58
|
+
expected: stateOf(wire.expected),
|
|
59
|
+
observed: stateOf(wire.observed)
|
|
60
|
+
};
|
|
61
|
+
case "invariant-rejected":
|
|
62
|
+
return { kind: "invariant-rejected", violations: wire.violations };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function receiptOf(wire) {
|
|
66
|
+
return {
|
|
67
|
+
command: refOf(wire.command),
|
|
68
|
+
decisionAt: stampOf(wire.decisionAt),
|
|
69
|
+
stateAt: stateOf(wire.stateAt),
|
|
70
|
+
outcome: outcomeOf(wire.outcome)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function errorOf(operation, wire) {
|
|
74
|
+
return logFailure(operation, wire);
|
|
75
|
+
}
|
|
76
|
+
function healthOf(operation, wire) {
|
|
77
|
+
if (wire.kind === "ready") {
|
|
78
|
+
return { kind: "ready", at: stampOf(wire.at) };
|
|
79
|
+
}
|
|
80
|
+
return { kind: "unavailable", error: errorOf(operation, wire.error) };
|
|
81
|
+
}
|
|
82
|
+
function phaseOf(operation, wire) {
|
|
83
|
+
switch (wire) {
|
|
84
|
+
case "prepared":
|
|
85
|
+
case "dispatchedUnresolved":
|
|
86
|
+
case "confirmed":
|
|
87
|
+
case "provedNonpublication":
|
|
88
|
+
return wire;
|
|
89
|
+
default:
|
|
90
|
+
throw invalidInput(operation);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function inspectionOf(wire) {
|
|
94
|
+
return {
|
|
95
|
+
identity: identityOf(wire.identity),
|
|
96
|
+
accessMode: wire.accessMode,
|
|
97
|
+
headRevision: wire.headRevision,
|
|
98
|
+
decision: stampOf(wire.decision),
|
|
99
|
+
state: stateOf(wire.state),
|
|
100
|
+
receipts: {
|
|
101
|
+
openEpoch: wire.openEpoch,
|
|
102
|
+
retiredThrough: wire.retiredThrough
|
|
103
|
+
},
|
|
104
|
+
tail: { count: wire.tailCount, bytes: wire.tailBytes },
|
|
105
|
+
unknownCommands: { count: wire.unknownCount, oldestMillis: wire.unknownOldestMillis },
|
|
106
|
+
roots: { count: wire.rootCount, capacity: wire.rootCapacity },
|
|
107
|
+
gc: wire.gc,
|
|
108
|
+
lastMaintenanceError: wire.lastMaintenanceError,
|
|
109
|
+
accounted: { diskBytes: wire.diskBytes, workingBytes: wire.workingBytes },
|
|
110
|
+
operations: { queued: wire.queued, active: wire.active }
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function cacheInspectionOf(wire) {
|
|
114
|
+
return {
|
|
115
|
+
openCount: wire.openCount,
|
|
116
|
+
opening: wire.opening,
|
|
117
|
+
budget: { bytes: wire.budgetBytes, maxOpen: wire.maxOpen },
|
|
118
|
+
evictions: wire.evictions,
|
|
119
|
+
slots: wire.slots.map((slot) => ({
|
|
120
|
+
binding: slot.binding,
|
|
121
|
+
state: slot.state,
|
|
122
|
+
borrows: slot.borrows,
|
|
123
|
+
diskBytes: slot.diskBytes
|
|
124
|
+
}))
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ── Checked outbound wire conversion (caller input; refuses, never casts) ──
|
|
128
|
+
function checkedString(operation, value, maxLength) {
|
|
129
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
|
|
130
|
+
throw invalidInput(operation);
|
|
131
|
+
}
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
function checkedUuid(operation, value) {
|
|
135
|
+
if (!Uuid.isUuid(value)) {
|
|
136
|
+
throw invalidInput(operation);
|
|
137
|
+
}
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
function identityWire(operation, identity) {
|
|
141
|
+
return {
|
|
142
|
+
databaseId: checkedUuid(operation, identity.databaseId),
|
|
143
|
+
incarnationId: checkedUuid(operation, identity.incarnationId),
|
|
144
|
+
schemaId: checkedString(operation, String(identity.schemaId), 64)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function credentialsWire(operation, credentials) {
|
|
148
|
+
if (credentials === undefined || credentials.kind === "provider-chain") {
|
|
149
|
+
return { kind: "provider-chain" };
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
kind: "static",
|
|
153
|
+
accessKeyId: checkedString(operation, credentials.accessKeyId, 256),
|
|
154
|
+
secretAccessKey: checkedString(operation, credentials.secretAccessKey, 256),
|
|
155
|
+
sessionToken: credentials.sessionToken === undefined ? null : checkedString(operation, credentials.sessionToken, 4096)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function bindingWire(operation, binding) {
|
|
159
|
+
if (binding.kind === "local") {
|
|
160
|
+
return {
|
|
161
|
+
kind: "local",
|
|
162
|
+
directory: checkedString(operation, binding.directory, 4096),
|
|
163
|
+
identity: identityWire(operation, binding.identity)
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (binding.kind !== "hosted") {
|
|
167
|
+
throw invalidInput(operation);
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
kind: "hosted",
|
|
171
|
+
directory: checkedString(operation, binding.directory, 4096),
|
|
172
|
+
bucket: checkedString(operation, binding.origin.bucket, 255),
|
|
173
|
+
prefix: checkedString(operation, binding.origin.prefix, 1024),
|
|
174
|
+
region: binding.origin.region === undefined ? null : checkedString(operation, binding.origin.region, 64),
|
|
175
|
+
identity: identityWire(operation, binding.identity),
|
|
176
|
+
credentials: credentialsWire(operation, binding.credentials)
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function bindingOf(wire) {
|
|
180
|
+
if (wire.kind === "local") {
|
|
181
|
+
return { kind: "local", directory: wire.directory, identity: identityOf(wire.identity) };
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
kind: "hosted",
|
|
185
|
+
directory: wire.directory,
|
|
186
|
+
origin: {
|
|
187
|
+
bucket: wire.bucket,
|
|
188
|
+
prefix: wire.prefix,
|
|
189
|
+
...(wire.region === null ? {} : { region: wire.region })
|
|
190
|
+
},
|
|
191
|
+
identity: identityOf(wire.identity),
|
|
192
|
+
credentials: { kind: "provider-chain" }
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function consistencyWire(operation, options) {
|
|
196
|
+
const consistency = options.consistency;
|
|
197
|
+
if (consistency.kind === "cached" || consistency.kind === "latest") {
|
|
198
|
+
return { kind: consistency.kind };
|
|
199
|
+
}
|
|
200
|
+
if (consistency.kind !== "at-least") {
|
|
201
|
+
throw invalidInput(operation);
|
|
202
|
+
}
|
|
203
|
+
// Checked outbound: the requested stamp is caller input. The hash is the
|
|
204
|
+
// exact 64-hex decision digest the native ancestry witness validates —
|
|
205
|
+
// AtLeast is never a bare sequence floor, so a malformed stamp refuses
|
|
206
|
+
// HERE, before dispatch.
|
|
207
|
+
if (typeof consistency.at.seq !== "bigint" || consistency.at.seq < 0n) {
|
|
208
|
+
throw invalidInput(operation);
|
|
209
|
+
}
|
|
210
|
+
return { kind: "at-least", seq: consistency.at.seq, hash: checkedString(operation, consistency.at.hash, 64) };
|
|
211
|
+
}
|
|
212
|
+
function refWire(operation, ref) {
|
|
213
|
+
return {
|
|
214
|
+
identity: identityWire(operation, ref.identity),
|
|
215
|
+
receiptEpoch: ref.id.receiptEpoch,
|
|
216
|
+
requestId: checkedUuid(operation, ref.id.requestId),
|
|
217
|
+
digest: checkedString(operation, ref.digest, 64)
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function scalarOk(value) {
|
|
221
|
+
const kind = typeof value;
|
|
222
|
+
if (kind === "bigint" || kind === "number" || kind === "string" || kind === "boolean") {
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
return value instanceof Uint8Array && value.buffer instanceof ArrayBuffer;
|
|
226
|
+
}
|
|
227
|
+
function resultWire(operation, result) {
|
|
228
|
+
const out = {};
|
|
229
|
+
const entries = Object.entries(result);
|
|
230
|
+
if (entries.length > 64) {
|
|
231
|
+
throw invalidInput(operation);
|
|
232
|
+
}
|
|
233
|
+
for (const [key, value] of entries) {
|
|
234
|
+
checkedString(operation, key, 128);
|
|
235
|
+
if (!scalarOk(value)) {
|
|
236
|
+
throw invalidInput(operation);
|
|
237
|
+
}
|
|
238
|
+
// The canonical result cell splits bigints at the sign: nonnegative is
|
|
239
|
+
// U64 (tag 1), negative is I64 (tag 2); anything outside those widths
|
|
240
|
+
// refuses HERE, before dispatch, never as a mid-marshal native throw.
|
|
241
|
+
if (typeof value === "bigint" && (value >= 1n << 64n || value < -(1n << 63n))) {
|
|
242
|
+
throw invalidInput(operation);
|
|
243
|
+
}
|
|
244
|
+
out[key] = value;
|
|
245
|
+
}
|
|
246
|
+
return out;
|
|
247
|
+
}
|
|
248
|
+
function preconditionWire(operation, precondition) {
|
|
249
|
+
if (precondition.kind === "blind") {
|
|
250
|
+
return { kind: "blind" };
|
|
251
|
+
}
|
|
252
|
+
if (precondition.kind !== "exact-state") {
|
|
253
|
+
throw invalidInput(operation);
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
kind: "exact-state",
|
|
257
|
+
incarnation: checkedUuid(operation, precondition.at.incarnation),
|
|
258
|
+
dataRevision: precondition.at.dataRevision
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function checkedCount(operation, value, max) {
|
|
262
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > max) {
|
|
263
|
+
throw invalidInput(operation);
|
|
264
|
+
}
|
|
265
|
+
return value;
|
|
266
|
+
}
|
|
267
|
+
function checkedNonNegative(operation, value, max) {
|
|
268
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > max) {
|
|
269
|
+
throw invalidInput(operation);
|
|
270
|
+
}
|
|
271
|
+
return value;
|
|
272
|
+
}
|
|
273
|
+
function creationWire(operation, creation) {
|
|
274
|
+
if (!(creation.artifact instanceof Uint8Array) || !(creation.artifact.buffer instanceof ArrayBuffer)) {
|
|
275
|
+
throw invalidInput(operation);
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
operationId: checkedUuid(operation, creation.operationId),
|
|
279
|
+
artifact: creation.artifact
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function snapshotsField(operation, plans) {
|
|
283
|
+
// Base schema snapshot first, then each entry's target: entries + 1 rows.
|
|
284
|
+
// Empty source still supplies the empty-schema render — never optional.
|
|
285
|
+
if (!Array.isArray(plans.snapshots) || plans.snapshots.length !== plans.manifest.entries.length + 1) {
|
|
286
|
+
throw invalidInput(operation);
|
|
287
|
+
}
|
|
288
|
+
return { snapshots: plans.snapshots.map((snapshot) => checkedString(operation, snapshot, 4 << 20)) };
|
|
289
|
+
}
|
|
290
|
+
function plansWire(operation, plans) {
|
|
291
|
+
if (plans.manifest.entries.length !== plans.plans.length || plans.manifest.entries.length > 4096) {
|
|
292
|
+
throw invalidInput(operation);
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
...snapshotsField(operation, plans),
|
|
296
|
+
manifestVersion: checkedNonNegative(operation, plans.manifest.manifestVersion, 0xffff),
|
|
297
|
+
planVersion: checkedNonNegative(operation, plans.manifest.planVersion, 0xffff),
|
|
298
|
+
baseSchemaId: checkedString(operation, plans.manifest.baseSchemaId, 64),
|
|
299
|
+
basePrefixDigest: checkedString(operation, plans.manifest.basePrefixDigest, 64),
|
|
300
|
+
entries: plans.manifest.entries.map((entry) => ({
|
|
301
|
+
sequence: checkedString(operation, entry.sequence, 20),
|
|
302
|
+
id: checkedString(operation, entry.id, 64),
|
|
303
|
+
fromSchemaId: checkedString(operation, entry.fromSchemaId, 64),
|
|
304
|
+
toSchemaId: checkedString(operation, entry.toSchemaId, 64),
|
|
305
|
+
planDigest: checkedString(operation, entry.planDigest, 64),
|
|
306
|
+
prefixDigest: checkedString(operation, entry.prefixDigest, 64)
|
|
307
|
+
})),
|
|
308
|
+
// Inert canonical transport of the generated plan data; the native
|
|
309
|
+
// migration codec is the one canonicalization/digest authority.
|
|
310
|
+
plans: plans.plans.map((plan) => JSON.stringify(plan))
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
export function makeLogMachine(wire, core) {
|
|
314
|
+
const cancel = (operation, callback) => wire.runtimeCancel(operation, callback);
|
|
315
|
+
const commandEntries = new WeakMap();
|
|
316
|
+
function makeCommand(cw) {
|
|
317
|
+
const state = { closed: false };
|
|
318
|
+
const command = {
|
|
319
|
+
ref: refOf(cw.ref),
|
|
320
|
+
close: () => Effect.suspend(() => {
|
|
321
|
+
state.closed = true;
|
|
322
|
+
return drainClose("Command.close", (callback) => wire.logCommandClose(cw.command, callback));
|
|
323
|
+
})
|
|
324
|
+
};
|
|
325
|
+
commandEntries.set(command, { handle: cw.command, state });
|
|
326
|
+
return command;
|
|
327
|
+
}
|
|
328
|
+
function makeSnapshot(schema, snapshot, provenance) {
|
|
329
|
+
const capability = core.reader(snapshot, schema);
|
|
330
|
+
return {
|
|
331
|
+
identity: identityOf(provenance.identity),
|
|
332
|
+
decisionStamp: stampOf(provenance.decision),
|
|
333
|
+
stateStamp: stateOf(provenance.state),
|
|
334
|
+
freshness: freshnessOf(provenance.freshness),
|
|
335
|
+
get: capability.get,
|
|
336
|
+
execute: capability.execute,
|
|
337
|
+
session: capability.session,
|
|
338
|
+
close: () => drainClose("PublishedSnapshot.close", (callback) => wire.runtimeSnapshotClose(snapshot, callback))
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function decodeSubmit(operation, ref, result) {
|
|
342
|
+
if (result.verb !== "submit") {
|
|
343
|
+
throw invalidInput(operation);
|
|
344
|
+
}
|
|
345
|
+
const outcome = result.outcome;
|
|
346
|
+
switch (outcome.kind) {
|
|
347
|
+
case "decided":
|
|
348
|
+
return {
|
|
349
|
+
kind: "decided",
|
|
350
|
+
receipt: receiptOf(outcome.receipt),
|
|
351
|
+
localHealth: healthOf(operation, outcome.localHealth),
|
|
352
|
+
phase: phaseOf(operation, outcome.publicationPhase)
|
|
353
|
+
};
|
|
354
|
+
case "not-submitted":
|
|
355
|
+
return {
|
|
356
|
+
kind: "not-submitted",
|
|
357
|
+
command: ref,
|
|
358
|
+
error: errorOf(operation, outcome.error),
|
|
359
|
+
phase: phaseOf(operation, outcome.publicationPhase)
|
|
360
|
+
};
|
|
361
|
+
case "outcome-unknown":
|
|
362
|
+
return {
|
|
363
|
+
kind: "outcome-unknown",
|
|
364
|
+
command: ref,
|
|
365
|
+
error: errorOf(operation, outcome.error),
|
|
366
|
+
phase: phaseOf(operation, outcome.publicationPhase)
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function decodeResolve(operation, result) {
|
|
371
|
+
if (result.verb !== "resolve") {
|
|
372
|
+
throw invalidInput(operation);
|
|
373
|
+
}
|
|
374
|
+
switch (result.outcome.kind) {
|
|
375
|
+
case "found":
|
|
376
|
+
return { kind: "found", receipt: receiptOf(result.outcome.receipt) };
|
|
377
|
+
case "not-recorded-at":
|
|
378
|
+
return { kind: "not-recorded-at", decisionAt: stampOf(result.outcome.decisionAt) };
|
|
379
|
+
case "command-epoch-closed":
|
|
380
|
+
return { kind: "command-epoch-closed" };
|
|
381
|
+
case "receipt-expired-unknown":
|
|
382
|
+
return { kind: "receipt-expired-unknown" };
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function makeFacadeMembers(schema, capability, meta, state) {
|
|
386
|
+
const identity = identityOf(meta.identity);
|
|
387
|
+
const receiptEpoch = meta.receiptEpoch;
|
|
388
|
+
function call(operation, work, request, accept) {
|
|
389
|
+
return Effect.suspend(() => {
|
|
390
|
+
if (state.closed) {
|
|
391
|
+
return Effect.fail(closedHandle(operation));
|
|
392
|
+
}
|
|
393
|
+
return logOperation(operation, cancel, (callback) => wire.logHistoryCall(capability, policyWire(work, operation), request, callback), wire.logHistoryResult, accept);
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
identity,
|
|
398
|
+
receiptEpoch,
|
|
399
|
+
snapshot(options) {
|
|
400
|
+
const operation = "History.snapshot";
|
|
401
|
+
const acquire = Effect.suspend(() => {
|
|
402
|
+
let request;
|
|
403
|
+
try {
|
|
404
|
+
request = { verb: "snapshot", consistency: consistencyWire(operation, options) };
|
|
405
|
+
}
|
|
406
|
+
catch (cause) {
|
|
407
|
+
return Effect.fail(logFailure(operation, cause));
|
|
408
|
+
}
|
|
409
|
+
return call(operation, options, request, (result) => {
|
|
410
|
+
if (result.verb !== "snapshot") {
|
|
411
|
+
throw invalidInput(operation);
|
|
412
|
+
}
|
|
413
|
+
return makeSnapshot(schema, result.snapshot, result.provenance);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
return scopedResource(operation, acquire, (snapshot) => snapshot.close());
|
|
417
|
+
},
|
|
418
|
+
submit(command, options) {
|
|
419
|
+
const operation = "History.submit";
|
|
420
|
+
return Effect.suspend(() => {
|
|
421
|
+
const entry = commandEntries.get(command);
|
|
422
|
+
if (entry === undefined) {
|
|
423
|
+
// A forged capability with no authentic ref is misuse: a defect,
|
|
424
|
+
// never a fabricated certainty arm or a forged receipt.
|
|
425
|
+
return Effect.die(invalidInput(operation));
|
|
426
|
+
}
|
|
427
|
+
const ref = command.ref;
|
|
428
|
+
// Identity is this sealed ref. Interrupt after dispatch is
|
|
429
|
+
// outcome-unknown under `ref`; retry resolve/resubmit here,
|
|
430
|
+
// never Command.seal of a newly minted id.
|
|
431
|
+
if (state.closed || entry.state.closed) {
|
|
432
|
+
return Effect.succeed({
|
|
433
|
+
kind: "not-submitted",
|
|
434
|
+
command: ref,
|
|
435
|
+
error: closedHandle(operation),
|
|
436
|
+
phase: "prepared"
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
return certaintyOperation(operation, cancel, (callback) => wire.logHistoryCall(capability, policyWire(options, operation), {
|
|
440
|
+
verb: "submit",
|
|
441
|
+
command: entry.handle,
|
|
442
|
+
attempts: checkedCount(operation, options.attempts, 0xffff),
|
|
443
|
+
backoffBaseMillis: checkedNonNegative(operation, options.backoff.baseMillis, 0xffffffff),
|
|
444
|
+
backoffCapMillis: checkedNonNegative(operation, options.backoff.capMillis, 0xffffffff)
|
|
445
|
+
}, callback), wire.logHistoryResult, (result) => decodeSubmit(operation, ref, result), (error) => ({
|
|
446
|
+
kind: "not-submitted",
|
|
447
|
+
command: ref,
|
|
448
|
+
error,
|
|
449
|
+
phase: "prepared"
|
|
450
|
+
}), (error) => ({
|
|
451
|
+
kind: "outcome-unknown",
|
|
452
|
+
command: ref,
|
|
453
|
+
error,
|
|
454
|
+
phase: "dispatchedUnresolved"
|
|
455
|
+
}));
|
|
456
|
+
});
|
|
457
|
+
},
|
|
458
|
+
resolve(ref, work) {
|
|
459
|
+
const operation = "History.resolve";
|
|
460
|
+
return Effect.suspend(() => {
|
|
461
|
+
let wireRef;
|
|
462
|
+
try {
|
|
463
|
+
wireRef = refWire(operation, ref);
|
|
464
|
+
}
|
|
465
|
+
catch (cause) {
|
|
466
|
+
return Effect.fail(logFailure(operation, cause));
|
|
467
|
+
}
|
|
468
|
+
return call(operation, work, { verb: "resolve", ref: wireRef }, (result) => decodeResolve(operation, result));
|
|
469
|
+
});
|
|
470
|
+
},
|
|
471
|
+
inspect(work) {
|
|
472
|
+
const operation = "History.inspect";
|
|
473
|
+
return call(operation, work, { verb: "inspect" }, (result) => {
|
|
474
|
+
if (result.verb !== "inspect") {
|
|
475
|
+
throw invalidInput(operation);
|
|
476
|
+
}
|
|
477
|
+
return inspectionOf(result.inspection);
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function makeHistory(schema, handle) {
|
|
483
|
+
const state = { closed: false };
|
|
484
|
+
const members = makeFacadeMembers(schema, handle.history, handle.meta, state);
|
|
485
|
+
return {
|
|
486
|
+
...members,
|
|
487
|
+
close: () => Effect.suspend(() => {
|
|
488
|
+
state.closed = true;
|
|
489
|
+
return drainClose("History.close", (callback) => wire.logHistoryClose(handle.history, callback));
|
|
490
|
+
})
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function makeBorrow(schema, handle) {
|
|
494
|
+
const state = { closed: false };
|
|
495
|
+
const members = makeFacadeMembers(schema, handle.history, handle.meta, state);
|
|
496
|
+
return {
|
|
497
|
+
...members,
|
|
498
|
+
release: () => Effect.suspend(() => {
|
|
499
|
+
state.closed = true;
|
|
500
|
+
return drainClose("HistoryBorrow.release", (callback) => wire.logBorrowRelease(handle.history, callback));
|
|
501
|
+
})
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function openHistory(operation, kind, mode, binding, schema, options) {
|
|
505
|
+
return Effect.gen(function* () {
|
|
506
|
+
const runtime = yield* core.runtime();
|
|
507
|
+
const acquire = Effect.suspend(() => {
|
|
508
|
+
if (binding.kind !== kind) {
|
|
509
|
+
return Effect.fail(invalidInput(operation));
|
|
510
|
+
}
|
|
511
|
+
if (mode === "create" && options.creation === undefined) {
|
|
512
|
+
return Effect.fail(invalidInput(operation));
|
|
513
|
+
}
|
|
514
|
+
return logOperation(operation, cancel, (callback) => wire.logHistoryOpen(runtime, policyWire(options, operation), {
|
|
515
|
+
mode,
|
|
516
|
+
binding: bindingWire(operation, binding),
|
|
517
|
+
schema: core.schemaSpec(schema),
|
|
518
|
+
discardMismatchedCache: "discardMismatchedCache" in options ? options.discardMismatchedCache === true : false,
|
|
519
|
+
creation: options.creation === undefined ? null : creationWire(operation, options.creation)
|
|
520
|
+
}, callback), wire.logHistoryTake, (handle) => makeHistory(schema, handle));
|
|
521
|
+
});
|
|
522
|
+
return yield* scopedResource(operation, acquire, (history) => history.close());
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
const LocalHistory = {
|
|
526
|
+
open: (binding, schema, options) => openHistory("LocalHistory.open", "local", "open", binding, schema, options),
|
|
527
|
+
create: (binding, schema, options) => openHistory("LocalHistory.create", "local", "create", binding, schema, options)
|
|
528
|
+
};
|
|
529
|
+
const HostedHistory = {
|
|
530
|
+
open: (binding, schema, options) => openHistory("HostedHistory.open", "hosted", "open", binding, schema, options),
|
|
531
|
+
create: (binding, schema, options) => openHistory("HostedHistory.create", "hosted", "create", binding, schema, options)
|
|
532
|
+
};
|
|
533
|
+
const CommandNamespace = {
|
|
534
|
+
seal(input, work) {
|
|
535
|
+
const operation = "Command.seal";
|
|
536
|
+
const acquire = Effect.suspend(() => {
|
|
537
|
+
// The exact core registry accessor: a foreign dynamic object
|
|
538
|
+
// refuses before any native dispatch (the Db.apply pattern);
|
|
539
|
+
// a spent/closed ChangeSet refuses as ClosedHandle; a scope/
|
|
540
|
+
// change schema mismatch refuses before native work.
|
|
541
|
+
const internal = core.changes(input.changes);
|
|
542
|
+
if (internal === undefined) {
|
|
543
|
+
return Effect.fail(invalidInput(operation));
|
|
544
|
+
}
|
|
545
|
+
if (internal.closed) {
|
|
546
|
+
return Effect.fail(closedHandle(operation));
|
|
547
|
+
}
|
|
548
|
+
let request;
|
|
549
|
+
try {
|
|
550
|
+
if (String(internal.schemaId) !== String(input.scope.schemaId)) {
|
|
551
|
+
throw invalidInput(operation);
|
|
552
|
+
}
|
|
553
|
+
request = {
|
|
554
|
+
scope: identityWire(operation, input.scope),
|
|
555
|
+
receiptEpoch: input.id.receiptEpoch,
|
|
556
|
+
requestId: checkedUuid(operation, input.id.requestId),
|
|
557
|
+
precondition: preconditionWire(operation, input.precondition),
|
|
558
|
+
result: resultWire(operation, input.result)
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
catch (cause) {
|
|
562
|
+
return Effect.fail(logFailure(operation, cause));
|
|
563
|
+
}
|
|
564
|
+
return logOperation(operation, cancel, (callback) => wire.logCommandSeal(internal.handle, policyWire(work, operation), request, callback), wire.logCommandTake, (cw) => makeCommand(cw));
|
|
565
|
+
});
|
|
566
|
+
return scopedResource(operation, acquire, (command) => command.close());
|
|
567
|
+
},
|
|
568
|
+
encode(command, work) {
|
|
569
|
+
const operation = "Command.encode";
|
|
570
|
+
return Effect.suspend(() => {
|
|
571
|
+
const entry = commandEntries.get(command);
|
|
572
|
+
if (entry === undefined) {
|
|
573
|
+
return Effect.die(invalidInput(operation));
|
|
574
|
+
}
|
|
575
|
+
if (entry.state.closed) {
|
|
576
|
+
return Effect.fail(closedHandle(operation));
|
|
577
|
+
}
|
|
578
|
+
return logOperation(operation, cancel, (callback) => wire.logCommandEncode(entry.handle, policyWire(work, operation), callback), wire.logBytesTake, (bytes) => bytes);
|
|
579
|
+
});
|
|
580
|
+
},
|
|
581
|
+
decode(bytes, schema, work) {
|
|
582
|
+
const operation = "Command.decode";
|
|
583
|
+
return Effect.gen(function* () {
|
|
584
|
+
const runtime = yield* core.runtime();
|
|
585
|
+
const acquire = Effect.suspend(() => {
|
|
586
|
+
if (!(bytes instanceof Uint8Array) || !(bytes.buffer instanceof ArrayBuffer)) {
|
|
587
|
+
return Effect.fail(logFailure(operation, invalidInput(operation)));
|
|
588
|
+
}
|
|
589
|
+
return logOperation(operation, cancel, (callback) => wire.logCommandDecode(runtime, policyWire(work, operation), bytes, core.schemaSpec(schema), callback), wire.logCommandTake, (cw) => makeCommand(cw));
|
|
590
|
+
});
|
|
591
|
+
return yield* scopedResource(operation, acquire, (command) => command.close());
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
const TenantCacheNamespace = {
|
|
596
|
+
make(schema, options) {
|
|
597
|
+
const operation = "TenantCache.make";
|
|
598
|
+
return Effect.gen(function* () {
|
|
599
|
+
const runtime = yield* core.runtime();
|
|
600
|
+
const acquire = Effect.suspend(() => {
|
|
601
|
+
let request;
|
|
602
|
+
try {
|
|
603
|
+
if (typeof options.budgetBytes !== "bigint" || options.budgetBytes < 0n) {
|
|
604
|
+
throw invalidInput(operation);
|
|
605
|
+
}
|
|
606
|
+
request = {
|
|
607
|
+
maxOpen: checkedCount(operation, options.maxOpen, 0xffffffff),
|
|
608
|
+
budgetBytes: options.budgetBytes,
|
|
609
|
+
expected: options.expected === undefined
|
|
610
|
+
? null
|
|
611
|
+
: {
|
|
612
|
+
schemaId: checkedString(operation, options.expected.schemaId, 64),
|
|
613
|
+
appliedPrefixDigest: checkedString(operation, options.expected.appliedPrefixDigest, 64)
|
|
614
|
+
},
|
|
615
|
+
schema: core.schemaSpec(schema)
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
catch (cause) {
|
|
619
|
+
return Effect.fail(logFailure(operation, cause));
|
|
620
|
+
}
|
|
621
|
+
return logOperation(operation, cancel, (callback) => wire.logCacheMake(runtime, policyWire(options.maintenance, operation), request, callback), wire.logCacheTake, (cache) => makeCache(schema, cache, options));
|
|
622
|
+
});
|
|
623
|
+
return yield* scopedResource(operation, acquire, (cache) => cache.close());
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
function makeCache(schema, cache, options) {
|
|
628
|
+
const state = { closed: false };
|
|
629
|
+
return {
|
|
630
|
+
acquire(binding, work) {
|
|
631
|
+
const operation = "TenantCache.acquire";
|
|
632
|
+
const acquire = Effect.suspend(() => {
|
|
633
|
+
if (state.closed) {
|
|
634
|
+
return Effect.fail(closedHandle(operation));
|
|
635
|
+
}
|
|
636
|
+
let wireBinding;
|
|
637
|
+
try {
|
|
638
|
+
wireBinding = bindingWire(operation, binding);
|
|
639
|
+
}
|
|
640
|
+
catch (cause) {
|
|
641
|
+
return Effect.fail(logFailure(operation, cause));
|
|
642
|
+
}
|
|
643
|
+
return logOperation(operation, cancel, (callback) => wire.logCacheAcquire(cache, policyWire(work, operation), { binding: wireBinding }, callback), wire.logBorrowTake, (handle) => makeBorrow(schema, handle));
|
|
644
|
+
});
|
|
645
|
+
return scopedResource(operation, acquire, (borrow) => borrow.release());
|
|
646
|
+
},
|
|
647
|
+
inspect(work) {
|
|
648
|
+
const operation = "TenantCache.inspect";
|
|
649
|
+
return Effect.suspend(() => {
|
|
650
|
+
if (state.closed) {
|
|
651
|
+
return Effect.fail(closedHandle(operation));
|
|
652
|
+
}
|
|
653
|
+
return logOperation(operation, cancel, (callback) => wire.logCacheInspect(cache, policyWire(work, operation), callback), wire.logCacheInspectTake, cacheInspectionOf);
|
|
654
|
+
});
|
|
655
|
+
},
|
|
656
|
+
evict(binding) {
|
|
657
|
+
const operation = "TenantCache.evict";
|
|
658
|
+
return Effect.suspend(() => {
|
|
659
|
+
if (state.closed) {
|
|
660
|
+
return Effect.fail(closedHandle(operation));
|
|
661
|
+
}
|
|
662
|
+
let wireBinding;
|
|
663
|
+
try {
|
|
664
|
+
wireBinding = bindingWire(operation, binding);
|
|
665
|
+
}
|
|
666
|
+
catch (cause) {
|
|
667
|
+
return Effect.fail(logFailure(operation, cause));
|
|
668
|
+
}
|
|
669
|
+
return logOperation(operation, cancel, (callback) => wire.logCacheEvict(cache, policyWire(options.maintenance, operation), { binding: wireBinding }, callback), wire.logCacheEvictTake, (report) => closeReportOf(operation, report));
|
|
670
|
+
});
|
|
671
|
+
},
|
|
672
|
+
close: () => Effect.suspend(() => {
|
|
673
|
+
state.closed = true;
|
|
674
|
+
return drainClose("TenantCache.close", (callback) => wire.logCacheClose(cache, callback));
|
|
675
|
+
})
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
// ── Admin/migration certainty wrappers ─────────────────────────────────
|
|
679
|
+
function decodeAdmin(operation, ref, result, decode) {
|
|
680
|
+
switch (result.certainty) {
|
|
681
|
+
case "completed":
|
|
682
|
+
return {
|
|
683
|
+
kind: "completed",
|
|
684
|
+
ref,
|
|
685
|
+
value: decode(result.value),
|
|
686
|
+
phase: phaseOf(operation, result.publicationPhase)
|
|
687
|
+
};
|
|
688
|
+
case "not-started":
|
|
689
|
+
return {
|
|
690
|
+
kind: "not-started",
|
|
691
|
+
ref,
|
|
692
|
+
error: errorOf(operation, result.error),
|
|
693
|
+
phase: phaseOf(operation, result.publicationPhase)
|
|
694
|
+
};
|
|
695
|
+
case "outcome-unknown":
|
|
696
|
+
return {
|
|
697
|
+
kind: "outcome-unknown",
|
|
698
|
+
ref,
|
|
699
|
+
error: errorOf(operation, result.error),
|
|
700
|
+
phase: phaseOf(operation, result.publicationPhase)
|
|
701
|
+
};
|
|
702
|
+
case "report":
|
|
703
|
+
// A read-only certainty from a mutating verb is a wire defect.
|
|
704
|
+
throw invalidInput(operation);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function adminMutation(operation, ref, work, request, decode) {
|
|
708
|
+
return Effect.gen(function* () {
|
|
709
|
+
const runtime = yield* Effect.result(core.runtime());
|
|
710
|
+
if (Result.isFailure(runtime)) {
|
|
711
|
+
return {
|
|
712
|
+
kind: "not-started",
|
|
713
|
+
ref,
|
|
714
|
+
error: runtime.failure,
|
|
715
|
+
phase: "prepared"
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
// `ref` is the caller-supplied operationId, fixed before dispatch.
|
|
719
|
+
// Interrupt after the native lease is outcome-unknown under this
|
|
720
|
+
// same ref; retry status/the same operationId, never a new mint.
|
|
721
|
+
return yield* certaintyOperation(operation, cancel, (callback) => wire.logAdmin(runtime.success, policyWire(work, operation), request(), callback), wire.logAdminTake, (result) => decodeAdmin(operation, ref, result, decode), (error) => ({ kind: "not-started", ref, error, phase: "prepared" }), (error) => ({
|
|
722
|
+
kind: "outcome-unknown",
|
|
723
|
+
ref,
|
|
724
|
+
error,
|
|
725
|
+
phase: "dispatchedUnresolved"
|
|
726
|
+
}));
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
function adminQuery(operation, work, request, decode) {
|
|
730
|
+
return Effect.gen(function* () {
|
|
731
|
+
const runtime = yield* core.runtime();
|
|
732
|
+
return yield* logOperation(operation, cancel, (callback) => wire.logAdmin(runtime, policyWire(work, operation), request(), callback), wire.logAdminTake, (result) => {
|
|
733
|
+
if (result.certainty !== "report") {
|
|
734
|
+
throw invalidInput(operation);
|
|
735
|
+
}
|
|
736
|
+
return decode(result.value);
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
function operationRef(binding, operationId) {
|
|
741
|
+
return { identity: binding.identity, operation: operationId };
|
|
742
|
+
}
|
|
743
|
+
/** The lowered core SchemaSpec, when the caller supplied a schema. */
|
|
744
|
+
function schemaField(schema) {
|
|
745
|
+
return schema === undefined ? {} : { schema: core.schemaSpec(schema) };
|
|
746
|
+
}
|
|
747
|
+
/** The backup operation id, when supplied (canonical UUID, checked outbound). */
|
|
748
|
+
function backupField(operation, backup) {
|
|
749
|
+
return backup === undefined ? {} : { backup: checkedUuid(operation, backup) };
|
|
750
|
+
}
|
|
751
|
+
/** Optional source binding + target schema for activate/abort. */
|
|
752
|
+
function targetFields(operation, options) {
|
|
753
|
+
return {
|
|
754
|
+
...(options.binding === undefined ? {} : { binding: bindingWire(operation, options.binding) }),
|
|
755
|
+
...schemaField(options.schema)
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
function destinationWire(operation, destination) {
|
|
759
|
+
if (destination.kind === "filesystem") {
|
|
760
|
+
return { kind: "filesystem", directory: checkedString(operation, destination.directory, 4096) };
|
|
761
|
+
}
|
|
762
|
+
if (destination.kind !== "s3") {
|
|
763
|
+
throw invalidInput(operation);
|
|
764
|
+
}
|
|
765
|
+
return {
|
|
766
|
+
kind: "s3",
|
|
767
|
+
bucket: checkedString(operation, destination.bucket, 255),
|
|
768
|
+
prefix: checkedString(operation, destination.prefix, 1024),
|
|
769
|
+
region: destination.region === undefined ? null : checkedString(operation, destination.region, 64),
|
|
770
|
+
credentials: credentialsWire(operation, destination.credentials)
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
function expectVerb(operation, verb) {
|
|
774
|
+
return (value) => {
|
|
775
|
+
if (value.verb !== verb) {
|
|
776
|
+
throw invalidInput(operation);
|
|
777
|
+
}
|
|
778
|
+
return value;
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
function sourceAccessOf(wire) {
|
|
782
|
+
return {
|
|
783
|
+
access: wire.access,
|
|
784
|
+
operation: wire.operationId === null ? null : wire.operationId
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
// `ActivationRef` is the C11 shape declared in #migrations/types.ts:
|
|
788
|
+
// { operation: OperationId, planSetDigest, target, targetGenesis }.
|
|
789
|
+
function activationRefOf(wire) {
|
|
790
|
+
return {
|
|
791
|
+
operation: wire.operationId,
|
|
792
|
+
planSetDigest: wire.planSetDigest,
|
|
793
|
+
target: identityOf(wire.target),
|
|
794
|
+
targetGenesis: wire.targetGenesis
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
function migrationRefOf(wire) {
|
|
798
|
+
return {
|
|
799
|
+
operation: { identity: identityOf(wire.identity), operation: wire.operationId },
|
|
800
|
+
planSetDigest: wire.planSetDigest,
|
|
801
|
+
target: identityOf(wire.target)
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
function activationRefWire(operation, ref) {
|
|
805
|
+
return {
|
|
806
|
+
operationId: checkedUuid(operation, ref.operation),
|
|
807
|
+
planSetDigest: checkedString(operation, ref.planSetDigest, 64),
|
|
808
|
+
target: identityWire(operation, ref.target),
|
|
809
|
+
targetGenesis: checkedString(operation, ref.targetGenesis, 64)
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
function migrationRefWire(operation, ref) {
|
|
813
|
+
return {
|
|
814
|
+
identity: identityWire(operation, ref.operation.identity),
|
|
815
|
+
operationId: checkedUuid(operation, ref.operation.operation),
|
|
816
|
+
planSetDigest: checkedString(operation, ref.planSetDigest, 64),
|
|
817
|
+
target: identityWire(operation, ref.target)
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
function migrateValueOf(operation, wire) {
|
|
821
|
+
switch (wire.kind) {
|
|
822
|
+
case "up-to-date":
|
|
823
|
+
return { kind: "up-to-date", binding: bindingOf(wire.binding) };
|
|
824
|
+
case "ready-to-switch":
|
|
825
|
+
return {
|
|
826
|
+
kind: "ready-to-switch",
|
|
827
|
+
deploymentBinding: bindingOf(wire.deploymentBinding),
|
|
828
|
+
activation: activationRefOf(wire.activation)
|
|
829
|
+
};
|
|
830
|
+
case "paused":
|
|
831
|
+
return {
|
|
832
|
+
kind: "paused",
|
|
833
|
+
error: errorOf(operation, wire.error),
|
|
834
|
+
sourceState: sourceAccessOf(wire.sourceState)
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
function migrationStatusOf(operation, wire) {
|
|
839
|
+
switch (wire.kind) {
|
|
840
|
+
case "up-to-date":
|
|
841
|
+
return { kind: "up-to-date", appliedPrefixDigest: wire.appliedPrefixDigest };
|
|
842
|
+
case "pending":
|
|
843
|
+
return { kind: "pending", pending: wire.pending };
|
|
844
|
+
case "in-progress":
|
|
845
|
+
return { kind: "in-progress", operation: migrationRefOf(wire.operationRef).operation };
|
|
846
|
+
case "paused":
|
|
847
|
+
return {
|
|
848
|
+
kind: "paused",
|
|
849
|
+
operation: migrationRefOf(wire.operationRef).operation,
|
|
850
|
+
error: errorOf(operation, wire.error),
|
|
851
|
+
sourceState: sourceAccessOf(wire.sourceState)
|
|
852
|
+
};
|
|
853
|
+
case "ready-to-switch":
|
|
854
|
+
return {
|
|
855
|
+
kind: "ready-to-switch",
|
|
856
|
+
operation: migrationRefOf(wire.operationRef).operation,
|
|
857
|
+
activation: activationRefOf(wire.activation)
|
|
858
|
+
};
|
|
859
|
+
case "activated":
|
|
860
|
+
return {
|
|
861
|
+
kind: "activated",
|
|
862
|
+
operation: migrationRefOf(wire.operationRef).operation,
|
|
863
|
+
target: identityOf(wire.target)
|
|
864
|
+
};
|
|
865
|
+
case "aborted":
|
|
866
|
+
return { kind: "aborted", operation: migrationRefOf(wire.operationRef).operation };
|
|
867
|
+
case "outcome-unknown":
|
|
868
|
+
return {
|
|
869
|
+
kind: "outcome-unknown",
|
|
870
|
+
operation: migrationRefOf(wire.operationRef).operation,
|
|
871
|
+
error: errorOf(operation, wire.error)
|
|
872
|
+
};
|
|
873
|
+
case "drift":
|
|
874
|
+
return { kind: "drift", detail: wire.detail };
|
|
875
|
+
case "database-ahead":
|
|
876
|
+
return { kind: "database-ahead", detail: wire.detail };
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
const admin = {
|
|
880
|
+
checkpoint(binding, options) {
|
|
881
|
+
const operation = "admin.checkpoint";
|
|
882
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
883
|
+
verb: "checkpoint",
|
|
884
|
+
binding: bindingWire(operation, binding),
|
|
885
|
+
...schemaField(options.schema),
|
|
886
|
+
operationId: checkedUuid(operation, options.operationId)
|
|
887
|
+
}), (value) => {
|
|
888
|
+
const report = expectVerb(operation, "checkpoint")(value);
|
|
889
|
+
return {
|
|
890
|
+
at: stampOf(report.at),
|
|
891
|
+
state: stateOf(report.state),
|
|
892
|
+
root: report.root
|
|
893
|
+
};
|
|
894
|
+
});
|
|
895
|
+
},
|
|
896
|
+
pinRestorePoint(binding, options) {
|
|
897
|
+
const operation = "admin.pinRestorePoint";
|
|
898
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
899
|
+
verb: "pin-root",
|
|
900
|
+
binding: bindingWire(operation, binding),
|
|
901
|
+
...schemaField(options.schema),
|
|
902
|
+
operationId: checkedUuid(operation, options.operationId),
|
|
903
|
+
label: checkedString(operation, options.label, 256)
|
|
904
|
+
}), (value) => {
|
|
905
|
+
const report = expectVerb(operation, "pin-root")(value);
|
|
906
|
+
return {
|
|
907
|
+
root: report.root,
|
|
908
|
+
at: stampOf(report.at),
|
|
909
|
+
state: stateOf(report.state)
|
|
910
|
+
};
|
|
911
|
+
});
|
|
912
|
+
},
|
|
913
|
+
releaseRestorePoint(binding, options) {
|
|
914
|
+
const operation = "admin.releaseRestorePoint";
|
|
915
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
916
|
+
verb: "release-root",
|
|
917
|
+
binding: bindingWire(operation, binding),
|
|
918
|
+
...schemaField(options.schema),
|
|
919
|
+
operationId: checkedUuid(operation, options.operationId),
|
|
920
|
+
root: checkedString(operation, options.root, 128)
|
|
921
|
+
}), (value) => {
|
|
922
|
+
const report = expectVerb(operation, "release-root")(value);
|
|
923
|
+
return {
|
|
924
|
+
root: report.root,
|
|
925
|
+
wasCurrentRecoveryBase: report.wasCurrentRecoveryBase
|
|
926
|
+
};
|
|
927
|
+
});
|
|
928
|
+
},
|
|
929
|
+
rotateReceiptEpoch(binding, options) {
|
|
930
|
+
const operation = "admin.rotateReceiptEpoch";
|
|
931
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
932
|
+
verb: "rotate-receipt-epoch",
|
|
933
|
+
binding: bindingWire(operation, binding),
|
|
934
|
+
...schemaField(options.schema),
|
|
935
|
+
operationId: checkedUuid(operation, options.operationId)
|
|
936
|
+
}), (value) => {
|
|
937
|
+
const report = expectVerb(operation, "rotate-receipt-epoch")(value);
|
|
938
|
+
return { openEpoch: report.openEpoch };
|
|
939
|
+
});
|
|
940
|
+
},
|
|
941
|
+
retireReceipts(binding, options) {
|
|
942
|
+
const operation = "admin.retireReceipts";
|
|
943
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => {
|
|
944
|
+
if (typeof options.through !== "bigint" || options.through < 0n) {
|
|
945
|
+
throw invalidInput(operation);
|
|
946
|
+
}
|
|
947
|
+
return {
|
|
948
|
+
verb: "retire-receipts",
|
|
949
|
+
binding: bindingWire(operation, binding),
|
|
950
|
+
...schemaField(options.schema),
|
|
951
|
+
operationId: checkedUuid(operation, options.operationId),
|
|
952
|
+
through: options.through
|
|
953
|
+
};
|
|
954
|
+
}, (value) => {
|
|
955
|
+
const report = expectVerb(operation, "retire-receipts")(value);
|
|
956
|
+
return { retiredThrough: report.retiredThrough };
|
|
957
|
+
});
|
|
958
|
+
},
|
|
959
|
+
collectGarbage(binding, options) {
|
|
960
|
+
const operation = "admin.collectGarbage";
|
|
961
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
962
|
+
verb: "collect-garbage",
|
|
963
|
+
binding: bindingWire(operation, binding),
|
|
964
|
+
...schemaField(options.schema),
|
|
965
|
+
operationId: checkedUuid(operation, options.operationId)
|
|
966
|
+
}), (value) => {
|
|
967
|
+
const report = expectVerb(operation, "collect-garbage")(value);
|
|
968
|
+
return {
|
|
969
|
+
objectEpoch: report.objectEpoch,
|
|
970
|
+
swept: report.swept,
|
|
971
|
+
orphansObserved: report.orphansObserved
|
|
972
|
+
};
|
|
973
|
+
});
|
|
974
|
+
},
|
|
975
|
+
backup(binding, options) {
|
|
976
|
+
const operation = "admin.backup";
|
|
977
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
978
|
+
verb: "backup",
|
|
979
|
+
binding: bindingWire(operation, binding),
|
|
980
|
+
...schemaField(options.schema),
|
|
981
|
+
operationId: checkedUuid(operation, options.operationId),
|
|
982
|
+
destination: destinationWire(operation, options.destination)
|
|
983
|
+
}), (value) => {
|
|
984
|
+
const report = expectVerb(operation, "backup")(value);
|
|
985
|
+
return {
|
|
986
|
+
manifestDigest: report.manifestDigest,
|
|
987
|
+
objects: report.objects,
|
|
988
|
+
bytes: report.bytes,
|
|
989
|
+
at: stampOf(report.at)
|
|
990
|
+
};
|
|
991
|
+
});
|
|
992
|
+
},
|
|
993
|
+
verifyBackup(destination, options) {
|
|
994
|
+
const operation = "admin.verifyBackup";
|
|
995
|
+
return adminQuery(operation, options, () => ({
|
|
996
|
+
verb: "verify-backup",
|
|
997
|
+
destination: destinationWire(operation, destination),
|
|
998
|
+
...backupField(operation, options.backup)
|
|
999
|
+
}), (value) => {
|
|
1000
|
+
const report = expectVerb(operation, "verify-backup")(value);
|
|
1001
|
+
return {
|
|
1002
|
+
identity: identityOf(report.identity),
|
|
1003
|
+
at: stampOf(report.at),
|
|
1004
|
+
state: stateOf(report.state),
|
|
1005
|
+
objects: report.objects,
|
|
1006
|
+
bytes: report.bytes,
|
|
1007
|
+
manifestDigest: report.manifestDigest
|
|
1008
|
+
};
|
|
1009
|
+
});
|
|
1010
|
+
},
|
|
1011
|
+
restore(source, target, options) {
|
|
1012
|
+
const operation = "admin.restore";
|
|
1013
|
+
return adminMutation(operation, operationRef(target, options.operationId), options, () => ({
|
|
1014
|
+
verb: "restore",
|
|
1015
|
+
source: destinationWire(operation, source),
|
|
1016
|
+
target: bindingWire(operation, target),
|
|
1017
|
+
...schemaField(options.schema),
|
|
1018
|
+
...backupField(operation, options.backup),
|
|
1019
|
+
operationId: checkedUuid(operation, options.operationId)
|
|
1020
|
+
}), (value) => {
|
|
1021
|
+
const report = expectVerb(operation, "restore")(value);
|
|
1022
|
+
return {
|
|
1023
|
+
identity: identityOf(report.identity),
|
|
1024
|
+
genesis: report.genesis,
|
|
1025
|
+
binding: bindingOf(report.binding)
|
|
1026
|
+
};
|
|
1027
|
+
});
|
|
1028
|
+
},
|
|
1029
|
+
erase(binding, options) {
|
|
1030
|
+
const operation = "admin.erase";
|
|
1031
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
1032
|
+
verb: "erase",
|
|
1033
|
+
binding: bindingWire(operation, binding),
|
|
1034
|
+
...schemaField(options.schema),
|
|
1035
|
+
operationId: checkedUuid(operation, options.operationId),
|
|
1036
|
+
retainRoots: options.retainRoots.map((root) => checkedString(operation, root, 128))
|
|
1037
|
+
}), (value) => {
|
|
1038
|
+
const report = expectVerb(operation, "erase")(value);
|
|
1039
|
+
return {
|
|
1040
|
+
tombstoned: report.tombstoned,
|
|
1041
|
+
retainedRoots: report.retainedRoots.map((root) => root),
|
|
1042
|
+
residual: report.residual
|
|
1043
|
+
};
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
const migrations = {
|
|
1048
|
+
migrationStatus(binding, plans, work) {
|
|
1049
|
+
const operation = "migrations.status";
|
|
1050
|
+
return adminQuery(operation, work, () => ({
|
|
1051
|
+
verb: "migration-status",
|
|
1052
|
+
binding: bindingWire(operation, binding),
|
|
1053
|
+
...schemaField(work.schema),
|
|
1054
|
+
plans: plansWire(operation, plans)
|
|
1055
|
+
}), (value) => {
|
|
1056
|
+
const report = expectVerb(operation, "migration-status")(value);
|
|
1057
|
+
return migrationStatusOf(operation, report.status);
|
|
1058
|
+
});
|
|
1059
|
+
},
|
|
1060
|
+
initialize(binding, plans, options) {
|
|
1061
|
+
const operation = "migrations.initialize";
|
|
1062
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
1063
|
+
verb: "migration-initialize",
|
|
1064
|
+
binding: bindingWire(operation, binding),
|
|
1065
|
+
...schemaField(options.schema),
|
|
1066
|
+
operationId: checkedUuid(operation, options.operationId),
|
|
1067
|
+
plans: plansWire(operation, plans)
|
|
1068
|
+
}), (value) => {
|
|
1069
|
+
const report = expectVerb(operation, "migration-initialize")(value);
|
|
1070
|
+
return { binding: bindingOf(report.binding), genesis: report.genesis };
|
|
1071
|
+
});
|
|
1072
|
+
},
|
|
1073
|
+
migrate(binding, plans, options) {
|
|
1074
|
+
const operation = "migrations.migrate";
|
|
1075
|
+
return adminMutation(operation, operationRef(binding, options.operationId), options, () => ({
|
|
1076
|
+
verb: "migration-migrate",
|
|
1077
|
+
binding: bindingWire(operation, binding),
|
|
1078
|
+
...schemaField(options.schema),
|
|
1079
|
+
operationId: checkedUuid(operation, options.operationId),
|
|
1080
|
+
plans: plansWire(operation, plans),
|
|
1081
|
+
to: options.to === undefined ? null : checkedString(operation, options.to, 256)
|
|
1082
|
+
}), (value) => {
|
|
1083
|
+
const report = expectVerb(operation, "migration-migrate")(value);
|
|
1084
|
+
return migrateValueOf(operation, report.value);
|
|
1085
|
+
});
|
|
1086
|
+
},
|
|
1087
|
+
activateMigration(ref, options) {
|
|
1088
|
+
const operation = "migrations.activate";
|
|
1089
|
+
return adminMutation(operation, { identity: ref.target, operation: ref.operation }, options, () => ({
|
|
1090
|
+
verb: "migration-activate",
|
|
1091
|
+
ref: activationRefWire(operation, ref),
|
|
1092
|
+
...targetFields(operation, options)
|
|
1093
|
+
}), (value) => {
|
|
1094
|
+
const report = expectVerb(operation, "migration-activate")(value);
|
|
1095
|
+
return {
|
|
1096
|
+
target: identityOf(report.target),
|
|
1097
|
+
accessMode: report.accessMode,
|
|
1098
|
+
operation: report.operationId,
|
|
1099
|
+
activatedNow: report.activatedNow
|
|
1100
|
+
};
|
|
1101
|
+
});
|
|
1102
|
+
},
|
|
1103
|
+
abortMigration(ref, options) {
|
|
1104
|
+
const operation = "migrations.abort";
|
|
1105
|
+
return adminMutation(operation, ref.operation, options, () => ({
|
|
1106
|
+
verb: "migration-abort",
|
|
1107
|
+
ref: migrationRefWire(operation, ref),
|
|
1108
|
+
...targetFields(operation, options)
|
|
1109
|
+
}), (value) => {
|
|
1110
|
+
const report = expectVerb(operation, "migration-abort")(value);
|
|
1111
|
+
return {
|
|
1112
|
+
target: identityOf(report.target),
|
|
1113
|
+
targetFenced: report.targetFenced,
|
|
1114
|
+
sourceAccess: report.sourceAccess
|
|
1115
|
+
};
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
return {
|
|
1120
|
+
LocalHistory,
|
|
1121
|
+
HostedHistory,
|
|
1122
|
+
Command: CommandNamespace,
|
|
1123
|
+
TenantCache: TenantCacheNamespace,
|
|
1124
|
+
admin,
|
|
1125
|
+
migrations
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
//# sourceMappingURL=machine.js.map
|