@crvouga/mockingbird-service-junction 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 +17 -1
- package/README.md +214 -7
- package/SUPPORT.md +4 -2
- package/dist/{chunk-ZRF3DDJ4.js → chunk-27N4VA23.js} +1042 -275
- package/dist/chunk-27N4VA23.js.map +7 -0
- package/dist/{chunk-WMJJYHRV.js → chunk-NTGGNJKR.js} +137 -17
- package/dist/chunk-NTGGNJKR.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +317 -107
- package/dist/index.js +1 -1
- package/dist/server.d.ts +347 -96
- package/dist/server.js +2 -2
- package/openapi.yaml +207 -0
- package/package.json +1 -1
- package/dist/chunk-WMJJYHRV.js.map +0 -7
- package/dist/chunk-ZRF3DDJ4.js.map +0 -7
|
@@ -6,13 +6,14 @@ import {
|
|
|
6
6
|
labAccountBehaviorFrom,
|
|
7
7
|
normalizeBootControls,
|
|
8
8
|
normalizeControls,
|
|
9
|
+
normalizeIdBase,
|
|
9
10
|
ownedTransport,
|
|
10
11
|
parseDuration,
|
|
11
12
|
parseFaultHeader,
|
|
12
13
|
pullCorpus,
|
|
13
14
|
resolveAdminPrefix,
|
|
14
15
|
restoreClock
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-27N4VA23.js";
|
|
16
17
|
import {
|
|
17
18
|
defaultCorpus
|
|
18
19
|
} from "./chunk-2FZJPMTR.js";
|
|
@@ -27,6 +28,19 @@ import { readFile as readFile6 } from "node:fs/promises";
|
|
|
27
28
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
28
29
|
import { parseArgs } from "node:util";
|
|
29
30
|
|
|
31
|
+
// ../../adapters/node/dist/boot-settings.js
|
|
32
|
+
var checkSettings = (target, settings, label) => {
|
|
33
|
+
if (!target.parseSettings)
|
|
34
|
+
throw new Error(`${label}: ${target.name} takes no boot settings`);
|
|
35
|
+
try {
|
|
36
|
+
return target.parseSettings(settings);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw new Error(`${label}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
39
|
+
cause: error
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
30
44
|
// ../../adapters/node/dist/fleet.js
|
|
31
45
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
32
46
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -2676,6 +2690,9 @@ var fleet_config_schema_default = {
|
|
|
2676
2690
|
adminControls: {
|
|
2677
2691
|
$ref: "#/$defs/controls"
|
|
2678
2692
|
},
|
|
2693
|
+
idBase: {
|
|
2694
|
+
$ref: "#/$defs/idBase"
|
|
2695
|
+
},
|
|
2679
2696
|
namespace: {
|
|
2680
2697
|
type: "string",
|
|
2681
2698
|
pattern: "^[A-Za-z0-9_.-]{1,64}$"
|
|
@@ -2765,6 +2782,12 @@ var fleet_config_schema_default = {
|
|
|
2765
2782
|
adminControls: {
|
|
2766
2783
|
$ref: "#/$defs/controls"
|
|
2767
2784
|
},
|
|
2785
|
+
idBase: {
|
|
2786
|
+
$ref: "#/$defs/idBase"
|
|
2787
|
+
},
|
|
2788
|
+
settings: {
|
|
2789
|
+
type: "object"
|
|
2790
|
+
},
|
|
2768
2791
|
fixtures: {
|
|
2769
2792
|
type: "object"
|
|
2770
2793
|
},
|
|
@@ -2811,6 +2834,18 @@ var fleet_config_schema_default = {
|
|
|
2811
2834
|
}
|
|
2812
2835
|
}
|
|
2813
2836
|
},
|
|
2837
|
+
idBase: {
|
|
2838
|
+
anyOf: [
|
|
2839
|
+
{
|
|
2840
|
+
type: "integer",
|
|
2841
|
+
minimum: 0
|
|
2842
|
+
},
|
|
2843
|
+
{
|
|
2844
|
+
type: "string",
|
|
2845
|
+
pattern: "^(boot|[0-9]+)$"
|
|
2846
|
+
}
|
|
2847
|
+
]
|
|
2848
|
+
},
|
|
2814
2849
|
controls: {
|
|
2815
2850
|
type: "object",
|
|
2816
2851
|
additionalProperties: false,
|
|
@@ -2960,6 +2995,8 @@ async function preflightFleet(config, options) {
|
|
|
2960
2995
|
throw new Error("protected archive policy requires a protected repository; configure its protector before startup");
|
|
2961
2996
|
resolveAdminPrefix(config.adminPrefix);
|
|
2962
2997
|
normalizeBootControls(config.adminControls);
|
|
2998
|
+
if (config.idBase !== void 0)
|
|
2999
|
+
normalizeIdBase(config.idBase, "idBase");
|
|
2963
3000
|
const targets = /* @__PURE__ */ new Map();
|
|
2964
3001
|
const ports = /* @__PURE__ */ new Set();
|
|
2965
3002
|
for (const [name, entry] of Object.entries(config.services)) {
|
|
@@ -2991,6 +3028,13 @@ async function preflightFleet(config, options) {
|
|
|
2991
3028
|
throw new Error("invalid protocol namespace selector");
|
|
2992
3029
|
}
|
|
2993
3030
|
}
|
|
3031
|
+
if (entry.idBase !== void 0)
|
|
3032
|
+
normalizeIdBase(entry.idBase, "idBase");
|
|
3033
|
+
if (entry.settings !== void 0) {
|
|
3034
|
+
if (protocol !== "http" || !("create" in target))
|
|
3035
|
+
throw new Error("settings: only HTTP services take boot settings");
|
|
3036
|
+
checkSettings(target, entry.settings, "settings");
|
|
3037
|
+
}
|
|
2994
3038
|
const port = entry.port ?? target.defaultPort;
|
|
2995
3039
|
if (port !== 0) {
|
|
2996
3040
|
const key = `${entry.host ?? "127.0.0.1"}:${port}`;
|
|
@@ -3026,7 +3070,7 @@ async function preflightFleet(config, options) {
|
|
|
3026
3070
|
break;
|
|
3027
3071
|
}
|
|
3028
3072
|
}
|
|
3029
|
-
targets.set(name, { ...target, packageVersion: packageVersion ?? "3.
|
|
3073
|
+
targets.set(name, { ...target, packageVersion: packageVersion ?? "3.7.0" });
|
|
3030
3074
|
} catch (error) {
|
|
3031
3075
|
throw new Error(`service ${name}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3032
3076
|
}
|
|
@@ -3346,6 +3390,7 @@ var httpChild = async (target, entry, options, admission, generation, privateAcc
|
|
|
3346
3390
|
options.onLog?.(entry2);
|
|
3347
3391
|
},
|
|
3348
3392
|
...entry.adminControls !== void 0 ? { adminControls: entry.adminControls } : {},
|
|
3393
|
+
...entry.settings !== void 0 ? { settings: checkSettings(target, entry.settings, "settings") } : {},
|
|
3349
3394
|
...entry.fixtures !== void 0 ? { fixtures: entry.fixtures } : {},
|
|
3350
3395
|
...(advertisedHttpBase(entry) ?? entry.baseUrl) !== void 0 ? { baseUrl: advertisedHttpBase(entry) ?? entry.baseUrl } : {}
|
|
3351
3396
|
});
|
|
@@ -3364,6 +3409,8 @@ var httpChild = async (target, entry, options, admission, generation, privateAcc
|
|
|
3364
3409
|
].some((method) => typeof created[method] !== "function"))
|
|
3365
3410
|
throw new Error("HTTP target does not implement the fleet runtime protocol; build/install matching supported service versions");
|
|
3366
3411
|
const runtime = created;
|
|
3412
|
+
if (entry.idBase !== void 0)
|
|
3413
|
+
runtime.setIdBase?.(entry.idBase);
|
|
3367
3414
|
const unobserve = runtime.webhooks?.observeDeliveries(observer.delivery);
|
|
3368
3415
|
if (options.outbound && runtime.webhooks)
|
|
3369
3416
|
runtime.webhooks.setTransportPolicy(ownedTransport(options.outbound));
|
|
@@ -3962,6 +4009,7 @@ async function startFleet(config, options) {
|
|
|
3962
4009
|
...entry,
|
|
3963
4010
|
adminPrefix: resolveAdminPrefix(entry.adminPrefix ?? adminPrefix),
|
|
3964
4011
|
...adminKey !== void 0 ? { adminKey } : {},
|
|
4012
|
+
...(entry.idBase ?? config.idBase) !== void 0 ? { idBase: entry.idBase ?? config.idBase } : {},
|
|
3965
4013
|
// Fleet-wide controls, with the service's own keys replacing them.
|
|
3966
4014
|
...config.adminControls !== void 0 || entry.adminControls !== void 0 ? { adminControls: { ...config.adminControls, ...entry.adminControls } } : {}
|
|
3967
4015
|
}, options, (namespace, request) => management?.admit(namespace, request), (namespace) => management?.generation(namespace), (namespace, request) => management?.privateRequest(namespace, request) ?? false, {
|
|
@@ -4646,6 +4694,16 @@ var COMMON_SERVE_OPTIONS = {
|
|
|
4646
4694
|
value: "<seed>",
|
|
4647
4695
|
description: "Seed for every random choice (env MOCKINGBIRD_SEED)"
|
|
4648
4696
|
},
|
|
4697
|
+
"id-base": {
|
|
4698
|
+
type: "string",
|
|
4699
|
+
value: "<n|boot>",
|
|
4700
|
+
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)"
|
|
4701
|
+
},
|
|
4702
|
+
settings: {
|
|
4703
|
+
type: "string",
|
|
4704
|
+
value: "<json|file>",
|
|
4705
|
+
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)"
|
|
4706
|
+
},
|
|
4649
4707
|
"admin-controls": {
|
|
4650
4708
|
type: "string",
|
|
4651
4709
|
value: "<json|file>",
|
|
@@ -4740,19 +4798,40 @@ var readJsonFile = async (path, label) => {
|
|
|
4740
4798
|
}
|
|
4741
4799
|
};
|
|
4742
4800
|
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4801
|
+
var readJsonOption = async (source, label) => {
|
|
4802
|
+
const trimmed = source.trim();
|
|
4803
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
4804
|
+
try {
|
|
4805
|
+
return JSON.parse(trimmed);
|
|
4806
|
+
} catch {
|
|
4807
|
+
throw new Error(`${label}: not valid JSON`);
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
return readJsonFile(source, label);
|
|
4811
|
+
};
|
|
4812
|
+
var resolveServeIdBase = (values, env = process.env) => {
|
|
4813
|
+
const source = asString(values["id-base"]) ?? env.MOCKINGBIRD_ID_BASE;
|
|
4814
|
+
if (source === void 0 || source.trim() === "")
|
|
4815
|
+
return void 0;
|
|
4816
|
+
normalizeIdBase(source.trim(), "--id-base");
|
|
4817
|
+
return source.trim();
|
|
4818
|
+
};
|
|
4819
|
+
var resolveServeSettings = async (target, values, env = process.env) => {
|
|
4820
|
+
const flag = asString(values.settings);
|
|
4821
|
+
const source = flag ?? env.MOCKINGBIRD_SETTINGS;
|
|
4822
|
+
if (source === void 0 || source.trim() === "")
|
|
4823
|
+
return void 0;
|
|
4824
|
+
const label = flag !== void 0 ? "--settings" : "MOCKINGBIRD_SETTINGS";
|
|
4825
|
+
const parsed = await readJsonOption(source, label);
|
|
4826
|
+
if (!isObject2(parsed))
|
|
4827
|
+
throw new Error(`${label}: expected a JSON object`);
|
|
4828
|
+
return checkSettings(target, parsed, label);
|
|
4829
|
+
};
|
|
4743
4830
|
var resolveServeControls = async (values, env = process.env, base) => {
|
|
4744
4831
|
const source = asString(values["admin-controls"]) ?? env.MOCKINGBIRD_ADMIN_CONTROLS;
|
|
4745
4832
|
let document = isObject2(base) ? { ...base } : {};
|
|
4746
4833
|
if (source !== void 0 && source.trim() !== "") {
|
|
4747
|
-
|
|
4748
|
-
if (source.trim().startsWith("{")) {
|
|
4749
|
-
try {
|
|
4750
|
-
parsed = JSON.parse(source);
|
|
4751
|
-
} catch {
|
|
4752
|
-
throw new Error("--admin-controls: not valid JSON");
|
|
4753
|
-
}
|
|
4754
|
-
} else
|
|
4755
|
-
parsed = await readJsonFile(source, "--admin-controls");
|
|
4834
|
+
const parsed = source.trim().startsWith("{") ? await readJsonOption(source, "--admin-controls") : await readJsonFile(source, "--admin-controls");
|
|
4756
4835
|
if (!isObject2(parsed))
|
|
4757
4836
|
throw new Error("--admin-controls: expected a JSON object");
|
|
4758
4837
|
document = { ...document, ...parsed };
|
|
@@ -4802,8 +4881,11 @@ var start = async (target, values, config) => {
|
|
|
4802
4881
|
adminKey: config.adminKey,
|
|
4803
4882
|
seed: config.seed,
|
|
4804
4883
|
onLog: formatLog(config.log),
|
|
4884
|
+
...config.settings !== void 0 ? { settings: config.settings } : {},
|
|
4805
4885
|
...config.adminControls !== void 0 ? { adminControls: config.adminControls } : {}
|
|
4806
4886
|
});
|
|
4887
|
+
if (config.idBase !== void 0)
|
|
4888
|
+
runtime.setIdBase?.(config.idBase);
|
|
4807
4889
|
const listening = await listen(runtime, { port: config.port, host: config.host });
|
|
4808
4890
|
target.listening?.(listening);
|
|
4809
4891
|
console.log(`${target.name} emulator listening on ${listening.url}`);
|
|
@@ -4849,6 +4931,11 @@ var serveCommand = (target) => ({
|
|
|
4849
4931
|
const adminControls = await resolveServeControls(values, process.env, config.adminControls);
|
|
4850
4932
|
if (adminControls !== void 0)
|
|
4851
4933
|
config.adminControls = adminControls;
|
|
4934
|
+
if (values.settings !== void 0)
|
|
4935
|
+
throw new Error("--settings serves a single service; give each service its own `settings` in the config");
|
|
4936
|
+
const idBase = config.idBase ?? resolveServeIdBase(values);
|
|
4937
|
+
if (idBase !== void 0)
|
|
4938
|
+
config.idBase = idBase;
|
|
4852
4939
|
const fleet = await startFleet(config, {
|
|
4853
4940
|
load: (name) => loadTarget(name, target),
|
|
4854
4941
|
onLog: formatLog(config.log ?? log),
|
|
@@ -4878,8 +4965,12 @@ var serveCommand = (target) => ({
|
|
|
4878
4965
|
let listening;
|
|
4879
4966
|
try {
|
|
4880
4967
|
const adminControls = await resolveServeControls(values);
|
|
4968
|
+
const idBase = resolveServeIdBase(values);
|
|
4969
|
+
const settings = await resolveServeSettings(target, values);
|
|
4881
4970
|
listening = await start(target, values, {
|
|
4882
4971
|
...adminControls !== void 0 ? { adminControls } : {},
|
|
4972
|
+
...idBase !== void 0 ? { idBase } : {},
|
|
4973
|
+
...settings !== void 0 ? { settings } : {},
|
|
4883
4974
|
adminPrefix: resolveAdminPrefix(asString(values["admin-prefix"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX),
|
|
4884
4975
|
port: port === void 0 ? target.defaultPort : Number.parseInt(port, 10),
|
|
4885
4976
|
host: asString(values.host) ?? "127.0.0.1",
|
|
@@ -4963,8 +5054,27 @@ var serveTarget = {
|
|
|
4963
5054
|
},
|
|
4964
5055
|
geo: {
|
|
4965
5056
|
type: "string",
|
|
4966
|
-
value: "<corpus|synthetic>",
|
|
4967
|
-
description: "Unknown ZIPs: refuse (corpus) or invent
|
|
5057
|
+
value: "<corpus|synthetic|corpus+synthetic>",
|
|
5058
|
+
description: "Unknown ZIPs: refuse (corpus), invent coverage (synthetic), or replay covered ZIPs and invent the rest (corpus+synthetic)"
|
|
5059
|
+
},
|
|
5060
|
+
"zip-overlays": {
|
|
5061
|
+
type: "string",
|
|
5062
|
+
value: "<file>",
|
|
5063
|
+
description: 'ZIP aliases and per-ZIP overrides: { "aliases": { "07105": "85004" }, "overrides": { "07105": { "phlebotomy_served": true } } }'
|
|
5064
|
+
},
|
|
5065
|
+
"catalog-overlays": {
|
|
5066
|
+
type: "string",
|
|
5067
|
+
value: "<file>",
|
|
5068
|
+
description: 'Lab tests cloned from catalog ones at boot: a JSON array of { "from", "id", "name", "slug", "lab", "stripAoe", "autoGenerated" }'
|
|
5069
|
+
},
|
|
5070
|
+
"marker-catalog": {
|
|
5071
|
+
type: "string",
|
|
5072
|
+
value: "<file>",
|
|
5073
|
+
description: "Markers GET /v3/lab_tests/markers offers on top of the catalog's: a JSON array (price, aoe, expected_results, a_la_carte_enabled)"
|
|
5074
|
+
},
|
|
5075
|
+
"add-on-source-markers": {
|
|
5076
|
+
type: "boolean",
|
|
5077
|
+
description: "Name the markers behind each add-on result line (source_markers[].marker_id)"
|
|
4968
5078
|
},
|
|
4969
5079
|
"lab-accounts": {
|
|
4970
5080
|
type: "string",
|
|
@@ -5054,9 +5164,15 @@ var serveTarget = {
|
|
|
5054
5164
|
corpus = await loadCorpus(asString2(values.corpus) ?? "default");
|
|
5055
5165
|
}
|
|
5056
5166
|
const geo = asString2(values.geo);
|
|
5057
|
-
if (geo !== void 0 && geo !== "corpus" && geo !== "synthetic") {
|
|
5058
|
-
throw new Error(`--geo must be corpus or synthetic (got ${geo})`);
|
|
5167
|
+
if (geo !== void 0 && geo !== "corpus" && geo !== "synthetic" && geo !== "corpus+synthetic") {
|
|
5168
|
+
throw new Error(`--geo must be corpus, synthetic or corpus+synthetic (got ${geo})`);
|
|
5059
5169
|
}
|
|
5170
|
+
const zipFile = asString2(values["zip-overlays"]);
|
|
5171
|
+
const zipOverlays = zipFile === void 0 ? void 0 : await readJson(zipFile);
|
|
5172
|
+
const overlayFile = asString2(values["catalog-overlays"]);
|
|
5173
|
+
const catalogOverlays = overlayFile === void 0 ? void 0 : await readJson(overlayFile);
|
|
5174
|
+
const markerFile = asString2(values["marker-catalog"]);
|
|
5175
|
+
const markerCatalog = markerFile === void 0 ? void 0 : await readJson(markerFile);
|
|
5060
5176
|
const accountsFile = asString2(values["lab-accounts"]);
|
|
5061
5177
|
const labAccounts = accountsFile === void 0 ? void 0 : await readJson(accountsFile);
|
|
5062
5178
|
const fixturesFile = asString2(values.fixtures);
|
|
@@ -5087,6 +5203,10 @@ var serveTarget = {
|
|
|
5087
5203
|
return createRuntime({
|
|
5088
5204
|
...corpus ? { corpus } : {},
|
|
5089
5205
|
...geo ? { geo } : {},
|
|
5206
|
+
...zipOverlays ? { zipOverlays } : {},
|
|
5207
|
+
...catalogOverlays ? { catalogOverlays } : {},
|
|
5208
|
+
...markerCatalog ? { markerCatalog } : {},
|
|
5209
|
+
...values["add-on-source-markers"] === true ? { addOnSourceMarkers: true } : {},
|
|
5090
5210
|
...labAccounts ? { labAccounts } : {},
|
|
5091
5211
|
...fixtures ? { fixtures } : {},
|
|
5092
5212
|
...teamId !== void 0 ? { teamId } : {},
|
|
@@ -5116,7 +5236,7 @@ var serveTarget = {
|
|
|
5116
5236
|
const info = api.corpusInfo();
|
|
5117
5237
|
return [
|
|
5118
5238
|
info ? `corpus ${info.label}: ${info.observations} observations, ${info.zips} ZIPs, ${info.labTests} lab tests, ${info.labAccounts} lab accounts (recorded ${info.recordedAt} from ${info.source})` : "corpus none: synthetic catalog and coverage",
|
|
5119
|
-
`geo ${api.geoMode}${api.geoMode === "corpus" ? " (unknown ZIPs answer 424 MOCKINGBIRD_UNKNOWN_ZIP)" : ""}`,
|
|
5239
|
+
`geo ${api.geoMode}${api.geoMode === "corpus" ? " (unknown ZIPs answer 424 MOCKINGBIRD_UNKNOWN_ZIP)" : api.geoMode === "corpus+synthetic" ? " (covered ZIPs replay the recording, the rest are synthesized)" : ""}`,
|
|
5120
5240
|
`team ${api.teamId}`,
|
|
5121
5241
|
`lab accounts: ${api.labAccounts().length}`,
|
|
5122
5242
|
`limits: ${Object.entries(api.limits).filter(([, value]) => value !== null && value !== false).map(([key, value]) => `${key}=${String(value)}`).join(", ") || "none (sandbox caps off)"}`,
|
|
@@ -5135,4 +5255,4 @@ export {
|
|
|
5135
5255
|
createServer2 as createServer,
|
|
5136
5256
|
serveTarget
|
|
5137
5257
|
};
|
|
5138
|
-
//# sourceMappingURL=chunk-
|
|
5258
|
+
//# sourceMappingURL=chunk-NTGGNJKR.js.map
|