@crvouga/mockingbird-service-flex 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-56LAVEQL.js → chunk-O2G3Z532.js} +205 -28
- package/dist/chunk-O2G3Z532.js.map +7 -0
- package/dist/chunk-Y75DCYJC.js +851 -0
- package/dist/chunk-Y75DCYJC.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-56LAVEQL.js.map +0 -7
- package/dist/chunk-GY5JFP6O.js +0 -384
- package/dist/chunk-GY5JFP6O.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-flex
|
|
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), sleep2 = (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), sleep2 = (ms) => new Promise((res
|
|
|
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), sleep2 = (ms) => new Promise((res
|
|
|
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)
|
|
@@ -1131,7 +1168,8 @@ var annotateResponse = (response, extra) => {
|
|
|
1131
1168
|
var responseNotes = (response) => notes.get(response);
|
|
1132
1169
|
|
|
1133
1170
|
// ../core/dist/metrics.js
|
|
1134
|
-
var createMetrics = () => {
|
|
1171
|
+
var createMetrics = (partition = true) => {
|
|
1172
|
+
const namespaces = /* @__PURE__ */ new Map();
|
|
1135
1173
|
let requests = 0;
|
|
1136
1174
|
let faults = 0;
|
|
1137
1175
|
let totalDurationMs = 0;
|
|
@@ -1139,6 +1177,14 @@ var createMetrics = () => {
|
|
|
1139
1177
|
const unmatched = /* @__PURE__ */ new Map();
|
|
1140
1178
|
return {
|
|
1141
1179
|
record(entry) {
|
|
1180
|
+
if (partition) {
|
|
1181
|
+
let scoped = namespaces.get(entry.namespace);
|
|
1182
|
+
if (!scoped) {
|
|
1183
|
+
scoped = createMetrics(false);
|
|
1184
|
+
namespaces.set(entry.namespace, scoped);
|
|
1185
|
+
}
|
|
1186
|
+
scoped.record(entry);
|
|
1187
|
+
}
|
|
1142
1188
|
requests++;
|
|
1143
1189
|
totalDurationMs += entry.durationMs;
|
|
1144
1190
|
if (entry.faultId !== void 0)
|
|
@@ -1150,7 +1196,7 @@ var createMetrics = () => {
|
|
|
1150
1196
|
unmatched.set(route, (unmatched.get(route) ?? 0) + 1);
|
|
1151
1197
|
}
|
|
1152
1198
|
},
|
|
1153
|
-
report: () => ({
|
|
1199
|
+
report: (namespace) => namespace !== void 0 ? (namespaces.get(namespace) ?? createMetrics(false)).report() : {
|
|
1154
1200
|
requests,
|
|
1155
1201
|
byOperation: Object.fromEntries([...byOperation].sort(([a], [b]) => a.localeCompare(b))),
|
|
1156
1202
|
unmatched: [...unmatched].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([route, count]) => {
|
|
@@ -1159,8 +1205,13 @@ var createMetrics = () => {
|
|
|
1159
1205
|
}),
|
|
1160
1206
|
faults,
|
|
1161
1207
|
totalDurationMs
|
|
1162
|
-
}
|
|
1163
|
-
reset() {
|
|
1208
|
+
},
|
|
1209
|
+
reset(namespace) {
|
|
1210
|
+
if (namespace !== void 0) {
|
|
1211
|
+
namespaces.delete(namespace);
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
namespaces.clear();
|
|
1164
1215
|
requests = 0;
|
|
1165
1216
|
faults = 0;
|
|
1166
1217
|
totalDurationMs = 0;
|
|
@@ -4132,7 +4183,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
4132
4183
|
};
|
|
4133
4184
|
|
|
4134
4185
|
// ../core/dist/version.js
|
|
4135
|
-
var PACKAGE_VERSION = true ? "1.
|
|
4186
|
+
var PACKAGE_VERSION = true ? "1.8.0" : UNRELEASED_VERSION;
|
|
4136
4187
|
|
|
4137
4188
|
// ../core/dist/signing.js
|
|
4138
4189
|
var encoder = new TextEncoder();
|
|
@@ -4225,7 +4276,9 @@ var createWebhookHub = (options) => {
|
|
|
4225
4276
|
const faults = /* @__PURE__ */ new Map();
|
|
4226
4277
|
const held = /* @__PURE__ */ new Map();
|
|
4227
4278
|
const inFlight2 = /* @__PURE__ */ new Set();
|
|
4279
|
+
const controllers = /* @__PURE__ */ new Map();
|
|
4228
4280
|
let immediate = Promise.resolve();
|
|
4281
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
4229
4282
|
const track = (work) => {
|
|
4230
4283
|
inFlight2.add(work);
|
|
4231
4284
|
void work.finally(() => inFlight2.delete(work));
|
|
@@ -4246,6 +4299,7 @@ var createWebhookHub = (options) => {
|
|
|
4246
4299
|
responseBody: null
|
|
4247
4300
|
};
|
|
4248
4301
|
const controller = new AbortController();
|
|
4302
|
+
controllers.set(delivery.id, controller);
|
|
4249
4303
|
const timer = scheduleTimer(() => controller.abort(), timeoutMs);
|
|
4250
4304
|
try {
|
|
4251
4305
|
const signed = await options.signer({
|
|
@@ -4275,6 +4329,7 @@ var createWebhookHub = (options) => {
|
|
|
4275
4329
|
} catch (error2) {
|
|
4276
4330
|
record.error = controller.signal.aborted ? `timed out after ${timeoutMs}ms` : error2 instanceof Error ? error2.message : String(error2);
|
|
4277
4331
|
} finally {
|
|
4332
|
+
controllers.delete(delivery.id);
|
|
4278
4333
|
cancel(timer);
|
|
4279
4334
|
record.durationMs = now() - started;
|
|
4280
4335
|
delivery.attempts.push(record);
|
|
@@ -4292,6 +4347,8 @@ var createWebhookHub = (options) => {
|
|
|
4292
4347
|
if (!payloads.has(delivery.id))
|
|
4293
4348
|
return;
|
|
4294
4349
|
await attempt(delivery).then((ok) => {
|
|
4350
|
+
if (!payloads.has(delivery.id))
|
|
4351
|
+
return;
|
|
4295
4352
|
if (ok)
|
|
4296
4353
|
delivery.state = "delivered";
|
|
4297
4354
|
else
|
|
@@ -4353,6 +4410,37 @@ var createWebhookHub = (options) => {
|
|
|
4353
4410
|
fanOut(message);
|
|
4354
4411
|
};
|
|
4355
4412
|
const hub = {
|
|
4413
|
+
pending(namespace) {
|
|
4414
|
+
return inFlight2.size + (held.get(namespace)?.length ?? 0) + [...deliveries.values()].filter((d) => d.namespace === namespace && d.state === "pending").length;
|
|
4415
|
+
},
|
|
4416
|
+
snapshot(namespace) {
|
|
4417
|
+
if (hub.pending(namespace) > 0)
|
|
4418
|
+
throw new Error("webhooks are not quiescent");
|
|
4419
|
+
const handle = {};
|
|
4420
|
+
snapshots.set(handle, structuredClone({
|
|
4421
|
+
namespace,
|
|
4422
|
+
endpoints: own.get(namespace) ?? [],
|
|
4423
|
+
messages: messages.filter((m) => m.namespace === namespace),
|
|
4424
|
+
deliveries: [...deliveries].filter(([, d]) => d.namespace === namespace),
|
|
4425
|
+
payloads: [...payloads].filter(([, p]) => p.message.namespace === namespace),
|
|
4426
|
+
faults: faults.get(namespace) ?? []
|
|
4427
|
+
}));
|
|
4428
|
+
return handle;
|
|
4429
|
+
},
|
|
4430
|
+
restore(namespace, handle) {
|
|
4431
|
+
const point = typeof handle === "object" && handle !== null ? snapshots.get(handle) : void 0;
|
|
4432
|
+
if (!point || point.namespace !== namespace || hub.pending(namespace) > 0)
|
|
4433
|
+
throw new Error("invalid webhook restore");
|
|
4434
|
+
hub.clear(namespace);
|
|
4435
|
+
const copied = structuredClone(point);
|
|
4436
|
+
own.set(namespace, copied.endpoints);
|
|
4437
|
+
messages.push(...copied.messages);
|
|
4438
|
+
for (const [id2, delivery] of copied.deliveries)
|
|
4439
|
+
deliveries.set(id2, delivery);
|
|
4440
|
+
for (const [id2, payload] of copied.payloads)
|
|
4441
|
+
payloads.set(id2, payload);
|
|
4442
|
+
faults.set(namespace, copied.faults);
|
|
4443
|
+
},
|
|
4356
4444
|
publish(input) {
|
|
4357
4445
|
const contentType = input.contentType ?? (input.form ? "application/x-www-form-urlencoded" : "application/json");
|
|
4358
4446
|
const body = typeof input.body === "string" ? input.body : input.form ? new URLSearchParams(input.form).toString() : JSON.stringify(input.body);
|
|
@@ -4443,6 +4531,7 @@ var createWebhookHub = (options) => {
|
|
|
4443
4531
|
for (const [id2, delivery] of deliveries) {
|
|
4444
4532
|
if (namespace !== void 0 && delivery.namespace !== namespace)
|
|
4445
4533
|
continue;
|
|
4534
|
+
controllers.get(id2)?.abort();
|
|
4446
4535
|
const timer = pending.get(id2);
|
|
4447
4536
|
if (timer !== void 0)
|
|
4448
4537
|
cancel(timer);
|
|
@@ -4630,6 +4719,20 @@ var createRuntime = (options) => {
|
|
|
4630
4719
|
const instances = /* @__PURE__ */ new Map();
|
|
4631
4720
|
const publicNamespaces = /* @__PURE__ */ new Set();
|
|
4632
4721
|
const branchRngs = /* @__PURE__ */ new Map();
|
|
4722
|
+
const namespaceClocks = /* @__PURE__ */ new Map();
|
|
4723
|
+
const namespaceForStorage = /* @__PURE__ */ new Map();
|
|
4724
|
+
let isolatedNamespaces = false;
|
|
4725
|
+
const namespaceClock = (name = DEFAULT_NAMESPACE) => {
|
|
4726
|
+
if (!isolatedNamespaces || name === DEFAULT_NAMESPACE)
|
|
4727
|
+
return clock;
|
|
4728
|
+
let found = namespaceClocks.get(name);
|
|
4729
|
+
if (!found) {
|
|
4730
|
+
found = createClock();
|
|
4731
|
+
namespaceClocks.set(name, found);
|
|
4732
|
+
}
|
|
4733
|
+
return found;
|
|
4734
|
+
};
|
|
4735
|
+
const fleetPoints = /* @__PURE__ */ new WeakMap();
|
|
4633
4736
|
const timelines = /* @__PURE__ */ new Map();
|
|
4634
4737
|
const branchStorage = /* @__PURE__ */ new Map();
|
|
4635
4738
|
const captured = /* @__PURE__ */ new Map();
|
|
@@ -4643,17 +4746,21 @@ var createRuntime = (options) => {
|
|
|
4643
4746
|
if (!NAMESPACE_PATTERN.test(key) || !NAMESPACE_PATTERN.test(publicNamespace)) {
|
|
4644
4747
|
throw new RangeError(`namespace must match ${NAMESPACE_PATTERN}: ${JSON.stringify(publicNamespace)}`);
|
|
4645
4748
|
}
|
|
4749
|
+
const createdContextRng = isolatedRng ?? (isolatedNamespaces && key !== DEFAULT_NAMESPACE ? createRng(options.seed ?? 0) : rng);
|
|
4646
4750
|
const created = options.create({
|
|
4647
4751
|
namespace: storageNamespace(key),
|
|
4648
4752
|
publicNamespace,
|
|
4649
4753
|
sqlite,
|
|
4650
|
-
clock,
|
|
4651
|
-
rng:
|
|
4754
|
+
clock: namespaceClock(publicNamespace),
|
|
4755
|
+
rng: createdContextRng
|
|
4652
4756
|
});
|
|
4653
4757
|
instances.set(key, created);
|
|
4758
|
+
namespaceForStorage.set(key, publicNamespace);
|
|
4654
4759
|
publicNamespaces.add(publicNamespace);
|
|
4655
4760
|
if (isolatedRng)
|
|
4656
4761
|
branchRngs.set(key, isolatedRng);
|
|
4762
|
+
else if (isolatedNamespaces && key !== DEFAULT_NAMESPACE)
|
|
4763
|
+
branchRngs.set(key, createdContextRng);
|
|
4657
4764
|
return created;
|
|
4658
4765
|
};
|
|
4659
4766
|
const instance = (name = DEFAULT_NAMESPACE) => instanceFor(name);
|
|
@@ -4671,7 +4778,7 @@ var createRuntime = (options) => {
|
|
|
4671
4778
|
captured.set(storage, snapshot2);
|
|
4672
4779
|
return Object.freeze({
|
|
4673
4780
|
snapshot: snapshot2,
|
|
4674
|
-
clock: Object.freeze(
|
|
4781
|
+
clock: Object.freeze(namespaceClock(namespaceForStorage.get(storage) ?? storage).state()),
|
|
4675
4782
|
rngState: (branchRngs.get(storage) ?? rng).state()
|
|
4676
4783
|
});
|
|
4677
4784
|
};
|
|
@@ -4681,7 +4788,7 @@ var createRuntime = (options) => {
|
|
|
4681
4788
|
return found;
|
|
4682
4789
|
instance(name);
|
|
4683
4790
|
found = new Timeline({
|
|
4684
|
-
now:
|
|
4791
|
+
now: namespaceClock(name).now,
|
|
4685
4792
|
...options.maxCheckpoints !== void 0 ? { maxCheckpoints: options.maxCheckpoints } : {}
|
|
4686
4793
|
});
|
|
4687
4794
|
found.commit(capture(name));
|
|
@@ -4708,12 +4815,13 @@ var createRuntime = (options) => {
|
|
|
4708
4815
|
const point = history2.checkout("main", at);
|
|
4709
4816
|
restoreNamespace(sqlite, storageNamespace(namespace), point.value.snapshot);
|
|
4710
4817
|
captured.set(namespace, point.value.snapshot);
|
|
4711
|
-
rng.setState(point.value.rngState);
|
|
4712
|
-
|
|
4818
|
+
(branchRngs.get(namespace) ?? rng).setState(point.value.rngState);
|
|
4819
|
+
const selectedClock = namespaceClock(namespace);
|
|
4820
|
+
selectedClock.set(point.value.clock.now);
|
|
4713
4821
|
if (point.value.clock.frozen)
|
|
4714
|
-
|
|
4822
|
+
selectedClock.freeze();
|
|
4715
4823
|
else
|
|
4716
|
-
|
|
4824
|
+
selectedClock.unfreeze();
|
|
4717
4825
|
}
|
|
4718
4826
|
return namespace;
|
|
4719
4827
|
}
|
|
@@ -4771,11 +4879,12 @@ var createRuntime = (options) => {
|
|
|
4771
4879
|
const storage = ensureBranch(namespace, branchName);
|
|
4772
4880
|
restoreNamespace(sqlite, storageNamespace(storage), point.value.snapshot);
|
|
4773
4881
|
captured.set(storage, point.value.snapshot);
|
|
4774
|
-
|
|
4882
|
+
const selectedClock = namespaceClock(namespace);
|
|
4883
|
+
selectedClock.set(point.value.clock.now);
|
|
4775
4884
|
if (point.value.clock.frozen)
|
|
4776
|
-
|
|
4885
|
+
selectedClock.freeze();
|
|
4777
4886
|
else
|
|
4778
|
-
|
|
4887
|
+
selectedClock.unfreeze();
|
|
4779
4888
|
(branchRngs.get(storage) ?? rng).setState(point.value.rngState);
|
|
4780
4889
|
};
|
|
4781
4890
|
const reset = async (name = DEFAULT_NAMESPACE) => {
|
|
@@ -4783,10 +4892,21 @@ var createRuntime = (options) => {
|
|
|
4783
4892
|
options.webhooks?.clear();
|
|
4784
4893
|
for (const each of instances.values())
|
|
4785
4894
|
await each.reset();
|
|
4895
|
+
for (const each of branchRngs.values())
|
|
4896
|
+
each.reset();
|
|
4786
4897
|
timelines.clear();
|
|
4898
|
+
for (const storage of branchStorage.values()) {
|
|
4899
|
+
instances.delete(storage);
|
|
4900
|
+
branchRngs.delete(storage);
|
|
4901
|
+
namespaceForStorage.delete(storage);
|
|
4902
|
+
}
|
|
4787
4903
|
branchStorage.clear();
|
|
4788
|
-
branchRngs.clear();
|
|
4789
4904
|
captured.clear();
|
|
4905
|
+
faults.clear();
|
|
4906
|
+
clock.reset();
|
|
4907
|
+
rng.reset();
|
|
4908
|
+
for (const each of namespaceClocks.values())
|
|
4909
|
+
each.reset();
|
|
4790
4910
|
return;
|
|
4791
4911
|
}
|
|
4792
4912
|
options.webhooks?.clear(name);
|
|
@@ -4804,11 +4924,18 @@ var createRuntime = (options) => {
|
|
|
4804
4924
|
else
|
|
4805
4925
|
clearNamespace(sqlite, storageNamespace(storage));
|
|
4806
4926
|
branchStorage.delete(mapping);
|
|
4927
|
+
instances.delete(storage);
|
|
4928
|
+
namespaceForStorage.delete(storage);
|
|
4807
4929
|
branchRngs.delete(storage);
|
|
4808
4930
|
captured.delete(storage);
|
|
4809
4931
|
}
|
|
4810
4932
|
timelines.delete(name);
|
|
4811
4933
|
captured.delete(name);
|
|
4934
|
+
faults.restore(name, { rules: [], rngState: createRng(options.seed ?? 0).state() });
|
|
4935
|
+
namespaceClock(name).reset();
|
|
4936
|
+
(branchRngs.get(name) ?? rng).reset();
|
|
4937
|
+
journal.clear(name);
|
|
4938
|
+
metrics.reset(name);
|
|
4812
4939
|
};
|
|
4813
4940
|
const snapshot = (name = DEFAULT_NAMESPACE) => {
|
|
4814
4941
|
return checkpoint(name, "main").value.snapshot;
|
|
@@ -4846,6 +4973,53 @@ var createRuntime = (options) => {
|
|
|
4846
4973
|
rng,
|
|
4847
4974
|
credentials,
|
|
4848
4975
|
webhooks: options.webhooks,
|
|
4976
|
+
isolateNamespaces() {
|
|
4977
|
+
if (publicNamespaces.size > 1)
|
|
4978
|
+
throw new Error("enable namespace isolation before creating named namespaces");
|
|
4979
|
+
isolatedNamespaces = true;
|
|
4980
|
+
faults.isolateNamespaces();
|
|
4981
|
+
},
|
|
4982
|
+
namespaceClock,
|
|
4983
|
+
namespaceOf(request) {
|
|
4984
|
+
const url = new URL(request.url);
|
|
4985
|
+
const prefixed = PATH_PREFIX.exec(url.pathname);
|
|
4986
|
+
const selected = request.headers.get(NAMESPACE_HEADER) ?? (prefixed ? decodeURIComponent(prefixed[1]) : void 0);
|
|
4987
|
+
const path = prefixed ? prefixed[2] ?? "/" : url.pathname;
|
|
4988
|
+
if (path === "/__admin" || path.startsWith("/__admin/"))
|
|
4989
|
+
return url.searchParams.get("namespace") ?? selected ?? DEFAULT_NAMESPACE;
|
|
4990
|
+
if (selected !== void 0)
|
|
4991
|
+
return selected;
|
|
4992
|
+
const credential = options.credential?.(request);
|
|
4993
|
+
return (credential !== void 0 ? credentials.get(credential) : void 0) ?? DEFAULT_NAMESPACE;
|
|
4994
|
+
},
|
|
4995
|
+
fleetSnapshot(namespace) {
|
|
4996
|
+
instance(namespace);
|
|
4997
|
+
const handle = {};
|
|
4998
|
+
fleetPoints.set(handle, {
|
|
4999
|
+
namespace,
|
|
5000
|
+
state: capture(namespace),
|
|
5001
|
+
faults: faults.snapshot(namespace),
|
|
5002
|
+
webhooks: options.webhooks?.snapshot(namespace)
|
|
5003
|
+
});
|
|
5004
|
+
return handle;
|
|
5005
|
+
},
|
|
5006
|
+
fleetRestore(handle, namespace) {
|
|
5007
|
+
const point = typeof handle === "object" && handle !== null ? fleetPoints.get(handle) : void 0;
|
|
5008
|
+
if (!point || point.namespace !== namespace)
|
|
5009
|
+
throw new Error("invalid fleet checkpoint");
|
|
5010
|
+
restoreNamespace(sqlite, storageNamespace(namespace), point.state.snapshot);
|
|
5011
|
+
captured.set(namespace, point.state.snapshot);
|
|
5012
|
+
const selectedClock = namespaceClock(namespace);
|
|
5013
|
+
selectedClock.freeze();
|
|
5014
|
+
selectedClock.set(point.state.clock.now);
|
|
5015
|
+
if (!point.state.clock.frozen)
|
|
5016
|
+
selectedClock.unfreeze();
|
|
5017
|
+
(branchRngs.get(namespace) ?? rng).setState(point.state.rngState);
|
|
5018
|
+
faults.restore(namespace, point.faults);
|
|
5019
|
+
if (point.webhooks !== void 0)
|
|
5020
|
+
options.webhooks?.restore(namespace, point.webhooks);
|
|
5021
|
+
timelines.delete(namespace);
|
|
5022
|
+
},
|
|
4849
5023
|
applyPreset: (name, namespace = DEFAULT_NAMESPACE, overrides = {}) => {
|
|
4850
5024
|
const preset = options.presets?.[name];
|
|
4851
5025
|
if (!preset)
|
|
@@ -5021,6 +5195,7 @@ var createRuntime = (options) => {
|
|
|
5021
5195
|
startedAt: wallNow(),
|
|
5022
5196
|
wallNow,
|
|
5023
5197
|
clock,
|
|
5198
|
+
namespaceClock,
|
|
5024
5199
|
faults,
|
|
5025
5200
|
metrics,
|
|
5026
5201
|
journal,
|
|
@@ -7242,6 +7417,8 @@ var FlexAPI = class {
|
|
|
7242
7417
|
var isNextActionType = (value) => typeof value === "string" && NEXT_ACTION_TYPES.includes(value);
|
|
7243
7418
|
|
|
7244
7419
|
export {
|
|
7420
|
+
createClock,
|
|
7421
|
+
parseDuration,
|
|
7245
7422
|
document2 as document,
|
|
7246
7423
|
operationIds,
|
|
7247
7424
|
supportedOperationIds,
|
|
@@ -7264,4 +7441,4 @@ export {
|
|
|
7264
7441
|
FlexAPI,
|
|
7265
7442
|
isNextActionType
|
|
7266
7443
|
};
|
|
7267
|
-
//# sourceMappingURL=chunk-
|
|
7444
|
+
//# sourceMappingURL=chunk-O2G3Z532.js.map
|