@crvouga/mockingbird-service-stripe 3.5.0 → 3.6.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-SBWLNRX7.js → chunk-53CRCMWH.js} +2 -2
- package/dist/{chunk-6GPNQX6K.js → chunk-Q3J6JUZM.js} +235 -43
- package/dist/chunk-Q3J6JUZM.js.map +7 -0
- package/dist/chunk-Z5GZOENC.js +1 -1
- package/dist/cli.js +2 -2
- package/dist/fleet.d.ts +58 -7
- package/dist/fleet.js +9 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-6GPNQX6K.js.map +0 -7
- /package/dist/{chunk-SBWLNRX7.js.map → chunk-53CRCMWH.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-stripe
|
|
2
2
|
|
|
3
|
-
## 3.
|
|
3
|
+
## 3.6.0 (2026-10-17)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- resolve fleet and emulator issue batch ([26d2f8c](https://github.com/crvouga/mockingbird/commit/26d2f8cee99fefed93192204bac44fb1be35c1da))
|
|
8
|
+
|
|
9
|
+
## 3.5.0 (2026-10-15)
|
|
4
10
|
|
|
5
11
|
### Features
|
|
6
12
|
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-EUF2MBTV.js";
|
|
5
5
|
import {
|
|
6
6
|
listen
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-Q3J6JUZM.js";
|
|
8
8
|
|
|
9
9
|
// src/server.ts
|
|
10
10
|
import { readFileSync } from "node:fs";
|
|
@@ -87,4 +87,4 @@ export {
|
|
|
87
87
|
createServer,
|
|
88
88
|
serveTarget
|
|
89
89
|
};
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
90
|
+
//# sourceMappingURL=chunk-53CRCMWH.js.map
|
|
@@ -12,6 +12,38 @@ import {
|
|
|
12
12
|
|
|
13
13
|
// ../../adapters/node/dist/fleet-archive.js
|
|
14
14
|
import { createHash } from "node:crypto";
|
|
15
|
+
function validateCompatibilityTags(tags) {
|
|
16
|
+
if (!tags || typeof tags !== "object" || Array.isArray(tags))
|
|
17
|
+
throw new Error("invalid archive compatibility tags");
|
|
18
|
+
const entries = Object.entries(tags);
|
|
19
|
+
if (entries.length > 32 || entries.some(([key, value]) => !/^[A-Za-z0-9_.-]{1,64}$/.test(key) || typeof value !== "string" || value.length < 1 || value.length > 256 || [...value].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)))
|
|
20
|
+
throw new Error("invalid archive compatibility tags");
|
|
21
|
+
}
|
|
22
|
+
function assertCompatibilityTags(tags, policy) {
|
|
23
|
+
if (tags !== void 0)
|
|
24
|
+
validateCompatibilityTags(tags);
|
|
25
|
+
if (!policy)
|
|
26
|
+
return;
|
|
27
|
+
validateCompatibilityTags(policy.tags);
|
|
28
|
+
if (policy.missing !== void 0 && !["allow", "reject"].includes(policy.missing))
|
|
29
|
+
throw new Error("invalid missing compatibility policy");
|
|
30
|
+
if (tags === void 0 && policy.missing === "allow")
|
|
31
|
+
return;
|
|
32
|
+
if (canonical(tags) !== canonical(policy.tags))
|
|
33
|
+
throw new Error("application archive compatibility mismatch");
|
|
34
|
+
}
|
|
35
|
+
function assertArchiveCompatibility(input, policy) {
|
|
36
|
+
const archive = validateArchive(input);
|
|
37
|
+
assertCompatibilityTags(archive.compatibility, policy);
|
|
38
|
+
return archive;
|
|
39
|
+
}
|
|
40
|
+
async function migrateApplicationArchive(input, migration) {
|
|
41
|
+
const source = assertArchiveCompatibility(input, migration.from);
|
|
42
|
+
validateCompatibilityTags(migration.to);
|
|
43
|
+
const transformed = await migration.transform(structuredClone(source));
|
|
44
|
+
const { sha256: _sha, ...content } = transformed;
|
|
45
|
+
return validateArchive(sealArchive({ ...content, compatibility: structuredClone(migration.to) }));
|
|
46
|
+
}
|
|
15
47
|
var canonical = (value) => {
|
|
16
48
|
if (Array.isArray(value))
|
|
17
49
|
return `[${value.map(canonical).join(",")}]`;
|
|
@@ -31,6 +63,8 @@ function validateArchive(value) {
|
|
|
31
63
|
const { sha256, ...content } = doc;
|
|
32
64
|
if (doc.format !== "mockingbird.fleet/v1" || typeof doc.sourceId !== "string" || typeof doc.createdAt !== "string" || !doc.namespaces || typeof doc.namespaces !== "object" || Array.isArray(doc.namespaces) || sha256 !== digest(content))
|
|
33
65
|
throw new Error("unsupported or corrupt fleet archive");
|
|
66
|
+
if (doc.compatibility !== void 0)
|
|
67
|
+
validateCompatibilityTags(doc.compatibility);
|
|
34
68
|
for (const [namespace, entry] of Object.entries(doc.namespaces)) {
|
|
35
69
|
if (!/^[A-Za-z0-9_.-]{1,64}$/.test(namespace) || !entry || !Number.isFinite(entry.clock?.now) || typeof entry.clock?.frozen !== "boolean" || !entry.services || !Object.keys(entry.services).length)
|
|
36
70
|
throw new Error("invalid archive namespace");
|
|
@@ -46,6 +80,7 @@ function inspectArchive(input) {
|
|
|
46
80
|
format: archive.format,
|
|
47
81
|
createdAt: archive.createdAt,
|
|
48
82
|
sha256: archive.sha256,
|
|
83
|
+
...archive.compatibility ? { compatibility: archive.compatibility } : {},
|
|
49
84
|
namespaces: Object.fromEntries(Object.entries(archive.namespaces).map(([name, ns]) => [
|
|
50
85
|
name,
|
|
51
86
|
{
|
|
@@ -1280,11 +1315,28 @@ var ingressSupport = {
|
|
|
1280
1315
|
streaming: true,
|
|
1281
1316
|
signing: "vendor request signing is not used; webhook signatures remain payload based"
|
|
1282
1317
|
},
|
|
1318
|
+
cognito: {
|
|
1319
|
+
publicOrigin: true,
|
|
1320
|
+
pathPrefix: true,
|
|
1321
|
+
namespaces: "path-or-header",
|
|
1322
|
+
streaming: true,
|
|
1323
|
+
signing: "JWT issuer and JWKS use the configured public namespace; SigV4 verification is not modelled"
|
|
1324
|
+
},
|
|
1325
|
+
medplum: {
|
|
1326
|
+
publicOrigin: true,
|
|
1327
|
+
pathPrefix: true,
|
|
1328
|
+
namespaces: "path-or-header",
|
|
1329
|
+
streaming: true,
|
|
1330
|
+
signing: "FHIR, OAuth and storage URLs use the configured public namespace"
|
|
1331
|
+
},
|
|
1283
1332
|
other: {
|
|
1284
1333
|
publicOrigin: false,
|
|
1285
1334
|
reason: "host/path-sensitive signing and hosted URL rewriting are not certified; use a direct endpoint"
|
|
1286
1335
|
}
|
|
1287
1336
|
};
|
|
1337
|
+
function supportsPublicIngress(service) {
|
|
1338
|
+
return service === "stripe" || service === "cognito" || service === "medplum";
|
|
1339
|
+
}
|
|
1288
1340
|
function advertisedHttpBase(entry) {
|
|
1289
1341
|
if (entry.publicPath !== void 0 && !entry.publicOrigin)
|
|
1290
1342
|
throw new Error("publicPath requires publicOrigin");
|
|
@@ -1303,7 +1355,7 @@ function createFleetIngress(config, manifest, transport = fetch) {
|
|
|
1303
1355
|
const base = advertisedHttpBase(entry);
|
|
1304
1356
|
if (!base)
|
|
1305
1357
|
return [];
|
|
1306
|
-
if ((entry.target ?? service)
|
|
1358
|
+
if (!supportsPublicIngress(entry.target ?? service))
|
|
1307
1359
|
throw new Error(`public ingress unsupported for ${entry.target ?? service}; host/path-sensitive signatures require a direct endpoint`);
|
|
1308
1360
|
const privateEndpoint = manifest.services[service];
|
|
1309
1361
|
if (!privateEndpoint || entry.protocol && entry.protocol !== "http")
|
|
@@ -1327,6 +1379,8 @@ function createFleetIngress(config, manifest, transport = fetch) {
|
|
|
1327
1379
|
const route = routes.find((r) => url.origin === r.origin && (url.pathname === r.prefix || url.pathname.startsWith(`${r.prefix}/`)));
|
|
1328
1380
|
if (!route)
|
|
1329
1381
|
return new Response("public ingress route not found", { status: 404 });
|
|
1382
|
+
if ((route.entry.target ?? route.service) === "cognito" && request.headers.get("authorization")?.startsWith("AWS4-HMAC-SHA256"))
|
|
1383
|
+
return new Response("SigV4 requests require a direct endpoint", { status: 403 });
|
|
1330
1384
|
const path = url.pathname.slice(route.prefix.length) || "/";
|
|
1331
1385
|
const adminPrefix = route.entry.adminPrefix ?? config.adminPrefix ?? "/__admin";
|
|
1332
1386
|
if ((path === adminPrefix || path.startsWith(`${adminPrefix}/`)) && !path.startsWith(`${adminPrefix}/ns/`))
|
|
@@ -2347,7 +2401,7 @@ data: ${JSON.stringify(data)}
|
|
|
2347
2401
|
{
|
|
2348
2402
|
protocol: c.protocol,
|
|
2349
2403
|
coverage: c.coverage,
|
|
2350
|
-
ingress: c.targetName
|
|
2404
|
+
ingress: supportsPublicIngress(c.targetName ?? "") ? ingressSupport[c.targetName] : ingressSupport.other,
|
|
2351
2405
|
target: c.targetName,
|
|
2352
2406
|
outboundPolicy: c.outboundPolicy ?? "unsupported",
|
|
2353
2407
|
version: 1,
|
|
@@ -3431,11 +3485,12 @@ data: ${JSON.stringify(data)}
|
|
|
3431
3485
|
format: "mockingbird.fleet/v1",
|
|
3432
3486
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3433
3487
|
sourceId: this.ctx.id,
|
|
3488
|
+
...this.ctx.options.archiveCompatibility ? { compatibility: structuredClone(this.ctx.options.archiveCompatibility.tags) } : {},
|
|
3434
3489
|
namespaces: contents
|
|
3435
3490
|
});
|
|
3436
3491
|
}
|
|
3437
3492
|
async restoreArchive(input, selectedNamespace) {
|
|
3438
|
-
const archive =
|
|
3493
|
+
const archive = assertArchiveCompatibility(input, this.ctx.options.archiveCompatibility);
|
|
3439
3494
|
const entries = Object.entries(archive.namespaces).filter(([ns]) => selectedNamespace === void 0 || ns === selectedNamespace);
|
|
3440
3495
|
if (!entries.length)
|
|
3441
3496
|
throw new Error("selected namespace absent from archive");
|
|
@@ -3719,7 +3774,7 @@ async function preflightFleet(config, options) {
|
|
|
3719
3774
|
if (entry.target !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(entry.target))
|
|
3720
3775
|
throw new Error("target must name a supported service suffix");
|
|
3721
3776
|
const service = entry.target ?? name;
|
|
3722
|
-
if (advertisedHttpBase(entry) && service
|
|
3777
|
+
if (advertisedHttpBase(entry) && !supportsPublicIngress(service))
|
|
3723
3778
|
throw new Error(`public ingress unsupported for ${service}; use a direct endpoint to preserve signed targets`);
|
|
3724
3779
|
const target = await options.load(service);
|
|
3725
3780
|
const protocol = "protocol" in target ? target.protocol : "http";
|
|
@@ -3770,7 +3825,7 @@ async function preflightFleet(config, options) {
|
|
|
3770
3825
|
break;
|
|
3771
3826
|
}
|
|
3772
3827
|
}
|
|
3773
|
-
targets.set(name, { ...target, packageVersion: packageVersion ?? "3.
|
|
3828
|
+
targets.set(name, { ...target, packageVersion: packageVersion ?? "3.6.0" });
|
|
3774
3829
|
} catch (error) {
|
|
3775
3830
|
throw new Error(`service ${name}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3776
3831
|
}
|
|
@@ -3814,6 +3869,11 @@ async function preflightFleet(config, options) {
|
|
|
3814
3869
|
return ordered;
|
|
3815
3870
|
}
|
|
3816
3871
|
function validateFleetPolicies(options) {
|
|
3872
|
+
if (options.archiveCompatibility) {
|
|
3873
|
+
validateCompatibilityTags(options.archiveCompatibility.tags);
|
|
3874
|
+
if (options.archiveCompatibility.missing !== void 0 && !["allow", "reject"].includes(options.archiveCompatibility.missing))
|
|
3875
|
+
throw new Error("archiveCompatibility.missing must be allow or reject");
|
|
3876
|
+
}
|
|
3817
3877
|
if (options.journal && !options.repository)
|
|
3818
3878
|
throw new Error("durable operation journal requires an archive repository");
|
|
3819
3879
|
if (options.cors) {
|
|
@@ -4645,6 +4705,40 @@ async function startFleet(config, options) {
|
|
|
4645
4705
|
}
|
|
4646
4706
|
}
|
|
4647
4707
|
|
|
4708
|
+
// ../../adapters/node/dist/fleet-loader.js
|
|
4709
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
4710
|
+
import { resolve as resolve2 } from "node:path";
|
|
4711
|
+
import { pathToFileURL } from "node:url";
|
|
4712
|
+
var suffix = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4713
|
+
function createInstalledServiceLoader(options) {
|
|
4714
|
+
if (!options.projectRoot)
|
|
4715
|
+
throw new Error("consumer projectRoot required");
|
|
4716
|
+
const allowed = new Set(options.services);
|
|
4717
|
+
for (const name of allowed)
|
|
4718
|
+
if (!suffix.test(name))
|
|
4719
|
+
throw new Error("invalid service suffix");
|
|
4720
|
+
const require2 = createRequire2(resolve2(options.projectRoot, "package.json"));
|
|
4721
|
+
const targets = new Map((options.targets ?? []).map((target) => [target.name, target]));
|
|
4722
|
+
return async (name) => {
|
|
4723
|
+
if (!suffix.test(name) || !allowed.has(name))
|
|
4724
|
+
throw new Error("service is not declared in loader allowlist");
|
|
4725
|
+
const own = targets.get(name);
|
|
4726
|
+
if (own)
|
|
4727
|
+
return own;
|
|
4728
|
+
const specifier = `@crvouga/mockingbird-service-${name}/server`;
|
|
4729
|
+
let location;
|
|
4730
|
+
try {
|
|
4731
|
+
location = require2.resolve(specifier);
|
|
4732
|
+
} catch {
|
|
4733
|
+
throw new Error(`cannot load service "${name}": install @crvouga/mockingbird-service-${name} in the consumer project; its /server export is required`);
|
|
4734
|
+
}
|
|
4735
|
+
const mod = await import(pathToFileURL(location).href);
|
|
4736
|
+
if (!mod.serveTarget || mod.serveTarget.name !== name || ("protocol" in mod.serveTarget ? typeof mod.serveTarget.start !== "function" : typeof mod.serveTarget.create !== "function"))
|
|
4737
|
+
throw new Error(`${specifier} exports no matching serveTarget`);
|
|
4738
|
+
return mod.serveTarget;
|
|
4739
|
+
};
|
|
4740
|
+
}
|
|
4741
|
+
|
|
4648
4742
|
// ../../adapters/node/dist/fleet-client.js
|
|
4649
4743
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
4650
4744
|
import { chmod as chmod2, readFile as readFile5, rename as rename4, rm as rm4, writeFile as writeFile4 } from "node:fs/promises";
|
|
@@ -4657,6 +4751,14 @@ var FleetClientError = class extends Error {
|
|
|
4657
4751
|
this.details = details;
|
|
4658
4752
|
}
|
|
4659
4753
|
};
|
|
4754
|
+
var FleetClientResponseError = class extends FleetClientError {
|
|
4755
|
+
code;
|
|
4756
|
+
constructor(code, status, origin) {
|
|
4757
|
+
super(status, { code, body: "omitted", ...origin ? { origin } : {} });
|
|
4758
|
+
this.code = code;
|
|
4759
|
+
this.name = "FleetClientResponseError";
|
|
4760
|
+
}
|
|
4761
|
+
};
|
|
4660
4762
|
var FleetClient = class {
|
|
4661
4763
|
base;
|
|
4662
4764
|
options;
|
|
@@ -4669,7 +4771,14 @@ var FleetClient = class {
|
|
|
4669
4771
|
if (url.username || url.password)
|
|
4670
4772
|
throw new Error("fleet client URL must not contain credentials");
|
|
4671
4773
|
url.searchParams.set("namespace", options.namespace ?? this.options.namespace ?? "default");
|
|
4774
|
+
const limit = options.maxResponseBytes ?? this.options.maxResponseBytes ?? 64 * 1024 * 1024;
|
|
4775
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
4776
|
+
throw new Error("invalid response byte limit");
|
|
4777
|
+
const deadline = AbortSignal.timeout(this.options.timeoutMs ?? 3e4);
|
|
4778
|
+
const signal = options.signal ? AbortSignal.any([options.signal, deadline]) : deadline;
|
|
4779
|
+
signal.throwIfAborted();
|
|
4672
4780
|
const response = await (this.options.fetch ?? fetch)(url, {
|
|
4781
|
+
redirect: "manual",
|
|
4673
4782
|
method: options.method ?? (options.body === void 0 ? "GET" : "POST"),
|
|
4674
4783
|
headers: {
|
|
4675
4784
|
"content-type": "application/json",
|
|
@@ -4677,11 +4786,71 @@ var FleetClient = class {
|
|
|
4677
4786
|
...options.idempotencyKey ? { "idempotency-key": options.idempotencyKey } : {}
|
|
4678
4787
|
},
|
|
4679
4788
|
...options.body !== void 0 ? { body: JSON.stringify(options.body) } : {},
|
|
4680
|
-
signal
|
|
4789
|
+
signal
|
|
4681
4790
|
});
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
throw new
|
|
4791
|
+
if (response.status >= 300 && response.status < 400) {
|
|
4792
|
+
await response.body?.cancel();
|
|
4793
|
+
throw new FleetClientResponseError("redirect", response.status, url.origin);
|
|
4794
|
+
}
|
|
4795
|
+
if (Number(response.headers.get("content-length")) > limit) {
|
|
4796
|
+
await response.body?.cancel();
|
|
4797
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4798
|
+
}
|
|
4799
|
+
const reader = response.body?.getReader();
|
|
4800
|
+
const chunks = [];
|
|
4801
|
+
let size = 0;
|
|
4802
|
+
const abort = () => {
|
|
4803
|
+
void reader?.cancel(signal.reason).catch(() => {
|
|
4804
|
+
});
|
|
4805
|
+
};
|
|
4806
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
4807
|
+
try {
|
|
4808
|
+
if (reader)
|
|
4809
|
+
while (true) {
|
|
4810
|
+
signal.throwIfAborted();
|
|
4811
|
+
const { done, value } = await reader.read();
|
|
4812
|
+
signal.throwIfAborted();
|
|
4813
|
+
if (done)
|
|
4814
|
+
break;
|
|
4815
|
+
size += value.byteLength;
|
|
4816
|
+
if (size > limit) {
|
|
4817
|
+
await reader.cancel();
|
|
4818
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4819
|
+
}
|
|
4820
|
+
chunks.push(value);
|
|
4821
|
+
}
|
|
4822
|
+
} finally {
|
|
4823
|
+
signal.removeEventListener("abort", abort);
|
|
4824
|
+
if (signal.aborted)
|
|
4825
|
+
await reader?.cancel(signal.reason).catch(() => {
|
|
4826
|
+
});
|
|
4827
|
+
reader?.releaseLock();
|
|
4828
|
+
}
|
|
4829
|
+
const bytes2 = new Uint8Array(size);
|
|
4830
|
+
let offset = 0;
|
|
4831
|
+
for (const chunk of chunks) {
|
|
4832
|
+
bytes2.set(chunk, offset);
|
|
4833
|
+
offset += chunk.byteLength;
|
|
4834
|
+
}
|
|
4835
|
+
const text = new TextDecoder().decode(bytes2);
|
|
4836
|
+
let data;
|
|
4837
|
+
try {
|
|
4838
|
+
data = text.length ? JSON.parse(text) : void 0;
|
|
4839
|
+
} catch {
|
|
4840
|
+
if (response.ok)
|
|
4841
|
+
throw new FleetClientResponseError("invalid_json", response.status);
|
|
4842
|
+
}
|
|
4843
|
+
if (!response.ok) {
|
|
4844
|
+
const error = data && typeof data === "object" ? data.error : void 0;
|
|
4845
|
+
const detail = { body: "omitted" };
|
|
4846
|
+
if (error && typeof error === "object")
|
|
4847
|
+
for (const key of ["type", "code"]) {
|
|
4848
|
+
const value = error[key];
|
|
4849
|
+
if (typeof value === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(value))
|
|
4850
|
+
detail[key] = value;
|
|
4851
|
+
}
|
|
4852
|
+
throw new FleetClientError(response.status, detail);
|
|
4853
|
+
}
|
|
4685
4854
|
return data;
|
|
4686
4855
|
}
|
|
4687
4856
|
discover() {
|
|
@@ -4747,17 +4916,52 @@ function renderConnections(manifest, privateManifest, namespace, mapping) {
|
|
|
4747
4916
|
const child = manifest.services[entry.service], secret = privateManifest.services[entry.service];
|
|
4748
4917
|
if (!child || !secret)
|
|
4749
4918
|
throw new Error(`missing service mapping ${entry.service}`);
|
|
4919
|
+
let endpoint;
|
|
4750
4920
|
if (child.protocol === "http") {
|
|
4751
4921
|
const template = child.namespaces.path;
|
|
4752
4922
|
if (typeof template !== "string")
|
|
4753
4923
|
throw new Error(`missing HTTP namespace mapping ${entry.service}`);
|
|
4754
|
-
|
|
4924
|
+
endpoint = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
|
|
4755
4925
|
} else {
|
|
4756
|
-
const
|
|
4757
|
-
if (!
|
|
4926
|
+
const selected = secret.namespaces?.[namespace];
|
|
4927
|
+
if (!selected)
|
|
4758
4928
|
throw new Error(`missing namespace mapping ${namespace}/${entry.service}`);
|
|
4759
|
-
|
|
4929
|
+
endpoint = selected;
|
|
4930
|
+
}
|
|
4931
|
+
const url = new URL(endpoint);
|
|
4932
|
+
const field = entry.field ?? "url";
|
|
4933
|
+
let value;
|
|
4934
|
+
switch (field) {
|
|
4935
|
+
case "url":
|
|
4936
|
+
value = endpoint;
|
|
4937
|
+
break;
|
|
4938
|
+
case "hostname":
|
|
4939
|
+
value = url.hostname.replace(/^\[|\]$/g, "");
|
|
4940
|
+
break;
|
|
4941
|
+
case "port":
|
|
4942
|
+
value = url.port;
|
|
4943
|
+
break;
|
|
4944
|
+
case "username":
|
|
4945
|
+
value = decodeURIComponent(url.username);
|
|
4946
|
+
break;
|
|
4947
|
+
case "password":
|
|
4948
|
+
value = decodeURIComponent(url.password);
|
|
4949
|
+
break;
|
|
4950
|
+
case "pathname":
|
|
4951
|
+
value = decodeURIComponent(url.pathname);
|
|
4952
|
+
break;
|
|
4953
|
+
case "database":
|
|
4954
|
+
value = decodeURIComponent(url.pathname.replace(/^\//, ""));
|
|
4955
|
+
break;
|
|
4956
|
+
default:
|
|
4957
|
+
throw new Error("unsupported connection field");
|
|
4760
4958
|
}
|
|
4959
|
+
if (!value) {
|
|
4960
|
+
if (typeof entry.fallback !== "string")
|
|
4961
|
+
throw new Error(`missing connection component ${field}`);
|
|
4962
|
+
value = entry.fallback;
|
|
4963
|
+
}
|
|
4964
|
+
result[variable] = value;
|
|
4761
4965
|
}
|
|
4762
4966
|
return result;
|
|
4763
4967
|
}
|
|
@@ -4777,14 +4981,14 @@ async function writeConnections(path, values, format = "json") {
|
|
|
4777
4981
|
|
|
4778
4982
|
// ../../adapters/node/dist/fleet-tools.js
|
|
4779
4983
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
4780
|
-
import { createRequire as
|
|
4781
|
-
import { resolve as
|
|
4984
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
4985
|
+
import { resolve as resolve3 } from "node:path";
|
|
4782
4986
|
async function doctorFleet(config, options, probes = []) {
|
|
4783
4987
|
const findings = [];
|
|
4784
4988
|
const plan = [];
|
|
4785
4989
|
try {
|
|
4786
4990
|
const targets = await preflightFleet(config, options);
|
|
4787
|
-
const require2 =
|
|
4991
|
+
const require2 = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
4788
4992
|
for (const [service, target] of targets) {
|
|
4789
4993
|
let version = "development";
|
|
4790
4994
|
try {
|
|
@@ -4839,7 +5043,7 @@ async function doctorFleet(config, options, probes = []) {
|
|
|
4839
5043
|
};
|
|
4840
5044
|
}
|
|
4841
5045
|
async function rehearseFleet(config, options, input, probes = [], timeoutMs = 3e4) {
|
|
4842
|
-
const archive =
|
|
5046
|
+
const archive = assertArchiveCompatibility(input, options.archiveCompatibility);
|
|
4843
5047
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4844
5048
|
const isolated = {
|
|
4845
5049
|
...config,
|
|
@@ -4851,7 +5055,7 @@ async function rehearseFleet(config, options, input, probes = [], timeoutMs = 3e
|
|
|
4851
5055
|
};
|
|
4852
5056
|
let fleet;
|
|
4853
5057
|
try {
|
|
4854
|
-
fleet = await startFleet(isolated,
|
|
5058
|
+
fleet = await startFleet(isolated, options);
|
|
4855
5059
|
const client = new FleetClient(fleet.manifest.adminBase, {
|
|
4856
5060
|
...config.adminKey ? { adminKey: config.adminKey } : {}
|
|
4857
5061
|
});
|
|
@@ -4990,9 +5194,6 @@ function fleetCommands(load) {
|
|
|
4990
5194
|
|
|
4991
5195
|
// ../../adapters/node/dist/cli.js
|
|
4992
5196
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
4993
|
-
import { createRequire as createRequire3 } from "node:module";
|
|
4994
|
-
import { resolve as resolve3 } from "node:path";
|
|
4995
|
-
import { pathToFileURL } from "node:url";
|
|
4996
5197
|
import { parseArgs } from "node:util";
|
|
4997
5198
|
var optionHelp = (options) => Object.entries(options).map(([name, option]) => {
|
|
4998
5199
|
const flag = `--${name}${option.type === "string" ? ` ${option.value ?? "<value>"}` : ""}`;
|
|
@@ -5231,26 +5432,7 @@ var resolveServeControls = async (values, env = process.env, base) => {
|
|
|
5231
5432
|
normalizeBootControls(document, "adminControls");
|
|
5232
5433
|
return document;
|
|
5233
5434
|
};
|
|
5234
|
-
var loadTarget =
|
|
5235
|
-
if (name === own.name)
|
|
5236
|
-
return own;
|
|
5237
|
-
const specifier = `@crvouga/mockingbird-service-${name}/server`;
|
|
5238
|
-
try {
|
|
5239
|
-
let mod;
|
|
5240
|
-
try {
|
|
5241
|
-
mod = await import(specifier);
|
|
5242
|
-
} catch {
|
|
5243
|
-
const fromProject = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
5244
|
-
mod = await import(pathToFileURL(fromProject.resolve(specifier)).href);
|
|
5245
|
-
}
|
|
5246
|
-
if (!mod.serveTarget)
|
|
5247
|
-
throw new Error(`${specifier} exports no serveTarget`);
|
|
5248
|
-
return mod.serveTarget;
|
|
5249
|
-
} catch (error) {
|
|
5250
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
5251
|
-
throw new Error(`cannot load service "${name}": ${reason}. Install @crvouga/mockingbird-service-${name}.`);
|
|
5252
|
-
}
|
|
5253
|
-
};
|
|
5435
|
+
var loadTarget = (name, own) => createInstalledServiceLoader({ projectRoot: process.cwd(), services: [name], targets: [own] })(name);
|
|
5254
5436
|
var start = async (target, values, config) => {
|
|
5255
5437
|
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
5256
5438
|
const runtime = await target.create(values, {
|
|
@@ -5900,9 +6082,14 @@ var sourceArchive = (input) => {
|
|
|
5900
6082
|
throw new Error("corrupt migration source");
|
|
5901
6083
|
return structuredClone(source);
|
|
5902
6084
|
};
|
|
5903
|
-
function archiveCompatibility(input, registry) {
|
|
6085
|
+
function archiveCompatibility(input, registry, policy) {
|
|
5904
6086
|
const source = sourceArchive(input);
|
|
5905
6087
|
const problems = [], steps = [];
|
|
6088
|
+
try {
|
|
6089
|
+
assertCompatibilityTags(source.compatibility, policy);
|
|
6090
|
+
} catch (error) {
|
|
6091
|
+
problems.push(error instanceof Error ? error.message : "invalid application compatibility");
|
|
6092
|
+
}
|
|
5906
6093
|
if (source.format !== "mockingbird.fleet/v1" && !registry.sourceFormats.includes(source.format))
|
|
5907
6094
|
problems.push(`unsupported source format ${source.format}`);
|
|
5908
6095
|
for (const [namespace, ns] of Object.entries(source.namespaces))
|
|
@@ -5954,6 +6141,7 @@ async function migrateArchive(input, registry, parameters = {}) {
|
|
|
5954
6141
|
const content = {
|
|
5955
6142
|
format: "mockingbird.fleet/v1",
|
|
5956
6143
|
sourceId: source.sourceId,
|
|
6144
|
+
...source.compatibility ? { compatibility: source.compatibility } : {},
|
|
5957
6145
|
createdAt: source.createdAt,
|
|
5958
6146
|
namespaces,
|
|
5959
6147
|
migration: {
|
|
@@ -6320,6 +6508,8 @@ var NamespacePool = class {
|
|
|
6320
6508
|
};
|
|
6321
6509
|
|
|
6322
6510
|
export {
|
|
6511
|
+
assertArchiveCompatibility,
|
|
6512
|
+
migrateApplicationArchive,
|
|
6323
6513
|
validateArchive,
|
|
6324
6514
|
inspectArchive,
|
|
6325
6515
|
diffArchives,
|
|
@@ -6345,7 +6535,9 @@ export {
|
|
|
6345
6535
|
serve,
|
|
6346
6536
|
listen,
|
|
6347
6537
|
startFleet,
|
|
6538
|
+
createInstalledServiceLoader,
|
|
6348
6539
|
FleetClientError,
|
|
6540
|
+
FleetClientResponseError,
|
|
6349
6541
|
FleetClient,
|
|
6350
6542
|
renderConnections,
|
|
6351
6543
|
writeConnections,
|
|
@@ -6373,4 +6565,4 @@ export {
|
|
|
6373
6565
|
withFleetRun,
|
|
6374
6566
|
NamespacePool
|
|
6375
6567
|
};
|
|
6376
|
-
//# sourceMappingURL=chunk-
|
|
6568
|
+
//# sourceMappingURL=chunk-Q3J6JUZM.js.map
|