@crvouga/mockingbird-service-odx 1.7.1 → 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 +15 -0
- package/dist/{chunk-IS6GBONJ.js → chunk-BSGAYJGM.js} +204 -27
- package/dist/chunk-BSGAYJGM.js.map +7 -0
- package/dist/chunk-WAJT2FWY.js +830 -0
- package/dist/chunk-WAJT2FWY.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-B3AFDDEE.js +0 -363
- package/dist/chunk-B3AFDDEE.js.map +0 -7
- package/dist/chunk-IS6GBONJ.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-odx
|
|
2
2
|
|
|
3
|
+
## 1.8.0 (2026-10-02)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- coordinate HTTP and protocol mocks ([3168653](https://github.com/crvouga/mockingbird/commit/31686534c55a9823fdaa92afc9cc456cf741b809))
|
|
8
|
+
|
|
9
|
+
### Fixes and improvements
|
|
10
|
+
|
|
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
|
+
|
|
3
18
|
## 1.7.1 (2026-10-01)
|
|
4
19
|
|
|
5
20
|
### Fixes and improvements
|
|
@@ -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();
|
|
192
193
|
if (body.freeze === true)
|
|
193
|
-
|
|
194
|
+
clock.freeze();
|
|
194
195
|
if (body.set !== void 0) {
|
|
195
196
|
const instant = parseInstant(body.set);
|
|
196
197
|
if (instant === void 0)
|
|
197
198
|
return adminError(400, "set: expected epoch ms or ISO-8601");
|
|
198
|
-
|
|
199
|
+
clock.set(instant);
|
|
199
200
|
}
|
|
200
201
|
if (body.advance !== void 0) {
|
|
201
202
|
const delta = parseDuration(body.advance);
|
|
202
203
|
if (delta === void 0)
|
|
203
204
|
return adminError(400, 'advance: expected ms or "15m"-style');
|
|
204
|
-
|
|
205
|
+
clock.advance(delta);
|
|
205
206
|
}
|
|
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 }) => {
|
|
@@ -467,7 +468,33 @@ var faultResponse = (rule) => {
|
|
|
467
468
|
};
|
|
468
469
|
var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) => {
|
|
469
470
|
const entries = [];
|
|
471
|
+
let isolated = false;
|
|
472
|
+
const scopedRngs = /* @__PURE__ */ new Map();
|
|
473
|
+
const random = (namespace) => {
|
|
474
|
+
if (!isolated || namespace === "default")
|
|
475
|
+
return rng;
|
|
476
|
+
let scoped = scopedRngs.get(namespace);
|
|
477
|
+
if (!scoped) {
|
|
478
|
+
scoped = createRng(rng.seed);
|
|
479
|
+
scopedRngs.set(namespace, scoped);
|
|
480
|
+
}
|
|
481
|
+
return scoped;
|
|
482
|
+
};
|
|
470
483
|
return {
|
|
484
|
+
isolateNamespaces() {
|
|
485
|
+
isolated = true;
|
|
486
|
+
},
|
|
487
|
+
snapshot(namespace) {
|
|
488
|
+
return {
|
|
489
|
+
rules: structuredClone(entries.map((entry, position) => ({
|
|
490
|
+
...entry.rule,
|
|
491
|
+
remaining: entry.remaining,
|
|
492
|
+
hits: entry.hits,
|
|
493
|
+
position
|
|
494
|
+
})).filter((entry) => entry.namespace === namespace)),
|
|
495
|
+
rngState: random(namespace).state()
|
|
496
|
+
};
|
|
497
|
+
},
|
|
471
498
|
add(rule) {
|
|
472
499
|
const existing = entries.findIndex((e) => e.rule.id === rule.id);
|
|
473
500
|
const entry = { rule, remaining: rule.count ?? null, hits: 0 };
|
|
@@ -487,6 +514,16 @@ var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((reso
|
|
|
487
514
|
},
|
|
488
515
|
clear() {
|
|
489
516
|
entries.length = 0;
|
|
517
|
+
rng.reset();
|
|
518
|
+
scopedRngs.clear();
|
|
519
|
+
},
|
|
520
|
+
restore(namespace, state) {
|
|
521
|
+
for (let i = entries.length - 1; i >= 0; i--)
|
|
522
|
+
if (entries[i]?.rule.namespace === namespace)
|
|
523
|
+
entries.splice(i, 1);
|
|
524
|
+
for (const { remaining, hits, position, ...rule } of state.rules)
|
|
525
|
+
entries.splice(Math.min(position, entries.length), 0, { rule, remaining, hits });
|
|
526
|
+
random(namespace).setState(state.rngState);
|
|
490
527
|
},
|
|
491
528
|
async take(candidate) {
|
|
492
529
|
const hits = [];
|
|
@@ -496,7 +533,7 @@ var createFaultRegistry = (rng = createRng(0), sleep = (ms) => new Promise((reso
|
|
|
496
533
|
if (!matches(entry.rule, candidate))
|
|
497
534
|
continue;
|
|
498
535
|
const rate = entry.rule.rate ?? 1;
|
|
499
|
-
if (
|
|
536
|
+
if (random(candidate.namespace).next() >= rate)
|
|
500
537
|
continue;
|
|
501
538
|
entry.hits++;
|
|
502
539
|
if (entry.remaining !== null)
|
|
@@ -832,7 +869,8 @@ var annotateResponse = (response, extra) => {
|
|
|
832
869
|
var responseNotes = (response) => notes.get(response);
|
|
833
870
|
|
|
834
871
|
// ../core/dist/metrics.js
|
|
835
|
-
var createMetrics = () => {
|
|
872
|
+
var createMetrics = (partition = true) => {
|
|
873
|
+
const namespaces = /* @__PURE__ */ new Map();
|
|
836
874
|
let requests = 0;
|
|
837
875
|
let faults = 0;
|
|
838
876
|
let totalDurationMs = 0;
|
|
@@ -840,6 +878,14 @@ var createMetrics = () => {
|
|
|
840
878
|
const unmatched = /* @__PURE__ */ new Map();
|
|
841
879
|
return {
|
|
842
880
|
record(entry) {
|
|
881
|
+
if (partition) {
|
|
882
|
+
let scoped = namespaces.get(entry.namespace);
|
|
883
|
+
if (!scoped) {
|
|
884
|
+
scoped = createMetrics(false);
|
|
885
|
+
namespaces.set(entry.namespace, scoped);
|
|
886
|
+
}
|
|
887
|
+
scoped.record(entry);
|
|
888
|
+
}
|
|
843
889
|
requests++;
|
|
844
890
|
totalDurationMs += entry.durationMs;
|
|
845
891
|
if (entry.faultId !== void 0)
|
|
@@ -851,7 +897,7 @@ var createMetrics = () => {
|
|
|
851
897
|
unmatched.set(route, (unmatched.get(route) ?? 0) + 1);
|
|
852
898
|
}
|
|
853
899
|
},
|
|
854
|
-
report: () => ({
|
|
900
|
+
report: (namespace) => namespace !== void 0 ? (namespaces.get(namespace) ?? createMetrics(false)).report() : {
|
|
855
901
|
requests,
|
|
856
902
|
byOperation: Object.fromEntries([...byOperation].sort(([a], [b]) => a.localeCompare(b))),
|
|
857
903
|
unmatched: [...unmatched].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([route, count]) => {
|
|
@@ -860,8 +906,13 @@ var createMetrics = () => {
|
|
|
860
906
|
}),
|
|
861
907
|
faults,
|
|
862
908
|
totalDurationMs
|
|
863
|
-
}
|
|
864
|
-
reset() {
|
|
909
|
+
},
|
|
910
|
+
reset(namespace) {
|
|
911
|
+
if (namespace !== void 0) {
|
|
912
|
+
namespaces.delete(namespace);
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
namespaces.clear();
|
|
865
916
|
requests = 0;
|
|
866
917
|
faults = 0;
|
|
867
918
|
totalDurationMs = 0;
|
|
@@ -3759,7 +3810,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
3759
3810
|
};
|
|
3760
3811
|
|
|
3761
3812
|
// ../core/dist/version.js
|
|
3762
|
-
var PACKAGE_VERSION = true ? "1.
|
|
3813
|
+
var PACKAGE_VERSION = true ? "1.8.0" : UNRELEASED_VERSION;
|
|
3763
3814
|
|
|
3764
3815
|
// ../core/dist/signing.js
|
|
3765
3816
|
var encoder = new TextEncoder();
|
|
@@ -3852,7 +3903,9 @@ var createWebhookHub = (options) => {
|
|
|
3852
3903
|
const faults = /* @__PURE__ */ new Map();
|
|
3853
3904
|
const held = /* @__PURE__ */ new Map();
|
|
3854
3905
|
const inFlight = /* @__PURE__ */ new Set();
|
|
3906
|
+
const controllers = /* @__PURE__ */ new Map();
|
|
3855
3907
|
let immediate = Promise.resolve();
|
|
3908
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
3856
3909
|
const track = (work) => {
|
|
3857
3910
|
inFlight.add(work);
|
|
3858
3911
|
void work.finally(() => inFlight.delete(work));
|
|
@@ -3873,6 +3926,7 @@ var createWebhookHub = (options) => {
|
|
|
3873
3926
|
responseBody: null
|
|
3874
3927
|
};
|
|
3875
3928
|
const controller = new AbortController();
|
|
3929
|
+
controllers.set(delivery.id, controller);
|
|
3876
3930
|
const timer = scheduleTimer(() => controller.abort(), timeoutMs);
|
|
3877
3931
|
try {
|
|
3878
3932
|
const signed = await options.signer({
|
|
@@ -3902,6 +3956,7 @@ var createWebhookHub = (options) => {
|
|
|
3902
3956
|
} catch (error) {
|
|
3903
3957
|
record.error = controller.signal.aborted ? `timed out after ${timeoutMs}ms` : error instanceof Error ? error.message : String(error);
|
|
3904
3958
|
} finally {
|
|
3959
|
+
controllers.delete(delivery.id);
|
|
3905
3960
|
cancel(timer);
|
|
3906
3961
|
record.durationMs = now() - started;
|
|
3907
3962
|
delivery.attempts.push(record);
|
|
@@ -3919,6 +3974,8 @@ var createWebhookHub = (options) => {
|
|
|
3919
3974
|
if (!payloads.has(delivery.id))
|
|
3920
3975
|
return;
|
|
3921
3976
|
await attempt(delivery).then((ok) => {
|
|
3977
|
+
if (!payloads.has(delivery.id))
|
|
3978
|
+
return;
|
|
3922
3979
|
if (ok)
|
|
3923
3980
|
delivery.state = "delivered";
|
|
3924
3981
|
else
|
|
@@ -3980,6 +4037,37 @@ var createWebhookHub = (options) => {
|
|
|
3980
4037
|
fanOut(message2);
|
|
3981
4038
|
};
|
|
3982
4039
|
const hub = {
|
|
4040
|
+
pending(namespace) {
|
|
4041
|
+
return inFlight.size + (held.get(namespace)?.length ?? 0) + [...deliveries.values()].filter((d) => d.namespace === namespace && d.state === "pending").length;
|
|
4042
|
+
},
|
|
4043
|
+
snapshot(namespace) {
|
|
4044
|
+
if (hub.pending(namespace) > 0)
|
|
4045
|
+
throw new Error("webhooks are not quiescent");
|
|
4046
|
+
const handle = {};
|
|
4047
|
+
snapshots.set(handle, structuredClone({
|
|
4048
|
+
namespace,
|
|
4049
|
+
endpoints: own.get(namespace) ?? [],
|
|
4050
|
+
messages: messages.filter((m) => m.namespace === namespace),
|
|
4051
|
+
deliveries: [...deliveries].filter(([, d]) => d.namespace === namespace),
|
|
4052
|
+
payloads: [...payloads].filter(([, p]) => p.message.namespace === namespace),
|
|
4053
|
+
faults: faults.get(namespace) ?? []
|
|
4054
|
+
}));
|
|
4055
|
+
return handle;
|
|
4056
|
+
},
|
|
4057
|
+
restore(namespace, handle) {
|
|
4058
|
+
const point = typeof handle === "object" && handle !== null ? snapshots.get(handle) : void 0;
|
|
4059
|
+
if (!point || point.namespace !== namespace || hub.pending(namespace) > 0)
|
|
4060
|
+
throw new Error("invalid webhook restore");
|
|
4061
|
+
hub.clear(namespace);
|
|
4062
|
+
const copied = structuredClone(point);
|
|
4063
|
+
own.set(namespace, copied.endpoints);
|
|
4064
|
+
messages.push(...copied.messages);
|
|
4065
|
+
for (const [id2, delivery] of copied.deliveries)
|
|
4066
|
+
deliveries.set(id2, delivery);
|
|
4067
|
+
for (const [id2, payload] of copied.payloads)
|
|
4068
|
+
payloads.set(id2, payload);
|
|
4069
|
+
faults.set(namespace, copied.faults);
|
|
4070
|
+
},
|
|
3983
4071
|
publish(input) {
|
|
3984
4072
|
const contentType = input.contentType ?? (input.form ? "application/x-www-form-urlencoded" : "application/json");
|
|
3985
4073
|
const body = typeof input.body === "string" ? input.body : input.form ? new URLSearchParams(input.form).toString() : JSON.stringify(input.body);
|
|
@@ -4070,6 +4158,7 @@ var createWebhookHub = (options) => {
|
|
|
4070
4158
|
for (const [id2, delivery] of deliveries) {
|
|
4071
4159
|
if (namespace !== void 0 && delivery.namespace !== namespace)
|
|
4072
4160
|
continue;
|
|
4161
|
+
controllers.get(id2)?.abort();
|
|
4073
4162
|
const timer = pending.get(id2);
|
|
4074
4163
|
if (timer !== void 0)
|
|
4075
4164
|
cancel(timer);
|
|
@@ -4257,6 +4346,20 @@ var createRuntime = (options) => {
|
|
|
4257
4346
|
const instances = /* @__PURE__ */ new Map();
|
|
4258
4347
|
const publicNamespaces = /* @__PURE__ */ new Set();
|
|
4259
4348
|
const branchRngs = /* @__PURE__ */ new Map();
|
|
4349
|
+
const namespaceClocks = /* @__PURE__ */ new Map();
|
|
4350
|
+
const namespaceForStorage = /* @__PURE__ */ new Map();
|
|
4351
|
+
let isolatedNamespaces = false;
|
|
4352
|
+
const namespaceClock = (name = DEFAULT_NAMESPACE) => {
|
|
4353
|
+
if (!isolatedNamespaces || name === DEFAULT_NAMESPACE)
|
|
4354
|
+
return clock;
|
|
4355
|
+
let found = namespaceClocks.get(name);
|
|
4356
|
+
if (!found) {
|
|
4357
|
+
found = createClock();
|
|
4358
|
+
namespaceClocks.set(name, found);
|
|
4359
|
+
}
|
|
4360
|
+
return found;
|
|
4361
|
+
};
|
|
4362
|
+
const fleetPoints = /* @__PURE__ */ new WeakMap();
|
|
4260
4363
|
const timelines = /* @__PURE__ */ new Map();
|
|
4261
4364
|
const branchStorage = /* @__PURE__ */ new Map();
|
|
4262
4365
|
const captured = /* @__PURE__ */ new Map();
|
|
@@ -4270,17 +4373,21 @@ var createRuntime = (options) => {
|
|
|
4270
4373
|
if (!NAMESPACE_PATTERN.test(key) || !NAMESPACE_PATTERN.test(publicNamespace)) {
|
|
4271
4374
|
throw new RangeError(`namespace must match ${NAMESPACE_PATTERN}: ${JSON.stringify(publicNamespace)}`);
|
|
4272
4375
|
}
|
|
4376
|
+
const createdContextRng = isolatedRng ?? (isolatedNamespaces && key !== DEFAULT_NAMESPACE ? createRng(options.seed ?? 0) : rng);
|
|
4273
4377
|
const created = options.create({
|
|
4274
4378
|
namespace: storageNamespace(key),
|
|
4275
4379
|
publicNamespace,
|
|
4276
4380
|
sqlite,
|
|
4277
|
-
clock,
|
|
4278
|
-
rng:
|
|
4381
|
+
clock: namespaceClock(publicNamespace),
|
|
4382
|
+
rng: createdContextRng
|
|
4279
4383
|
});
|
|
4280
4384
|
instances.set(key, created);
|
|
4385
|
+
namespaceForStorage.set(key, publicNamespace);
|
|
4281
4386
|
publicNamespaces.add(publicNamespace);
|
|
4282
4387
|
if (isolatedRng)
|
|
4283
4388
|
branchRngs.set(key, isolatedRng);
|
|
4389
|
+
else if (isolatedNamespaces && key !== DEFAULT_NAMESPACE)
|
|
4390
|
+
branchRngs.set(key, createdContextRng);
|
|
4284
4391
|
return created;
|
|
4285
4392
|
};
|
|
4286
4393
|
const instance = (name = DEFAULT_NAMESPACE) => instanceFor(name);
|
|
@@ -4298,7 +4405,7 @@ var createRuntime = (options) => {
|
|
|
4298
4405
|
captured.set(storage, snapshot2);
|
|
4299
4406
|
return Object.freeze({
|
|
4300
4407
|
snapshot: snapshot2,
|
|
4301
|
-
clock: Object.freeze(
|
|
4408
|
+
clock: Object.freeze(namespaceClock(namespaceForStorage.get(storage) ?? storage).state()),
|
|
4302
4409
|
rngState: (branchRngs.get(storage) ?? rng).state()
|
|
4303
4410
|
});
|
|
4304
4411
|
};
|
|
@@ -4308,7 +4415,7 @@ var createRuntime = (options) => {
|
|
|
4308
4415
|
return found;
|
|
4309
4416
|
instance(name);
|
|
4310
4417
|
found = new Timeline({
|
|
4311
|
-
now:
|
|
4418
|
+
now: namespaceClock(name).now,
|
|
4312
4419
|
...options.maxCheckpoints !== void 0 ? { maxCheckpoints: options.maxCheckpoints } : {}
|
|
4313
4420
|
});
|
|
4314
4421
|
found.commit(capture(name));
|
|
@@ -4335,12 +4442,13 @@ var createRuntime = (options) => {
|
|
|
4335
4442
|
const point = history2.checkout("main", at);
|
|
4336
4443
|
restoreNamespace(sqlite, storageNamespace(namespace), point.value.snapshot);
|
|
4337
4444
|
captured.set(namespace, point.value.snapshot);
|
|
4338
|
-
rng.setState(point.value.rngState);
|
|
4339
|
-
|
|
4445
|
+
(branchRngs.get(namespace) ?? rng).setState(point.value.rngState);
|
|
4446
|
+
const selectedClock = namespaceClock(namespace);
|
|
4447
|
+
selectedClock.set(point.value.clock.now);
|
|
4340
4448
|
if (point.value.clock.frozen)
|
|
4341
|
-
|
|
4449
|
+
selectedClock.freeze();
|
|
4342
4450
|
else
|
|
4343
|
-
|
|
4451
|
+
selectedClock.unfreeze();
|
|
4344
4452
|
}
|
|
4345
4453
|
return namespace;
|
|
4346
4454
|
}
|
|
@@ -4398,11 +4506,12 @@ var createRuntime = (options) => {
|
|
|
4398
4506
|
const storage = ensureBranch(namespace, branchName);
|
|
4399
4507
|
restoreNamespace(sqlite, storageNamespace(storage), point.value.snapshot);
|
|
4400
4508
|
captured.set(storage, point.value.snapshot);
|
|
4401
|
-
|
|
4509
|
+
const selectedClock = namespaceClock(namespace);
|
|
4510
|
+
selectedClock.set(point.value.clock.now);
|
|
4402
4511
|
if (point.value.clock.frozen)
|
|
4403
|
-
|
|
4512
|
+
selectedClock.freeze();
|
|
4404
4513
|
else
|
|
4405
|
-
|
|
4514
|
+
selectedClock.unfreeze();
|
|
4406
4515
|
(branchRngs.get(storage) ?? rng).setState(point.value.rngState);
|
|
4407
4516
|
};
|
|
4408
4517
|
const reset = async (name = DEFAULT_NAMESPACE) => {
|
|
@@ -4410,10 +4519,21 @@ var createRuntime = (options) => {
|
|
|
4410
4519
|
options.webhooks?.clear();
|
|
4411
4520
|
for (const each of instances.values())
|
|
4412
4521
|
await each.reset();
|
|
4522
|
+
for (const each of branchRngs.values())
|
|
4523
|
+
each.reset();
|
|
4413
4524
|
timelines.clear();
|
|
4525
|
+
for (const storage of branchStorage.values()) {
|
|
4526
|
+
instances.delete(storage);
|
|
4527
|
+
branchRngs.delete(storage);
|
|
4528
|
+
namespaceForStorage.delete(storage);
|
|
4529
|
+
}
|
|
4414
4530
|
branchStorage.clear();
|
|
4415
|
-
branchRngs.clear();
|
|
4416
4531
|
captured.clear();
|
|
4532
|
+
faults.clear();
|
|
4533
|
+
clock.reset();
|
|
4534
|
+
rng.reset();
|
|
4535
|
+
for (const each of namespaceClocks.values())
|
|
4536
|
+
each.reset();
|
|
4417
4537
|
return;
|
|
4418
4538
|
}
|
|
4419
4539
|
options.webhooks?.clear(name);
|
|
@@ -4431,11 +4551,18 @@ var createRuntime = (options) => {
|
|
|
4431
4551
|
else
|
|
4432
4552
|
clearNamespace(sqlite, storageNamespace(storage));
|
|
4433
4553
|
branchStorage.delete(mapping);
|
|
4554
|
+
instances.delete(storage);
|
|
4555
|
+
namespaceForStorage.delete(storage);
|
|
4434
4556
|
branchRngs.delete(storage);
|
|
4435
4557
|
captured.delete(storage);
|
|
4436
4558
|
}
|
|
4437
4559
|
timelines.delete(name);
|
|
4438
4560
|
captured.delete(name);
|
|
4561
|
+
faults.restore(name, { rules: [], rngState: createRng(options.seed ?? 0).state() });
|
|
4562
|
+
namespaceClock(name).reset();
|
|
4563
|
+
(branchRngs.get(name) ?? rng).reset();
|
|
4564
|
+
journal.clear(name);
|
|
4565
|
+
metrics.reset(name);
|
|
4439
4566
|
};
|
|
4440
4567
|
const snapshot = (name = DEFAULT_NAMESPACE) => {
|
|
4441
4568
|
return checkpoint(name, "main").value.snapshot;
|
|
@@ -4473,6 +4600,53 @@ var createRuntime = (options) => {
|
|
|
4473
4600
|
rng,
|
|
4474
4601
|
credentials,
|
|
4475
4602
|
webhooks: options.webhooks,
|
|
4603
|
+
isolateNamespaces() {
|
|
4604
|
+
if (publicNamespaces.size > 1)
|
|
4605
|
+
throw new Error("enable namespace isolation before creating named namespaces");
|
|
4606
|
+
isolatedNamespaces = true;
|
|
4607
|
+
faults.isolateNamespaces();
|
|
4608
|
+
},
|
|
4609
|
+
namespaceClock,
|
|
4610
|
+
namespaceOf(request) {
|
|
4611
|
+
const url = new URL(request.url);
|
|
4612
|
+
const prefixed = PATH_PREFIX.exec(url.pathname);
|
|
4613
|
+
const selected = request.headers.get(NAMESPACE_HEADER) ?? (prefixed ? decodeURIComponent(prefixed[1]) : void 0);
|
|
4614
|
+
const path = prefixed ? prefixed[2] ?? "/" : url.pathname;
|
|
4615
|
+
if (path === "/__admin" || path.startsWith("/__admin/"))
|
|
4616
|
+
return url.searchParams.get("namespace") ?? selected ?? DEFAULT_NAMESPACE;
|
|
4617
|
+
if (selected !== void 0)
|
|
4618
|
+
return selected;
|
|
4619
|
+
const credential = options.credential?.(request);
|
|
4620
|
+
return (credential !== void 0 ? credentials.get(credential) : void 0) ?? DEFAULT_NAMESPACE;
|
|
4621
|
+
},
|
|
4622
|
+
fleetSnapshot(namespace) {
|
|
4623
|
+
instance(namespace);
|
|
4624
|
+
const handle = {};
|
|
4625
|
+
fleetPoints.set(handle, {
|
|
4626
|
+
namespace,
|
|
4627
|
+
state: capture(namespace),
|
|
4628
|
+
faults: faults.snapshot(namespace),
|
|
4629
|
+
webhooks: options.webhooks?.snapshot(namespace)
|
|
4630
|
+
});
|
|
4631
|
+
return handle;
|
|
4632
|
+
},
|
|
4633
|
+
fleetRestore(handle, namespace) {
|
|
4634
|
+
const point = typeof handle === "object" && handle !== null ? fleetPoints.get(handle) : void 0;
|
|
4635
|
+
if (!point || point.namespace !== namespace)
|
|
4636
|
+
throw new Error("invalid fleet checkpoint");
|
|
4637
|
+
restoreNamespace(sqlite, storageNamespace(namespace), point.state.snapshot);
|
|
4638
|
+
captured.set(namespace, point.state.snapshot);
|
|
4639
|
+
const selectedClock = namespaceClock(namespace);
|
|
4640
|
+
selectedClock.freeze();
|
|
4641
|
+
selectedClock.set(point.state.clock.now);
|
|
4642
|
+
if (!point.state.clock.frozen)
|
|
4643
|
+
selectedClock.unfreeze();
|
|
4644
|
+
(branchRngs.get(namespace) ?? rng).setState(point.state.rngState);
|
|
4645
|
+
faults.restore(namespace, point.faults);
|
|
4646
|
+
if (point.webhooks !== void 0)
|
|
4647
|
+
options.webhooks?.restore(namespace, point.webhooks);
|
|
4648
|
+
timelines.delete(namespace);
|
|
4649
|
+
},
|
|
4476
4650
|
applyPreset: (name, namespace = DEFAULT_NAMESPACE, overrides = {}) => {
|
|
4477
4651
|
const preset = options.presets?.[name];
|
|
4478
4652
|
if (!preset)
|
|
@@ -4648,6 +4822,7 @@ var createRuntime = (options) => {
|
|
|
4648
4822
|
startedAt: wallNow(),
|
|
4649
4823
|
wallNow,
|
|
4650
4824
|
clock,
|
|
4825
|
+
namespaceClock,
|
|
4651
4826
|
faults,
|
|
4652
4827
|
metrics,
|
|
4653
4828
|
journal,
|
|
@@ -5779,6 +5954,8 @@ var OdxAPI = class {
|
|
|
5779
5954
|
var publicPatient = ({ partnerUserId: _partner, ...patient }) => patient;
|
|
5780
5955
|
|
|
5781
5956
|
export {
|
|
5957
|
+
createClock,
|
|
5958
|
+
parseDuration,
|
|
5782
5959
|
LABS,
|
|
5783
5960
|
ELEMENTS,
|
|
5784
5961
|
document2 as document,
|
|
@@ -5795,4 +5972,4 @@ export {
|
|
|
5795
5972
|
apiKeyCredential,
|
|
5796
5973
|
OdxAPI
|
|
5797
5974
|
};
|
|
5798
|
-
//# sourceMappingURL=chunk-
|
|
5975
|
+
//# sourceMappingURL=chunk-BSGAYJGM.js.map
|