@crvouga/mockingbird-service-mailosaur 3.6.0 → 3.7.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 +7 -1
- package/dist/{chunk-4B6IN77Y.js → chunk-GRXH63CD.js} +103 -12
- package/dist/chunk-GRXH63CD.js.map +7 -0
- package/dist/{chunk-U3FYDM4L.js → chunk-PROCZMVA.js} +114 -30
- package/dist/chunk-PROCZMVA.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +28 -0
- package/dist/index.js +1 -1
- package/dist/server.d.ts +69 -0
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-4B6IN77Y.js.map +0 -7
- package/dist/chunk-U3FYDM4L.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-mailosaur
|
|
2
2
|
|
|
3
|
-
## 3.
|
|
3
|
+
## 3.7.0 (2026-10-19)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- resolve the agent-reported issue queue in one batch ([25c52b6](https://github.com/crvouga/mockingbird/commit/25c52b668a53ddb80b968419601a20abf33f956b))
|
|
8
|
+
|
|
9
|
+
## 3.6.0 (2026-10-16)
|
|
4
10
|
|
|
5
11
|
### Features
|
|
6
12
|
|
|
@@ -3,12 +3,13 @@ import {
|
|
|
3
3
|
createRuntime,
|
|
4
4
|
normalizeBootControls,
|
|
5
5
|
normalizeControls,
|
|
6
|
+
normalizeIdBase,
|
|
6
7
|
ownedTransport,
|
|
7
8
|
parseDuration,
|
|
8
9
|
parseFaultHeader,
|
|
9
10
|
resolveAdminPrefix,
|
|
10
11
|
restoreClock
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PROCZMVA.js";
|
|
12
13
|
|
|
13
14
|
// src/server.ts
|
|
14
15
|
import { writeFileSync } from "node:fs";
|
|
@@ -23,6 +24,19 @@ import { createServer as createTlsServer } from "node:tls";
|
|
|
23
24
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
24
25
|
import { parseArgs } from "node:util";
|
|
25
26
|
|
|
27
|
+
// ../../adapters/node/dist/boot-settings.js
|
|
28
|
+
var checkSettings = (target, settings, label) => {
|
|
29
|
+
if (!target.parseSettings)
|
|
30
|
+
throw new Error(`${label}: ${target.name} takes no boot settings`);
|
|
31
|
+
try {
|
|
32
|
+
return target.parseSettings(settings);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`${label}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
35
|
+
cause: error
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
26
40
|
// ../../adapters/node/dist/fleet.js
|
|
27
41
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
28
42
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -2672,6 +2686,9 @@ var fleet_config_schema_default = {
|
|
|
2672
2686
|
adminControls: {
|
|
2673
2687
|
$ref: "#/$defs/controls"
|
|
2674
2688
|
},
|
|
2689
|
+
idBase: {
|
|
2690
|
+
$ref: "#/$defs/idBase"
|
|
2691
|
+
},
|
|
2675
2692
|
namespace: {
|
|
2676
2693
|
type: "string",
|
|
2677
2694
|
pattern: "^[A-Za-z0-9_.-]{1,64}$"
|
|
@@ -2761,6 +2778,12 @@ var fleet_config_schema_default = {
|
|
|
2761
2778
|
adminControls: {
|
|
2762
2779
|
$ref: "#/$defs/controls"
|
|
2763
2780
|
},
|
|
2781
|
+
idBase: {
|
|
2782
|
+
$ref: "#/$defs/idBase"
|
|
2783
|
+
},
|
|
2784
|
+
settings: {
|
|
2785
|
+
type: "object"
|
|
2786
|
+
},
|
|
2764
2787
|
fixtures: {
|
|
2765
2788
|
type: "object"
|
|
2766
2789
|
},
|
|
@@ -2807,6 +2830,18 @@ var fleet_config_schema_default = {
|
|
|
2807
2830
|
}
|
|
2808
2831
|
}
|
|
2809
2832
|
},
|
|
2833
|
+
idBase: {
|
|
2834
|
+
anyOf: [
|
|
2835
|
+
{
|
|
2836
|
+
type: "integer",
|
|
2837
|
+
minimum: 0
|
|
2838
|
+
},
|
|
2839
|
+
{
|
|
2840
|
+
type: "string",
|
|
2841
|
+
pattern: "^(boot|[0-9]+)$"
|
|
2842
|
+
}
|
|
2843
|
+
]
|
|
2844
|
+
},
|
|
2810
2845
|
controls: {
|
|
2811
2846
|
type: "object",
|
|
2812
2847
|
additionalProperties: false,
|
|
@@ -2956,6 +2991,8 @@ async function preflightFleet(config, options) {
|
|
|
2956
2991
|
throw new Error("protected archive policy requires a protected repository; configure its protector before startup");
|
|
2957
2992
|
resolveAdminPrefix(config.adminPrefix);
|
|
2958
2993
|
normalizeBootControls(config.adminControls);
|
|
2994
|
+
if (config.idBase !== void 0)
|
|
2995
|
+
normalizeIdBase(config.idBase, "idBase");
|
|
2959
2996
|
const targets = /* @__PURE__ */ new Map();
|
|
2960
2997
|
const ports = /* @__PURE__ */ new Set();
|
|
2961
2998
|
for (const [name2, entry] of Object.entries(config.services)) {
|
|
@@ -2987,6 +3024,13 @@ async function preflightFleet(config, options) {
|
|
|
2987
3024
|
throw new Error("invalid protocol namespace selector");
|
|
2988
3025
|
}
|
|
2989
3026
|
}
|
|
3027
|
+
if (entry.idBase !== void 0)
|
|
3028
|
+
normalizeIdBase(entry.idBase, "idBase");
|
|
3029
|
+
if (entry.settings !== void 0) {
|
|
3030
|
+
if (protocol !== "http" || !("create" in target))
|
|
3031
|
+
throw new Error("settings: only HTTP services take boot settings");
|
|
3032
|
+
checkSettings(target, entry.settings, "settings");
|
|
3033
|
+
}
|
|
2990
3034
|
const port = entry.port ?? target.defaultPort;
|
|
2991
3035
|
if (port !== 0) {
|
|
2992
3036
|
const key = `${entry.host ?? "127.0.0.1"}:${port}`;
|
|
@@ -3022,7 +3066,7 @@ async function preflightFleet(config, options) {
|
|
|
3022
3066
|
break;
|
|
3023
3067
|
}
|
|
3024
3068
|
}
|
|
3025
|
-
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.
|
|
3069
|
+
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.7.0" });
|
|
3026
3070
|
} catch (error) {
|
|
3027
3071
|
throw new Error(`service ${name2}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3028
3072
|
}
|
|
@@ -3342,6 +3386,7 @@ var httpChild = async (target, entry, options, admission, generation, privateAcc
|
|
|
3342
3386
|
options.onLog?.(entry2);
|
|
3343
3387
|
},
|
|
3344
3388
|
...entry.adminControls !== void 0 ? { adminControls: entry.adminControls } : {},
|
|
3389
|
+
...entry.settings !== void 0 ? { settings: checkSettings(target, entry.settings, "settings") } : {},
|
|
3345
3390
|
...entry.fixtures !== void 0 ? { fixtures: entry.fixtures } : {},
|
|
3346
3391
|
...(advertisedHttpBase(entry) ?? entry.baseUrl) !== void 0 ? { baseUrl: advertisedHttpBase(entry) ?? entry.baseUrl } : {}
|
|
3347
3392
|
});
|
|
@@ -3360,6 +3405,8 @@ var httpChild = async (target, entry, options, admission, generation, privateAcc
|
|
|
3360
3405
|
].some((method) => typeof created[method] !== "function"))
|
|
3361
3406
|
throw new Error("HTTP target does not implement the fleet runtime protocol; build/install matching supported service versions");
|
|
3362
3407
|
const runtime = created;
|
|
3408
|
+
if (entry.idBase !== void 0)
|
|
3409
|
+
runtime.setIdBase?.(entry.idBase);
|
|
3363
3410
|
const unobserve = runtime.webhooks?.observeDeliveries(observer.delivery);
|
|
3364
3411
|
if (options.outbound && runtime.webhooks)
|
|
3365
3412
|
runtime.webhooks.setTransportPolicy(ownedTransport(options.outbound));
|
|
@@ -3958,6 +4005,7 @@ async function startFleet(config, options) {
|
|
|
3958
4005
|
...entry,
|
|
3959
4006
|
adminPrefix: resolveAdminPrefix(entry.adminPrefix ?? adminPrefix),
|
|
3960
4007
|
...adminKey !== void 0 ? { adminKey } : {},
|
|
4008
|
+
...(entry.idBase ?? config.idBase) !== void 0 ? { idBase: entry.idBase ?? config.idBase } : {},
|
|
3961
4009
|
// Fleet-wide controls, with the service's own keys replacing them.
|
|
3962
4010
|
...config.adminControls !== void 0 || entry.adminControls !== void 0 ? { adminControls: { ...config.adminControls, ...entry.adminControls } } : {}
|
|
3963
4011
|
}, options, (namespace, request) => management?.admit(namespace, request), (namespace) => management?.generation(namespace), (namespace, request) => management?.privateRequest(namespace, request) ?? false, {
|
|
@@ -4642,6 +4690,16 @@ var COMMON_SERVE_OPTIONS = {
|
|
|
4642
4690
|
value: "<seed>",
|
|
4643
4691
|
description: "Seed for every random choice (env MOCKINGBIRD_SEED)"
|
|
4644
4692
|
},
|
|
4693
|
+
"id-base": {
|
|
4694
|
+
type: "string",
|
|
4695
|
+
value: "<n|boot>",
|
|
4696
|
+
description: "Start generated ids at this base so a restart does not reissue the last boot's ids; boot derives one from the clock (env MOCKINGBIRD_ID_BASE; default 0, the same ids every boot)"
|
|
4697
|
+
},
|
|
4698
|
+
settings: {
|
|
4699
|
+
type: "string",
|
|
4700
|
+
value: "<json|file>",
|
|
4701
|
+
description: "Service settings to boot with, as JSON or a JSON file; every namespace starts from them (env MOCKINGBIRD_SETTINGS; only for services that declare settings)"
|
|
4702
|
+
},
|
|
4645
4703
|
"admin-controls": {
|
|
4646
4704
|
type: "string",
|
|
4647
4705
|
value: "<json|file>",
|
|
@@ -4736,19 +4794,40 @@ var readJsonFile = async (path, label) => {
|
|
|
4736
4794
|
}
|
|
4737
4795
|
};
|
|
4738
4796
|
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4797
|
+
var readJsonOption = async (source, label) => {
|
|
4798
|
+
const trimmed = source.trim();
|
|
4799
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
4800
|
+
try {
|
|
4801
|
+
return JSON.parse(trimmed);
|
|
4802
|
+
} catch {
|
|
4803
|
+
throw new Error(`${label}: not valid JSON`);
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4806
|
+
return readJsonFile(source, label);
|
|
4807
|
+
};
|
|
4808
|
+
var resolveServeIdBase = (values, env = process.env) => {
|
|
4809
|
+
const source = asString(values["id-base"]) ?? env.MOCKINGBIRD_ID_BASE;
|
|
4810
|
+
if (source === void 0 || source.trim() === "")
|
|
4811
|
+
return void 0;
|
|
4812
|
+
normalizeIdBase(source.trim(), "--id-base");
|
|
4813
|
+
return source.trim();
|
|
4814
|
+
};
|
|
4815
|
+
var resolveServeSettings = async (target, values, env = process.env) => {
|
|
4816
|
+
const flag = asString(values.settings);
|
|
4817
|
+
const source = flag ?? env.MOCKINGBIRD_SETTINGS;
|
|
4818
|
+
if (source === void 0 || source.trim() === "")
|
|
4819
|
+
return void 0;
|
|
4820
|
+
const label = flag !== void 0 ? "--settings" : "MOCKINGBIRD_SETTINGS";
|
|
4821
|
+
const parsed = await readJsonOption(source, label);
|
|
4822
|
+
if (!isObject2(parsed))
|
|
4823
|
+
throw new Error(`${label}: expected a JSON object`);
|
|
4824
|
+
return checkSettings(target, parsed, label);
|
|
4825
|
+
};
|
|
4739
4826
|
var resolveServeControls = async (values, env = process.env, base) => {
|
|
4740
4827
|
const source = asString(values["admin-controls"]) ?? env.MOCKINGBIRD_ADMIN_CONTROLS;
|
|
4741
4828
|
let document = isObject2(base) ? { ...base } : {};
|
|
4742
4829
|
if (source !== void 0 && source.trim() !== "") {
|
|
4743
|
-
|
|
4744
|
-
if (source.trim().startsWith("{")) {
|
|
4745
|
-
try {
|
|
4746
|
-
parsed = JSON.parse(source);
|
|
4747
|
-
} catch {
|
|
4748
|
-
throw new Error("--admin-controls: not valid JSON");
|
|
4749
|
-
}
|
|
4750
|
-
} else
|
|
4751
|
-
parsed = await readJsonFile(source, "--admin-controls");
|
|
4830
|
+
const parsed = source.trim().startsWith("{") ? await readJsonOption(source, "--admin-controls") : await readJsonFile(source, "--admin-controls");
|
|
4752
4831
|
if (!isObject2(parsed))
|
|
4753
4832
|
throw new Error("--admin-controls: expected a JSON object");
|
|
4754
4833
|
document = { ...document, ...parsed };
|
|
@@ -4798,8 +4877,11 @@ var start = async (target, values, config) => {
|
|
|
4798
4877
|
adminKey: config.adminKey,
|
|
4799
4878
|
seed: config.seed,
|
|
4800
4879
|
onLog: formatLog(config.log),
|
|
4880
|
+
...config.settings !== void 0 ? { settings: config.settings } : {},
|
|
4801
4881
|
...config.adminControls !== void 0 ? { adminControls: config.adminControls } : {}
|
|
4802
4882
|
});
|
|
4883
|
+
if (config.idBase !== void 0)
|
|
4884
|
+
runtime.setIdBase?.(config.idBase);
|
|
4803
4885
|
const listening = await listen(runtime, { port: config.port, host: config.host });
|
|
4804
4886
|
target.listening?.(listening);
|
|
4805
4887
|
console.log(`${target.name} emulator listening on ${listening.url}`);
|
|
@@ -4845,6 +4927,11 @@ var serveCommand = (target) => ({
|
|
|
4845
4927
|
const adminControls = await resolveServeControls(values, process.env, config.adminControls);
|
|
4846
4928
|
if (adminControls !== void 0)
|
|
4847
4929
|
config.adminControls = adminControls;
|
|
4930
|
+
if (values.settings !== void 0)
|
|
4931
|
+
throw new Error("--settings serves a single service; give each service its own `settings` in the config");
|
|
4932
|
+
const idBase = config.idBase ?? resolveServeIdBase(values);
|
|
4933
|
+
if (idBase !== void 0)
|
|
4934
|
+
config.idBase = idBase;
|
|
4848
4935
|
const fleet = await startFleet(config, {
|
|
4849
4936
|
load: (name2) => loadTarget(name2, target),
|
|
4850
4937
|
onLog: formatLog(config.log ?? log),
|
|
@@ -4874,8 +4961,12 @@ var serveCommand = (target) => ({
|
|
|
4874
4961
|
let listening;
|
|
4875
4962
|
try {
|
|
4876
4963
|
const adminControls = await resolveServeControls(values);
|
|
4964
|
+
const idBase = resolveServeIdBase(values);
|
|
4965
|
+
const settings = await resolveServeSettings(target, values);
|
|
4877
4966
|
listening = await start(target, values, {
|
|
4878
4967
|
...adminControls !== void 0 ? { adminControls } : {},
|
|
4968
|
+
...idBase !== void 0 ? { idBase } : {},
|
|
4969
|
+
...settings !== void 0 ? { settings } : {},
|
|
4879
4970
|
adminPrefix: resolveAdminPrefix(asString(values["admin-prefix"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX),
|
|
4880
4971
|
port: port === void 0 ? target.defaultPort : Number.parseInt(port, 10),
|
|
4881
4972
|
host: asString(values.host) ?? "127.0.0.1",
|
|
@@ -5149,4 +5240,4 @@ export {
|
|
|
5149
5240
|
createServer2 as createServer,
|
|
5150
5241
|
serveTarget
|
|
5151
5242
|
};
|
|
5152
|
-
//# sourceMappingURL=chunk-
|
|
5243
|
+
//# sourceMappingURL=chunk-GRXH63CD.js.map
|