@crvouga/mockingbird-service-fullscript 1.7.0 → 1.8.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/CHANGELOG.md +21 -4
- package/dist/{chunk-Q5BBSHKJ.js → chunk-L5A2NSLT.js} +205 -28
- package/dist/chunk-L5A2NSLT.js.map +7 -0
- package/dist/chunk-VH7HDXIA.js +851 -0
- package/dist/chunk-VH7HDXIA.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +1 -1
- package/dist/server.d.ts +62 -4
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-7JQ2IK4I.js +0 -384
- package/dist/chunk-7JQ2IK4I.js.map +0 -7
- package/dist/chunk-Q5BBSHKJ.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-fullscript
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
3
|
+
## 1.8.0 (2026-10-02)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- coordinate HTTP and protocol mocks ([3168653](https://github.com/crvouga/mockingbird/commit/31686534c55a9823fdaa92afc9cc456cf741b809))
|
|
8
|
+
|
|
9
|
+
### Fixes and improvements
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
- decouple smoke types from built packages ([a4b31c6](https://github.com/crvouga/mockingbird/commit/a4b31c6205d92aa0c6f7c9de3518d5ae44d38829))
|
|
12
|
+
- protect child admin endpoints ([5410b94](https://github.com/crvouga/mockingbird/commit/5410b948a30dcedc21e9a70e44fd415c1ea25394))
|
|
13
|
+
- harden protocol startup and state ([6f5b557](https://github.com/crvouga/mockingbird/commit/6f5b557e87b48b31985949e04f3b5ef58f51d295))
|
|
14
|
+
- preserve checkpoints and lifecycle ([50e8c32](https://github.com/crvouga/mockingbird/commit/50e8c322feded2f7f45afce9d8cdef43c37ab9ab))
|
|
15
|
+
- clean branch state on reset ([3b714d4](https://github.com/crvouga/mockingbird/commit/3b714d4a5df8e75fee0bb31e98d7c7566e164381))
|
|
16
|
+
- type signal listener cleanup ([5279852](https://github.com/crvouga/mockingbird/commit/5279852e56ea60262ccf17aa6e46b3c31091a34a))
|
|
17
|
+
|
|
18
|
+
## 1.7.1 (2026-10-01)
|
|
19
|
+
|
|
20
|
+
### Fixes and improvements
|
|
10
21
|
|
|
11
|
-
-
|
|
22
|
+
- freeze clock before setting time ([a054a1d](https://github.com/crvouga/mockingbird/commit/a054a1defad62539d719b1d31c15107afea623bd))
|
|
23
|
+
|
|
24
|
+
## 1.7.0 (2026-09-30)
|
|
25
|
+
|
|
26
|
+
### Features
|
|
27
|
+
|
|
28
|
+
- record SQL timelines and serve the admin explorer ([8ced17a](https://github.com/crvouga/mockingbird/commit/8ced17ac398e386ef4e9d7e01fc7744c34b95d07))
|
|
12
29
|
|
|
13
30
|
## 1.6.1 (2026-09-30)
|
|
14
31
|
|
|
@@ -183,29 +183,30 @@ var createControlPlane = (context) => {
|
|
|
183
183
|
return json(200, { status: "ok", reset: target === "*" ? context.namespaces() : [target] });
|
|
184
184
|
},
|
|
185
185
|
"GET /namespaces": () => json(200, { default: context.defaultNamespace, namespaces: context.namespaces() }),
|
|
186
|
-
"GET /clock": () => json(200, context.clock.state()),
|
|
187
|
-
"POST /clock": ({ body }) => {
|
|
186
|
+
"GET /clock": ({ namespace }) => json(200, (context.namespaceClock?.(namespace) ?? context.clock).state()),
|
|
187
|
+
"POST /clock": ({ body, namespace }) => {
|
|
188
|
+
const clock = context.namespaceClock?.(namespace) ?? context.clock;
|
|
188
189
|
if (!isRecord(body))
|
|
189
190
|
return adminError(400, "expected a JSON object");
|
|
190
191
|
if (body.reset === true)
|
|
191
|
-
|
|
192
|
+
clock.reset();
|
|
193
|
+
if (body.freeze === true)
|
|
194
|
+
clock.freeze();
|
|
192
195
|
if (body.set !== void 0) {
|
|
193
196
|
const instant = parseInstant(body.set);
|
|
194
197
|
if (instant === void 0)
|
|
195
198
|
return adminError(400, "set: expected epoch ms or ISO-8601");
|
|
196
|
-
|
|
199
|
+
clock.set(instant);
|
|
197
200
|
}
|
|
198
201
|
if (body.advance !== void 0) {
|
|
199
202
|
const delta = parseDuration(body.advance);
|
|
200
203
|
if (delta === void 0)
|
|
201
204
|
return adminError(400, 'advance: expected ms or "15m"-style');
|
|
202
|
-
|
|
205
|
+
clock.advance(delta);
|
|
203
206
|
}
|
|
204
|
-
if (body.freeze === true)
|
|
205
|
-
context.clock.freeze();
|
|
206
207
|
if (body.freeze === false)
|
|
207
|
-
|
|
208
|
-
return json(200,
|
|
208
|
+
clock.unfreeze();
|
|
209
|
+
return json(200, clock.state());
|
|
209
210
|
},
|
|
210
211
|
"GET /faults": () => json(200, { faults: context.faults.list() }),
|
|
211
212
|
"POST /faults": ({ body, namespace }) => {
|
|
@@ -474,7 +475,33 @@ var faultResponse = (rule) => {
|
|
|
474
475
|
};
|
|
475
476
|
var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) => {
|
|
476
477
|
const entries = [];
|
|
478
|
+
let isolated = false;
|
|
479
|
+
const scopedRngs = /* @__PURE__ */ new Map();
|
|
480
|
+
const random = (namespace) => {
|
|
481
|
+
if (!isolated || namespace === "default")
|
|
482
|
+
return rng;
|
|
483
|
+
let scoped = scopedRngs.get(namespace);
|
|
484
|
+
if (!scoped) {
|
|
485
|
+
scoped = createRng(rng.seed);
|
|
486
|
+
scopedRngs.set(namespace, scoped);
|
|
487
|
+
}
|
|
488
|
+
return scoped;
|
|
489
|
+
};
|
|
477
490
|
return {
|
|
491
|
+
isolateNamespaces() {
|
|
492
|
+
isolated = true;
|
|
493
|
+
},
|
|
494
|
+
snapshot(namespace) {
|
|
495
|
+
return {
|
|
496
|
+
rules: structuredClone(entries.map((entry, position) => ({
|
|
497
|
+
...entry.rule,
|
|
498
|
+
remaining: entry.remaining,
|
|
499
|
+
hits: entry.hits,
|
|
500
|
+
position
|
|
501
|
+
})).filter((entry) => entry.namespace === namespace)),
|
|
502
|
+
rngState: random(namespace).state()
|
|
503
|
+
};
|
|
504
|
+
},
|
|
478
505
|
add(rule) {
|
|
479
506
|
const existing = entries.findIndex((e) => e.rule.id === rule.id);
|
|
480
507
|
const entry = { rule, remaining: rule.count ?? null, hits: 0 };
|
|
@@ -494,6 +521,16 @@ var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((reso
|
|
|
494
521
|
},
|
|
495
522
|
clear() {
|
|
496
523
|
entries.length = 0;
|
|
524
|
+
rng.reset();
|
|
525
|
+
scopedRngs.clear();
|
|
526
|
+
},
|
|
527
|
+
restore(namespace, state) {
|
|
528
|
+
for (let i = entries.length - 1; i >= 0; i--)
|
|
529
|
+
if (entries[i]?.rule.namespace === namespace)
|
|
530
|
+
entries.splice(i, 1);
|
|
531
|
+
for (const { remaining, hits, position, ...rule } of state.rules)
|
|
532
|
+
entries.splice(Math.min(position, entries.length), 0, { rule, remaining, hits });
|
|
533
|
+
random(namespace).setState(state.rngState);
|
|
497
534
|
},
|
|
498
535
|
async take(candidate) {
|
|
499
536
|
const hits = [];
|
|
@@ -503,7 +540,7 @@ var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((reso
|
|
|
503
540
|
if (!matches(entry.rule, candidate))
|
|
504
541
|
continue;
|
|
505
542
|
const rate = entry.rule.rate ?? 1;
|
|
506
|
-
if (
|
|
543
|
+
if (random(candidate.namespace).next() >= rate)
|
|
507
544
|
continue;
|
|
508
545
|
entry.hits++;
|
|
509
546
|
if (entry.remaining !== null)
|
|
@@ -1093,7 +1130,8 @@ var annotateResponse = (response, extra) => {
|
|
|
1093
1130
|
var responseNotes = (response) => notes.get(response);
|
|
1094
1131
|
|
|
1095
1132
|
// ../core/dist/metrics.js
|
|
1096
|
-
var createMetrics = () => {
|
|
1133
|
+
var createMetrics = (partition = true) => {
|
|
1134
|
+
const namespaces = /* @__PURE__ */ new Map();
|
|
1097
1135
|
let requests = 0;
|
|
1098
1136
|
let faults = 0;
|
|
1099
1137
|
let totalDurationMs = 0;
|
|
@@ -1101,6 +1139,14 @@ var createMetrics = () => {
|
|
|
1101
1139
|
const unmatched = /* @__PURE__ */ new Map();
|
|
1102
1140
|
return {
|
|
1103
1141
|
record(entry) {
|
|
1142
|
+
if (partition) {
|
|
1143
|
+
let scoped = namespaces.get(entry.namespace);
|
|
1144
|
+
if (!scoped) {
|
|
1145
|
+
scoped = createMetrics(false);
|
|
1146
|
+
namespaces.set(entry.namespace, scoped);
|
|
1147
|
+
}
|
|
1148
|
+
scoped.record(entry);
|
|
1149
|
+
}
|
|
1104
1150
|
requests++;
|
|
1105
1151
|
totalDurationMs += entry.durationMs;
|
|
1106
1152
|
if (entry.faultId !== void 0)
|
|
@@ -1112,7 +1158,7 @@ var createMetrics = () => {
|
|
|
1112
1158
|
unmatched.set(route, (unmatched.get(route) ?? 0) + 1);
|
|
1113
1159
|
}
|
|
1114
1160
|
},
|
|
1115
|
-
report: () => ({
|
|
1161
|
+
report: (namespace) => namespace !== void 0 ? (namespaces.get(namespace) ?? createMetrics(false)).report() : {
|
|
1116
1162
|
requests,
|
|
1117
1163
|
byOperation: Object.fromEntries([...byOperation].sort(([a], [b]) => a.localeCompare(b))),
|
|
1118
1164
|
unmatched: [...unmatched].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([route, count]) => {
|
|
@@ -1121,8 +1167,13 @@ var createMetrics = () => {
|
|
|
1121
1167
|
}),
|
|
1122
1168
|
faults,
|
|
1123
1169
|
totalDurationMs
|
|
1124
|
-
}
|
|
1125
|
-
reset() {
|
|
1170
|
+
},
|
|
1171
|
+
reset(namespace) {
|
|
1172
|
+
if (namespace !== void 0) {
|
|
1173
|
+
namespaces.delete(namespace);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
namespaces.clear();
|
|
1126
1177
|
requests = 0;
|
|
1127
1178
|
faults = 0;
|
|
1128
1179
|
totalDurationMs = 0;
|
|
@@ -4094,7 +4145,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
4094
4145
|
};
|
|
4095
4146
|
|
|
4096
4147
|
// ../core/dist/version.js
|
|
4097
|
-
var PACKAGE_VERSION = true ? "1.
|
|
4148
|
+
var PACKAGE_VERSION = true ? "1.8.0" : UNRELEASED_VERSION;
|
|
4098
4149
|
|
|
4099
4150
|
// ../core/dist/signing.js
|
|
4100
4151
|
var encoder = new TextEncoder();
|
|
@@ -4187,7 +4238,9 @@ var createWebhookHub = (options) => {
|
|
|
4187
4238
|
const faults = /* @__PURE__ */ new Map();
|
|
4188
4239
|
const held = /* @__PURE__ */ new Map();
|
|
4189
4240
|
const inFlight = /* @__PURE__ */ new Set();
|
|
4241
|
+
const controllers = /* @__PURE__ */ new Map();
|
|
4190
4242
|
let immediate = Promise.resolve();
|
|
4243
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
4191
4244
|
const track = (work) => {
|
|
4192
4245
|
inFlight.add(work);
|
|
4193
4246
|
void work.finally(() => inFlight.delete(work));
|
|
@@ -4208,6 +4261,7 @@ var createWebhookHub = (options) => {
|
|
|
4208
4261
|
responseBody: null
|
|
4209
4262
|
};
|
|
4210
4263
|
const controller = new AbortController();
|
|
4264
|
+
controllers.set(delivery.id, controller);
|
|
4211
4265
|
const timer = scheduleTimer(() => controller.abort(), timeoutMs);
|
|
4212
4266
|
try {
|
|
4213
4267
|
const signed = await options.signer({
|
|
@@ -4237,6 +4291,7 @@ var createWebhookHub = (options) => {
|
|
|
4237
4291
|
} catch (error) {
|
|
4238
4292
|
record.error = controller.signal.aborted ? `timed out after ${timeoutMs}ms` : error instanceof Error ? error.message : String(error);
|
|
4239
4293
|
} finally {
|
|
4294
|
+
controllers.delete(delivery.id);
|
|
4240
4295
|
cancel(timer);
|
|
4241
4296
|
record.durationMs = now() - started;
|
|
4242
4297
|
delivery.attempts.push(record);
|
|
@@ -4254,6 +4309,8 @@ var createWebhookHub = (options) => {
|
|
|
4254
4309
|
if (!payloads.has(delivery.id))
|
|
4255
4310
|
return;
|
|
4256
4311
|
await attempt(delivery).then((ok2) => {
|
|
4312
|
+
if (!payloads.has(delivery.id))
|
|
4313
|
+
return;
|
|
4257
4314
|
if (ok2)
|
|
4258
4315
|
delivery.state = "delivered";
|
|
4259
4316
|
else
|
|
@@ -4315,6 +4372,37 @@ var createWebhookHub = (options) => {
|
|
|
4315
4372
|
fanOut(message);
|
|
4316
4373
|
};
|
|
4317
4374
|
const hub = {
|
|
4375
|
+
pending(namespace) {
|
|
4376
|
+
return inFlight.size + (held.get(namespace)?.length ?? 0) + [...deliveries.values()].filter((d) => d.namespace === namespace && d.state === "pending").length;
|
|
4377
|
+
},
|
|
4378
|
+
snapshot(namespace) {
|
|
4379
|
+
if (hub.pending(namespace) > 0)
|
|
4380
|
+
throw new Error("webhooks are not quiescent");
|
|
4381
|
+
const handle = {};
|
|
4382
|
+
snapshots.set(handle, structuredClone({
|
|
4383
|
+
namespace,
|
|
4384
|
+
endpoints: own.get(namespace) ?? [],
|
|
4385
|
+
messages: messages.filter((m) => m.namespace === namespace),
|
|
4386
|
+
deliveries: [...deliveries].filter(([, d]) => d.namespace === namespace),
|
|
4387
|
+
payloads: [...payloads].filter(([, p]) => p.message.namespace === namespace),
|
|
4388
|
+
faults: faults.get(namespace) ?? []
|
|
4389
|
+
}));
|
|
4390
|
+
return handle;
|
|
4391
|
+
},
|
|
4392
|
+
restore(namespace, handle) {
|
|
4393
|
+
const point = typeof handle === "object" && handle !== null ? snapshots.get(handle) : void 0;
|
|
4394
|
+
if (!point || point.namespace !== namespace || hub.pending(namespace) > 0)
|
|
4395
|
+
throw new Error("invalid webhook restore");
|
|
4396
|
+
hub.clear(namespace);
|
|
4397
|
+
const copied = structuredClone(point);
|
|
4398
|
+
own.set(namespace, copied.endpoints);
|
|
4399
|
+
messages.push(...copied.messages);
|
|
4400
|
+
for (const [id2, delivery] of copied.deliveries)
|
|
4401
|
+
deliveries.set(id2, delivery);
|
|
4402
|
+
for (const [id2, payload] of copied.payloads)
|
|
4403
|
+
payloads.set(id2, payload);
|
|
4404
|
+
faults.set(namespace, copied.faults);
|
|
4405
|
+
},
|
|
4318
4406
|
publish(input) {
|
|
4319
4407
|
const contentType = input.contentType ?? (input.form ? "application/x-www-form-urlencoded" : "application/json");
|
|
4320
4408
|
const body = typeof input.body === "string" ? input.body : input.form ? new URLSearchParams(input.form).toString() : JSON.stringify(input.body);
|
|
@@ -4405,6 +4493,7 @@ var createWebhookHub = (options) => {
|
|
|
4405
4493
|
for (const [id2, delivery] of deliveries) {
|
|
4406
4494
|
if (namespace !== void 0 && delivery.namespace !== namespace)
|
|
4407
4495
|
continue;
|
|
4496
|
+
controllers.get(id2)?.abort();
|
|
4408
4497
|
const timer = pending.get(id2);
|
|
4409
4498
|
if (timer !== void 0)
|
|
4410
4499
|
cancel(timer);
|
|
@@ -4592,6 +4681,20 @@ var createRuntime = (options) => {
|
|
|
4592
4681
|
const instances = /* @__PURE__ */ new Map();
|
|
4593
4682
|
const publicNamespaces = /* @__PURE__ */ new Set();
|
|
4594
4683
|
const branchRngs = /* @__PURE__ */ new Map();
|
|
4684
|
+
const namespaceClocks = /* @__PURE__ */ new Map();
|
|
4685
|
+
const namespaceForStorage = /* @__PURE__ */ new Map();
|
|
4686
|
+
let isolatedNamespaces = false;
|
|
4687
|
+
const namespaceClock = (name = DEFAULT_NAMESPACE) => {
|
|
4688
|
+
if (!isolatedNamespaces || name === DEFAULT_NAMESPACE)
|
|
4689
|
+
return clock;
|
|
4690
|
+
let found = namespaceClocks.get(name);
|
|
4691
|
+
if (!found) {
|
|
4692
|
+
found = createClock();
|
|
4693
|
+
namespaceClocks.set(name, found);
|
|
4694
|
+
}
|
|
4695
|
+
return found;
|
|
4696
|
+
};
|
|
4697
|
+
const fleetPoints = /* @__PURE__ */ new WeakMap();
|
|
4595
4698
|
const timelines = /* @__PURE__ */ new Map();
|
|
4596
4699
|
const branchStorage = /* @__PURE__ */ new Map();
|
|
4597
4700
|
const captured = /* @__PURE__ */ new Map();
|
|
@@ -4605,17 +4708,21 @@ var createRuntime = (options) => {
|
|
|
4605
4708
|
if (!NAMESPACE_PATTERN.test(key) || !NAMESPACE_PATTERN.test(publicNamespace)) {
|
|
4606
4709
|
throw new RangeError(`namespace must match ${NAMESPACE_PATTERN}: ${JSON.stringify(publicNamespace)}`);
|
|
4607
4710
|
}
|
|
4711
|
+
const createdContextRng = isolatedRng ?? (isolatedNamespaces && key !== DEFAULT_NAMESPACE ? createRng(options.seed ?? 0) : rng);
|
|
4608
4712
|
const created = options.create({
|
|
4609
4713
|
namespace: storageNamespace(key),
|
|
4610
4714
|
publicNamespace,
|
|
4611
4715
|
sqlite,
|
|
4612
|
-
clock,
|
|
4613
|
-
rng:
|
|
4716
|
+
clock: namespaceClock(publicNamespace),
|
|
4717
|
+
rng: createdContextRng
|
|
4614
4718
|
});
|
|
4615
4719
|
instances.set(key, created);
|
|
4720
|
+
namespaceForStorage.set(key, publicNamespace);
|
|
4616
4721
|
publicNamespaces.add(publicNamespace);
|
|
4617
4722
|
if (isolatedRng)
|
|
4618
4723
|
branchRngs.set(key, isolatedRng);
|
|
4724
|
+
else if (isolatedNamespaces && key !== DEFAULT_NAMESPACE)
|
|
4725
|
+
branchRngs.set(key, createdContextRng);
|
|
4619
4726
|
return created;
|
|
4620
4727
|
};
|
|
4621
4728
|
const instance = (name = DEFAULT_NAMESPACE) => instanceFor(name);
|
|
@@ -4633,7 +4740,7 @@ var createRuntime = (options) => {
|
|
|
4633
4740
|
captured.set(storage, snapshot2);
|
|
4634
4741
|
return Object.freeze({
|
|
4635
4742
|
snapshot: snapshot2,
|
|
4636
|
-
clock: Object.freeze(
|
|
4743
|
+
clock: Object.freeze(namespaceClock(namespaceForStorage.get(storage) ?? storage).state()),
|
|
4637
4744
|
rngState: (branchRngs.get(storage) ?? rng).state()
|
|
4638
4745
|
});
|
|
4639
4746
|
};
|
|
@@ -4643,7 +4750,7 @@ var createRuntime = (options) => {
|
|
|
4643
4750
|
return found;
|
|
4644
4751
|
instance(name);
|
|
4645
4752
|
found = new Timeline({
|
|
4646
|
-
now:
|
|
4753
|
+
now: namespaceClock(name).now,
|
|
4647
4754
|
...options.maxCheckpoints !== void 0 ? { maxCheckpoints: options.maxCheckpoints } : {}
|
|
4648
4755
|
});
|
|
4649
4756
|
found.commit(capture(name));
|
|
@@ -4670,12 +4777,13 @@ var createRuntime = (options) => {
|
|
|
4670
4777
|
const point = history2.checkout("main", at);
|
|
4671
4778
|
restoreNamespace(sqlite, storageNamespace(namespace), point.value.snapshot);
|
|
4672
4779
|
captured.set(namespace, point.value.snapshot);
|
|
4673
|
-
rng.setState(point.value.rngState);
|
|
4674
|
-
|
|
4780
|
+
(branchRngs.get(namespace) ?? rng).setState(point.value.rngState);
|
|
4781
|
+
const selectedClock = namespaceClock(namespace);
|
|
4782
|
+
selectedClock.set(point.value.clock.now);
|
|
4675
4783
|
if (point.value.clock.frozen)
|
|
4676
|
-
|
|
4784
|
+
selectedClock.freeze();
|
|
4677
4785
|
else
|
|
4678
|
-
|
|
4786
|
+
selectedClock.unfreeze();
|
|
4679
4787
|
}
|
|
4680
4788
|
return namespace;
|
|
4681
4789
|
}
|
|
@@ -4733,11 +4841,12 @@ var createRuntime = (options) => {
|
|
|
4733
4841
|
const storage = ensureBranch(namespace, branchName);
|
|
4734
4842
|
restoreNamespace(sqlite, storageNamespace(storage), point.value.snapshot);
|
|
4735
4843
|
captured.set(storage, point.value.snapshot);
|
|
4736
|
-
|
|
4844
|
+
const selectedClock = namespaceClock(namespace);
|
|
4845
|
+
selectedClock.set(point.value.clock.now);
|
|
4737
4846
|
if (point.value.clock.frozen)
|
|
4738
|
-
|
|
4847
|
+
selectedClock.freeze();
|
|
4739
4848
|
else
|
|
4740
|
-
|
|
4849
|
+
selectedClock.unfreeze();
|
|
4741
4850
|
(branchRngs.get(storage) ?? rng).setState(point.value.rngState);
|
|
4742
4851
|
};
|
|
4743
4852
|
const reset = async (name = DEFAULT_NAMESPACE) => {
|
|
@@ -4745,10 +4854,21 @@ var createRuntime = (options) => {
|
|
|
4745
4854
|
options.webhooks?.clear();
|
|
4746
4855
|
for (const each of instances.values())
|
|
4747
4856
|
await each.reset();
|
|
4857
|
+
for (const each of branchRngs.values())
|
|
4858
|
+
each.reset();
|
|
4748
4859
|
timelines.clear();
|
|
4860
|
+
for (const storage of branchStorage.values()) {
|
|
4861
|
+
instances.delete(storage);
|
|
4862
|
+
branchRngs.delete(storage);
|
|
4863
|
+
namespaceForStorage.delete(storage);
|
|
4864
|
+
}
|
|
4749
4865
|
branchStorage.clear();
|
|
4750
|
-
branchRngs.clear();
|
|
4751
4866
|
captured.clear();
|
|
4867
|
+
faults.clear();
|
|
4868
|
+
clock.reset();
|
|
4869
|
+
rng.reset();
|
|
4870
|
+
for (const each of namespaceClocks.values())
|
|
4871
|
+
each.reset();
|
|
4752
4872
|
return;
|
|
4753
4873
|
}
|
|
4754
4874
|
options.webhooks?.clear(name);
|
|
@@ -4766,11 +4886,18 @@ var createRuntime = (options) => {
|
|
|
4766
4886
|
else
|
|
4767
4887
|
clearNamespace(sqlite, storageNamespace(storage));
|
|
4768
4888
|
branchStorage.delete(mapping);
|
|
4889
|
+
instances.delete(storage);
|
|
4890
|
+
namespaceForStorage.delete(storage);
|
|
4769
4891
|
branchRngs.delete(storage);
|
|
4770
4892
|
captured.delete(storage);
|
|
4771
4893
|
}
|
|
4772
4894
|
timelines.delete(name);
|
|
4773
4895
|
captured.delete(name);
|
|
4896
|
+
faults.restore(name, { rules: [], rngState: createRng(options.seed ?? 0).state() });
|
|
4897
|
+
namespaceClock(name).reset();
|
|
4898
|
+
(branchRngs.get(name) ?? rng).reset();
|
|
4899
|
+
journal.clear(name);
|
|
4900
|
+
metrics.reset(name);
|
|
4774
4901
|
};
|
|
4775
4902
|
const snapshot = (name = DEFAULT_NAMESPACE) => {
|
|
4776
4903
|
return checkpoint(name, "main").value.snapshot;
|
|
@@ -4808,6 +4935,53 @@ var createRuntime = (options) => {
|
|
|
4808
4935
|
rng,
|
|
4809
4936
|
credentials,
|
|
4810
4937
|
webhooks: options.webhooks,
|
|
4938
|
+
isolateNamespaces() {
|
|
4939
|
+
if (publicNamespaces.size > 1)
|
|
4940
|
+
throw new Error("enable namespace isolation before creating named namespaces");
|
|
4941
|
+
isolatedNamespaces = true;
|
|
4942
|
+
faults.isolateNamespaces();
|
|
4943
|
+
},
|
|
4944
|
+
namespaceClock,
|
|
4945
|
+
namespaceOf(request) {
|
|
4946
|
+
const url = new URL(request.url);
|
|
4947
|
+
const prefixed = PATH_PREFIX.exec(url.pathname);
|
|
4948
|
+
const selected = request.headers.get(NAMESPACE_HEADER) ?? (prefixed ? decodeURIComponent(prefixed[1]) : void 0);
|
|
4949
|
+
const path = prefixed ? prefixed[2] ?? "/" : url.pathname;
|
|
4950
|
+
if (path === "/__admin" || path.startsWith("/__admin/"))
|
|
4951
|
+
return url.searchParams.get("namespace") ?? selected ?? DEFAULT_NAMESPACE;
|
|
4952
|
+
if (selected !== void 0)
|
|
4953
|
+
return selected;
|
|
4954
|
+
const credential = options.credential?.(request);
|
|
4955
|
+
return (credential !== void 0 ? credentials.get(credential) : void 0) ?? DEFAULT_NAMESPACE;
|
|
4956
|
+
},
|
|
4957
|
+
fleetSnapshot(namespace) {
|
|
4958
|
+
instance(namespace);
|
|
4959
|
+
const handle = {};
|
|
4960
|
+
fleetPoints.set(handle, {
|
|
4961
|
+
namespace,
|
|
4962
|
+
state: capture(namespace),
|
|
4963
|
+
faults: faults.snapshot(namespace),
|
|
4964
|
+
webhooks: options.webhooks?.snapshot(namespace)
|
|
4965
|
+
});
|
|
4966
|
+
return handle;
|
|
4967
|
+
},
|
|
4968
|
+
fleetRestore(handle, namespace) {
|
|
4969
|
+
const point = typeof handle === "object" && handle !== null ? fleetPoints.get(handle) : void 0;
|
|
4970
|
+
if (!point || point.namespace !== namespace)
|
|
4971
|
+
throw new Error("invalid fleet checkpoint");
|
|
4972
|
+
restoreNamespace(sqlite, storageNamespace(namespace), point.state.snapshot);
|
|
4973
|
+
captured.set(namespace, point.state.snapshot);
|
|
4974
|
+
const selectedClock = namespaceClock(namespace);
|
|
4975
|
+
selectedClock.freeze();
|
|
4976
|
+
selectedClock.set(point.state.clock.now);
|
|
4977
|
+
if (!point.state.clock.frozen)
|
|
4978
|
+
selectedClock.unfreeze();
|
|
4979
|
+
(branchRngs.get(namespace) ?? rng).setState(point.state.rngState);
|
|
4980
|
+
faults.restore(namespace, point.faults);
|
|
4981
|
+
if (point.webhooks !== void 0)
|
|
4982
|
+
options.webhooks?.restore(namespace, point.webhooks);
|
|
4983
|
+
timelines.delete(namespace);
|
|
4984
|
+
},
|
|
4811
4985
|
applyPreset: (name, namespace = DEFAULT_NAMESPACE, overrides = {}) => {
|
|
4812
4986
|
const preset = options.presets?.[name];
|
|
4813
4987
|
if (!preset)
|
|
@@ -4983,6 +5157,7 @@ var createRuntime = (options) => {
|
|
|
4983
5157
|
startedAt: wallNow(),
|
|
4984
5158
|
wallNow,
|
|
4985
5159
|
clock,
|
|
5160
|
+
namespaceClock,
|
|
4986
5161
|
faults,
|
|
4987
5162
|
metrics,
|
|
4988
5163
|
journal,
|
|
@@ -6000,6 +6175,8 @@ var FullscriptAPI = class {
|
|
|
6000
6175
|
};
|
|
6001
6176
|
|
|
6002
6177
|
export {
|
|
6178
|
+
createClock,
|
|
6179
|
+
parseDuration,
|
|
6003
6180
|
document2 as document,
|
|
6004
6181
|
operationIds,
|
|
6005
6182
|
supportedOperationIds,
|
|
@@ -6020,4 +6197,4 @@ export {
|
|
|
6020
6197
|
envelope,
|
|
6021
6198
|
FullscriptAPI
|
|
6022
6199
|
};
|
|
6023
|
-
//# sourceMappingURL=chunk-
|
|
6200
|
+
//# sourceMappingURL=chunk-L5A2NSLT.js.map
|