@crvouga/mockingbird-service-rxvortex 1.8.1 → 1.9.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-CNQMYSGI.js → chunk-HJ32ST6Y.js} +204 -27
- package/dist/chunk-HJ32ST6Y.js.map +7 -0
- package/dist/chunk-USWQ72DY.js +889 -0
- package/dist/chunk-USWQ72DY.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-CNQMYSGI.js.map +0 -7
- package/dist/chunk-U5XXCFRO.js +0 -422
- package/dist/chunk-U5XXCFRO.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-rxvortex
|
|
2
2
|
|
|
3
|
+
## 1.9.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.8.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 }) => {
|
|
@@ -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)
|
|
@@ -1071,7 +1108,8 @@ var annotateResponse = (response, extra) => {
|
|
|
1071
1108
|
var responseNotes = (response) => notes.get(response);
|
|
1072
1109
|
|
|
1073
1110
|
// ../core/dist/metrics.js
|
|
1074
|
-
var createMetrics = () => {
|
|
1111
|
+
var createMetrics = (partition = true) => {
|
|
1112
|
+
const namespaces = /* @__PURE__ */ new Map();
|
|
1075
1113
|
let requests = 0;
|
|
1076
1114
|
let faults = 0;
|
|
1077
1115
|
let totalDurationMs = 0;
|
|
@@ -1079,6 +1117,14 @@ var createMetrics = () => {
|
|
|
1079
1117
|
const unmatched = /* @__PURE__ */ new Map();
|
|
1080
1118
|
return {
|
|
1081
1119
|
record(entry) {
|
|
1120
|
+
if (partition) {
|
|
1121
|
+
let scoped = namespaces.get(entry.namespace);
|
|
1122
|
+
if (!scoped) {
|
|
1123
|
+
scoped = createMetrics(false);
|
|
1124
|
+
namespaces.set(entry.namespace, scoped);
|
|
1125
|
+
}
|
|
1126
|
+
scoped.record(entry);
|
|
1127
|
+
}
|
|
1082
1128
|
requests++;
|
|
1083
1129
|
totalDurationMs += entry.durationMs;
|
|
1084
1130
|
if (entry.faultId !== void 0)
|
|
@@ -1090,7 +1136,7 @@ var createMetrics = () => {
|
|
|
1090
1136
|
unmatched.set(route, (unmatched.get(route) ?? 0) + 1);
|
|
1091
1137
|
}
|
|
1092
1138
|
},
|
|
1093
|
-
report: () => ({
|
|
1139
|
+
report: (namespace) => namespace !== void 0 ? (namespaces.get(namespace) ?? createMetrics(false)).report() : {
|
|
1094
1140
|
requests,
|
|
1095
1141
|
byOperation: Object.fromEntries([...byOperation].sort(([a], [b]) => a.localeCompare(b))),
|
|
1096
1142
|
unmatched: [...unmatched].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([route, count]) => {
|
|
@@ -1099,8 +1145,13 @@ var createMetrics = () => {
|
|
|
1099
1145
|
}),
|
|
1100
1146
|
faults,
|
|
1101
1147
|
totalDurationMs
|
|
1102
|
-
}
|
|
1103
|
-
reset() {
|
|
1148
|
+
},
|
|
1149
|
+
reset(namespace) {
|
|
1150
|
+
if (namespace !== void 0) {
|
|
1151
|
+
namespaces.delete(namespace);
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
namespaces.clear();
|
|
1104
1155
|
requests = 0;
|
|
1105
1156
|
faults = 0;
|
|
1106
1157
|
totalDurationMs = 0;
|
|
@@ -4082,7 +4133,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
4082
4133
|
};
|
|
4083
4134
|
|
|
4084
4135
|
// ../core/dist/version.js
|
|
4085
|
-
var PACKAGE_VERSION = true ? "1.
|
|
4136
|
+
var PACKAGE_VERSION = true ? "1.9.0" : UNRELEASED_VERSION;
|
|
4086
4137
|
|
|
4087
4138
|
// ../core/dist/signing.js
|
|
4088
4139
|
var encoder = new TextEncoder();
|
|
@@ -4175,7 +4226,9 @@ var createWebhookHub = (options) => {
|
|
|
4175
4226
|
const faults = /* @__PURE__ */ new Map();
|
|
4176
4227
|
const held = /* @__PURE__ */ new Map();
|
|
4177
4228
|
const inFlight = /* @__PURE__ */ new Set();
|
|
4229
|
+
const controllers = /* @__PURE__ */ new Map();
|
|
4178
4230
|
let immediate = Promise.resolve();
|
|
4231
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
4179
4232
|
const track = (work) => {
|
|
4180
4233
|
inFlight.add(work);
|
|
4181
4234
|
void work.finally(() => inFlight.delete(work));
|
|
@@ -4196,6 +4249,7 @@ var createWebhookHub = (options) => {
|
|
|
4196
4249
|
responseBody: null
|
|
4197
4250
|
};
|
|
4198
4251
|
const controller = new AbortController();
|
|
4252
|
+
controllers.set(delivery.id, controller);
|
|
4199
4253
|
const timer = scheduleTimer(() => controller.abort(), timeoutMs);
|
|
4200
4254
|
try {
|
|
4201
4255
|
const signed = await options.signer({
|
|
@@ -4225,6 +4279,7 @@ var createWebhookHub = (options) => {
|
|
|
4225
4279
|
} catch (error) {
|
|
4226
4280
|
record2.error = controller.signal.aborted ? `timed out after ${timeoutMs}ms` : error instanceof Error ? error.message : String(error);
|
|
4227
4281
|
} finally {
|
|
4282
|
+
controllers.delete(delivery.id);
|
|
4228
4283
|
cancel(timer);
|
|
4229
4284
|
record2.durationMs = now() - started;
|
|
4230
4285
|
delivery.attempts.push(record2);
|
|
@@ -4242,6 +4297,8 @@ var createWebhookHub = (options) => {
|
|
|
4242
4297
|
if (!payloads.has(delivery.id))
|
|
4243
4298
|
return;
|
|
4244
4299
|
await attempt(delivery).then((ok) => {
|
|
4300
|
+
if (!payloads.has(delivery.id))
|
|
4301
|
+
return;
|
|
4245
4302
|
if (ok)
|
|
4246
4303
|
delivery.state = "delivered";
|
|
4247
4304
|
else
|
|
@@ -4303,6 +4360,37 @@ var createWebhookHub = (options) => {
|
|
|
4303
4360
|
fanOut(message);
|
|
4304
4361
|
};
|
|
4305
4362
|
const hub = {
|
|
4363
|
+
pending(namespace) {
|
|
4364
|
+
return inFlight.size + (held.get(namespace)?.length ?? 0) + [...deliveries.values()].filter((d) => d.namespace === namespace && d.state === "pending").length;
|
|
4365
|
+
},
|
|
4366
|
+
snapshot(namespace) {
|
|
4367
|
+
if (hub.pending(namespace) > 0)
|
|
4368
|
+
throw new Error("webhooks are not quiescent");
|
|
4369
|
+
const handle = {};
|
|
4370
|
+
snapshots.set(handle, structuredClone({
|
|
4371
|
+
namespace,
|
|
4372
|
+
endpoints: own.get(namespace) ?? [],
|
|
4373
|
+
messages: messages.filter((m) => m.namespace === namespace),
|
|
4374
|
+
deliveries: [...deliveries].filter(([, d]) => d.namespace === namespace),
|
|
4375
|
+
payloads: [...payloads].filter(([, p]) => p.message.namespace === namespace),
|
|
4376
|
+
faults: faults.get(namespace) ?? []
|
|
4377
|
+
}));
|
|
4378
|
+
return handle;
|
|
4379
|
+
},
|
|
4380
|
+
restore(namespace, handle) {
|
|
4381
|
+
const point = typeof handle === "object" && handle !== null ? snapshots.get(handle) : void 0;
|
|
4382
|
+
if (!point || point.namespace !== namespace || hub.pending(namespace) > 0)
|
|
4383
|
+
throw new Error("invalid webhook restore");
|
|
4384
|
+
hub.clear(namespace);
|
|
4385
|
+
const copied = structuredClone(point);
|
|
4386
|
+
own.set(namespace, copied.endpoints);
|
|
4387
|
+
messages.push(...copied.messages);
|
|
4388
|
+
for (const [id2, delivery] of copied.deliveries)
|
|
4389
|
+
deliveries.set(id2, delivery);
|
|
4390
|
+
for (const [id2, payload] of copied.payloads)
|
|
4391
|
+
payloads.set(id2, payload);
|
|
4392
|
+
faults.set(namespace, copied.faults);
|
|
4393
|
+
},
|
|
4306
4394
|
publish(input) {
|
|
4307
4395
|
const contentType = input.contentType ?? (input.form ? "application/x-www-form-urlencoded" : "application/json");
|
|
4308
4396
|
const body = typeof input.body === "string" ? input.body : input.form ? new URLSearchParams(input.form).toString() : JSON.stringify(input.body);
|
|
@@ -4393,6 +4481,7 @@ var createWebhookHub = (options) => {
|
|
|
4393
4481
|
for (const [id2, delivery] of deliveries) {
|
|
4394
4482
|
if (namespace !== void 0 && delivery.namespace !== namespace)
|
|
4395
4483
|
continue;
|
|
4484
|
+
controllers.get(id2)?.abort();
|
|
4396
4485
|
const timer = pending.get(id2);
|
|
4397
4486
|
if (timer !== void 0)
|
|
4398
4487
|
cancel(timer);
|
|
@@ -4580,6 +4669,20 @@ var createRuntime = (options) => {
|
|
|
4580
4669
|
const instances = /* @__PURE__ */ new Map();
|
|
4581
4670
|
const publicNamespaces = /* @__PURE__ */ new Set();
|
|
4582
4671
|
const branchRngs = /* @__PURE__ */ new Map();
|
|
4672
|
+
const namespaceClocks = /* @__PURE__ */ new Map();
|
|
4673
|
+
const namespaceForStorage = /* @__PURE__ */ new Map();
|
|
4674
|
+
let isolatedNamespaces = false;
|
|
4675
|
+
const namespaceClock = (name = DEFAULT_NAMESPACE) => {
|
|
4676
|
+
if (!isolatedNamespaces || name === DEFAULT_NAMESPACE)
|
|
4677
|
+
return clock;
|
|
4678
|
+
let found = namespaceClocks.get(name);
|
|
4679
|
+
if (!found) {
|
|
4680
|
+
found = createClock();
|
|
4681
|
+
namespaceClocks.set(name, found);
|
|
4682
|
+
}
|
|
4683
|
+
return found;
|
|
4684
|
+
};
|
|
4685
|
+
const fleetPoints = /* @__PURE__ */ new WeakMap();
|
|
4583
4686
|
const timelines = /* @__PURE__ */ new Map();
|
|
4584
4687
|
const branchStorage = /* @__PURE__ */ new Map();
|
|
4585
4688
|
const captured = /* @__PURE__ */ new Map();
|
|
@@ -4593,17 +4696,21 @@ var createRuntime = (options) => {
|
|
|
4593
4696
|
if (!NAMESPACE_PATTERN.test(key) || !NAMESPACE_PATTERN.test(publicNamespace)) {
|
|
4594
4697
|
throw new RangeError(`namespace must match ${NAMESPACE_PATTERN}: ${JSON.stringify(publicNamespace)}`);
|
|
4595
4698
|
}
|
|
4699
|
+
const createdContextRng = isolatedRng ?? (isolatedNamespaces && key !== DEFAULT_NAMESPACE ? createRng(options.seed ?? 0) : rng);
|
|
4596
4700
|
const created = options.create({
|
|
4597
4701
|
namespace: storageNamespace(key),
|
|
4598
4702
|
publicNamespace,
|
|
4599
4703
|
sqlite,
|
|
4600
|
-
clock,
|
|
4601
|
-
rng:
|
|
4704
|
+
clock: namespaceClock(publicNamespace),
|
|
4705
|
+
rng: createdContextRng
|
|
4602
4706
|
});
|
|
4603
4707
|
instances.set(key, created);
|
|
4708
|
+
namespaceForStorage.set(key, publicNamespace);
|
|
4604
4709
|
publicNamespaces.add(publicNamespace);
|
|
4605
4710
|
if (isolatedRng)
|
|
4606
4711
|
branchRngs.set(key, isolatedRng);
|
|
4712
|
+
else if (isolatedNamespaces && key !== DEFAULT_NAMESPACE)
|
|
4713
|
+
branchRngs.set(key, createdContextRng);
|
|
4607
4714
|
return created;
|
|
4608
4715
|
};
|
|
4609
4716
|
const instance = (name = DEFAULT_NAMESPACE) => instanceFor(name);
|
|
@@ -4621,7 +4728,7 @@ var createRuntime = (options) => {
|
|
|
4621
4728
|
captured.set(storage, snapshot2);
|
|
4622
4729
|
return Object.freeze({
|
|
4623
4730
|
snapshot: snapshot2,
|
|
4624
|
-
clock: Object.freeze(
|
|
4731
|
+
clock: Object.freeze(namespaceClock(namespaceForStorage.get(storage) ?? storage).state()),
|
|
4625
4732
|
rngState: (branchRngs.get(storage) ?? rng).state()
|
|
4626
4733
|
});
|
|
4627
4734
|
};
|
|
@@ -4631,7 +4738,7 @@ var createRuntime = (options) => {
|
|
|
4631
4738
|
return found;
|
|
4632
4739
|
instance(name);
|
|
4633
4740
|
found = new Timeline({
|
|
4634
|
-
now:
|
|
4741
|
+
now: namespaceClock(name).now,
|
|
4635
4742
|
...options.maxCheckpoints !== void 0 ? { maxCheckpoints: options.maxCheckpoints } : {}
|
|
4636
4743
|
});
|
|
4637
4744
|
found.commit(capture(name));
|
|
@@ -4658,12 +4765,13 @@ var createRuntime = (options) => {
|
|
|
4658
4765
|
const point = history2.checkout("main", at);
|
|
4659
4766
|
restoreNamespace(sqlite, storageNamespace(namespace), point.value.snapshot);
|
|
4660
4767
|
captured.set(namespace, point.value.snapshot);
|
|
4661
|
-
rng.setState(point.value.rngState);
|
|
4662
|
-
|
|
4768
|
+
(branchRngs.get(namespace) ?? rng).setState(point.value.rngState);
|
|
4769
|
+
const selectedClock = namespaceClock(namespace);
|
|
4770
|
+
selectedClock.set(point.value.clock.now);
|
|
4663
4771
|
if (point.value.clock.frozen)
|
|
4664
|
-
|
|
4772
|
+
selectedClock.freeze();
|
|
4665
4773
|
else
|
|
4666
|
-
|
|
4774
|
+
selectedClock.unfreeze();
|
|
4667
4775
|
}
|
|
4668
4776
|
return namespace;
|
|
4669
4777
|
}
|
|
@@ -4721,11 +4829,12 @@ var createRuntime = (options) => {
|
|
|
4721
4829
|
const storage = ensureBranch(namespace, branchName);
|
|
4722
4830
|
restoreNamespace(sqlite, storageNamespace(storage), point.value.snapshot);
|
|
4723
4831
|
captured.set(storage, point.value.snapshot);
|
|
4724
|
-
|
|
4832
|
+
const selectedClock = namespaceClock(namespace);
|
|
4833
|
+
selectedClock.set(point.value.clock.now);
|
|
4725
4834
|
if (point.value.clock.frozen)
|
|
4726
|
-
|
|
4835
|
+
selectedClock.freeze();
|
|
4727
4836
|
else
|
|
4728
|
-
|
|
4837
|
+
selectedClock.unfreeze();
|
|
4729
4838
|
(branchRngs.get(storage) ?? rng).setState(point.value.rngState);
|
|
4730
4839
|
};
|
|
4731
4840
|
const reset = async (name = DEFAULT_NAMESPACE) => {
|
|
@@ -4733,10 +4842,21 @@ var createRuntime = (options) => {
|
|
|
4733
4842
|
options.webhooks?.clear();
|
|
4734
4843
|
for (const each of instances.values())
|
|
4735
4844
|
await each.reset();
|
|
4845
|
+
for (const each of branchRngs.values())
|
|
4846
|
+
each.reset();
|
|
4736
4847
|
timelines.clear();
|
|
4848
|
+
for (const storage of branchStorage.values()) {
|
|
4849
|
+
instances.delete(storage);
|
|
4850
|
+
branchRngs.delete(storage);
|
|
4851
|
+
namespaceForStorage.delete(storage);
|
|
4852
|
+
}
|
|
4737
4853
|
branchStorage.clear();
|
|
4738
|
-
branchRngs.clear();
|
|
4739
4854
|
captured.clear();
|
|
4855
|
+
faults.clear();
|
|
4856
|
+
clock.reset();
|
|
4857
|
+
rng.reset();
|
|
4858
|
+
for (const each of namespaceClocks.values())
|
|
4859
|
+
each.reset();
|
|
4740
4860
|
return;
|
|
4741
4861
|
}
|
|
4742
4862
|
options.webhooks?.clear(name);
|
|
@@ -4754,11 +4874,18 @@ var createRuntime = (options) => {
|
|
|
4754
4874
|
else
|
|
4755
4875
|
clearNamespace(sqlite, storageNamespace(storage));
|
|
4756
4876
|
branchStorage.delete(mapping);
|
|
4877
|
+
instances.delete(storage);
|
|
4878
|
+
namespaceForStorage.delete(storage);
|
|
4757
4879
|
branchRngs.delete(storage);
|
|
4758
4880
|
captured.delete(storage);
|
|
4759
4881
|
}
|
|
4760
4882
|
timelines.delete(name);
|
|
4761
4883
|
captured.delete(name);
|
|
4884
|
+
faults.restore(name, { rules: [], rngState: createRng(options.seed ?? 0).state() });
|
|
4885
|
+
namespaceClock(name).reset();
|
|
4886
|
+
(branchRngs.get(name) ?? rng).reset();
|
|
4887
|
+
journal.clear(name);
|
|
4888
|
+
metrics.reset(name);
|
|
4762
4889
|
};
|
|
4763
4890
|
const snapshot = (name = DEFAULT_NAMESPACE) => {
|
|
4764
4891
|
return checkpoint(name, "main").value.snapshot;
|
|
@@ -4796,6 +4923,53 @@ var createRuntime = (options) => {
|
|
|
4796
4923
|
rng,
|
|
4797
4924
|
credentials,
|
|
4798
4925
|
webhooks: options.webhooks,
|
|
4926
|
+
isolateNamespaces() {
|
|
4927
|
+
if (publicNamespaces.size > 1)
|
|
4928
|
+
throw new Error("enable namespace isolation before creating named namespaces");
|
|
4929
|
+
isolatedNamespaces = true;
|
|
4930
|
+
faults.isolateNamespaces();
|
|
4931
|
+
},
|
|
4932
|
+
namespaceClock,
|
|
4933
|
+
namespaceOf(request) {
|
|
4934
|
+
const url = new URL(request.url);
|
|
4935
|
+
const prefixed = PATH_PREFIX.exec(url.pathname);
|
|
4936
|
+
const selected = request.headers.get(NAMESPACE_HEADER) ?? (prefixed ? decodeURIComponent(prefixed[1]) : void 0);
|
|
4937
|
+
const path = prefixed ? prefixed[2] ?? "/" : url.pathname;
|
|
4938
|
+
if (path === "/__admin" || path.startsWith("/__admin/"))
|
|
4939
|
+
return url.searchParams.get("namespace") ?? selected ?? DEFAULT_NAMESPACE;
|
|
4940
|
+
if (selected !== void 0)
|
|
4941
|
+
return selected;
|
|
4942
|
+
const credential = options.credential?.(request);
|
|
4943
|
+
return (credential !== void 0 ? credentials.get(credential) : void 0) ?? DEFAULT_NAMESPACE;
|
|
4944
|
+
},
|
|
4945
|
+
fleetSnapshot(namespace) {
|
|
4946
|
+
instance(namespace);
|
|
4947
|
+
const handle = {};
|
|
4948
|
+
fleetPoints.set(handle, {
|
|
4949
|
+
namespace,
|
|
4950
|
+
state: capture(namespace),
|
|
4951
|
+
faults: faults.snapshot(namespace),
|
|
4952
|
+
webhooks: options.webhooks?.snapshot(namespace)
|
|
4953
|
+
});
|
|
4954
|
+
return handle;
|
|
4955
|
+
},
|
|
4956
|
+
fleetRestore(handle, namespace) {
|
|
4957
|
+
const point = typeof handle === "object" && handle !== null ? fleetPoints.get(handle) : void 0;
|
|
4958
|
+
if (!point || point.namespace !== namespace)
|
|
4959
|
+
throw new Error("invalid fleet checkpoint");
|
|
4960
|
+
restoreNamespace(sqlite, storageNamespace(namespace), point.state.snapshot);
|
|
4961
|
+
captured.set(namespace, point.state.snapshot);
|
|
4962
|
+
const selectedClock = namespaceClock(namespace);
|
|
4963
|
+
selectedClock.freeze();
|
|
4964
|
+
selectedClock.set(point.state.clock.now);
|
|
4965
|
+
if (!point.state.clock.frozen)
|
|
4966
|
+
selectedClock.unfreeze();
|
|
4967
|
+
(branchRngs.get(namespace) ?? rng).setState(point.state.rngState);
|
|
4968
|
+
faults.restore(namespace, point.faults);
|
|
4969
|
+
if (point.webhooks !== void 0)
|
|
4970
|
+
options.webhooks?.restore(namespace, point.webhooks);
|
|
4971
|
+
timelines.delete(namespace);
|
|
4972
|
+
},
|
|
4799
4973
|
applyPreset: (name, namespace = DEFAULT_NAMESPACE, overrides = {}) => {
|
|
4800
4974
|
const preset = options.presets?.[name];
|
|
4801
4975
|
if (!preset)
|
|
@@ -4971,6 +5145,7 @@ var createRuntime = (options) => {
|
|
|
4971
5145
|
startedAt: wallNow(),
|
|
4972
5146
|
wallNow,
|
|
4973
5147
|
clock,
|
|
5148
|
+
namespaceClock,
|
|
4974
5149
|
faults,
|
|
4975
5150
|
metrics,
|
|
4976
5151
|
journal,
|
|
@@ -5892,6 +6067,8 @@ var RxVortexAPI = class {
|
|
|
5892
6067
|
};
|
|
5893
6068
|
|
|
5894
6069
|
export {
|
|
6070
|
+
createClock,
|
|
6071
|
+
parseDuration,
|
|
5895
6072
|
document2 as document,
|
|
5896
6073
|
operationIds,
|
|
5897
6074
|
supportedOperationIds,
|
|
@@ -5905,4 +6082,4 @@ export {
|
|
|
5905
6082
|
tokenCredential,
|
|
5906
6083
|
RxVortexAPI
|
|
5907
6084
|
};
|
|
5908
|
-
//# sourceMappingURL=chunk-
|
|
6085
|
+
//# sourceMappingURL=chunk-HJ32ST6Y.js.map
|