@crvouga/mockingbird-service-formbricks 3.5.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 +13 -1
- package/README.md +20 -1
- package/dist/{chunk-MYBPU56P.js → chunk-M3VADEIL.js} +442 -52
- package/dist/chunk-M3VADEIL.js.map +7 -0
- package/dist/{chunk-THESW6F4.js → chunk-XJB56QGS.js} +107 -23
- package/dist/chunk-XJB56QGS.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 +76 -1
- package/dist/server.js +4 -2
- package/package.json +1 -1
- package/dist/chunk-MYBPU56P.js.map +0 -7
- package/dist/chunk-THESW6F4.js.map +0 -7
|
@@ -1,23 +1,38 @@
|
|
|
1
1
|
import {
|
|
2
|
+
CORPUS_SURVEYS,
|
|
2
3
|
DEFAULT_SETTINGS,
|
|
3
4
|
createClock,
|
|
4
5
|
createRuntime,
|
|
5
6
|
normalizeBootControls,
|
|
6
7
|
normalizeControls,
|
|
8
|
+
normalizeIdBase,
|
|
7
9
|
ownedTransport,
|
|
8
10
|
parseDuration,
|
|
9
11
|
parseFaultHeader,
|
|
10
12
|
resolveAdminPrefix,
|
|
11
13
|
restoreClock
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XJB56QGS.js";
|
|
15
|
+
|
|
16
|
+
// src/server.ts
|
|
17
|
+
import { readFileSync } from "node:fs";
|
|
13
18
|
|
|
14
19
|
// ../../adapters/node/dist/cli.js
|
|
15
20
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
16
|
-
import { createRequire as createRequire3 } from "node:module";
|
|
17
|
-
import { resolve as resolve3 } from "node:path";
|
|
18
|
-
import { pathToFileURL } from "node:url";
|
|
19
21
|
import { parseArgs } from "node:util";
|
|
20
22
|
|
|
23
|
+
// ../../adapters/node/dist/boot-settings.js
|
|
24
|
+
var checkSettings = (target, settings, label) => {
|
|
25
|
+
if (!target.parseSettings)
|
|
26
|
+
throw new Error(`${label}: ${target.name} takes no boot settings`);
|
|
27
|
+
try {
|
|
28
|
+
return target.parseSettings(settings);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
throw new Error(`${label}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
31
|
+
cause: error
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
21
36
|
// ../../adapters/node/dist/fleet.js
|
|
22
37
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
23
38
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -29,6 +44,31 @@ import { createHash as createHash3, randomBytes, randomUUID as randomUUID3 } fro
|
|
|
29
44
|
|
|
30
45
|
// ../../adapters/node/dist/fleet-archive.js
|
|
31
46
|
import { createHash } from "node:crypto";
|
|
47
|
+
function validateCompatibilityTags(tags) {
|
|
48
|
+
if (!tags || typeof tags !== "object" || Array.isArray(tags))
|
|
49
|
+
throw new Error("invalid archive compatibility tags");
|
|
50
|
+
const entries = Object.entries(tags);
|
|
51
|
+
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)))
|
|
52
|
+
throw new Error("invalid archive compatibility tags");
|
|
53
|
+
}
|
|
54
|
+
function assertCompatibilityTags(tags, policy) {
|
|
55
|
+
if (tags !== void 0)
|
|
56
|
+
validateCompatibilityTags(tags);
|
|
57
|
+
if (!policy)
|
|
58
|
+
return;
|
|
59
|
+
validateCompatibilityTags(policy.tags);
|
|
60
|
+
if (policy.missing !== void 0 && !["allow", "reject"].includes(policy.missing))
|
|
61
|
+
throw new Error("invalid missing compatibility policy");
|
|
62
|
+
if (tags === void 0 && policy.missing === "allow")
|
|
63
|
+
return;
|
|
64
|
+
if (canonical(tags) !== canonical(policy.tags))
|
|
65
|
+
throw new Error("application archive compatibility mismatch");
|
|
66
|
+
}
|
|
67
|
+
function assertArchiveCompatibility(input, policy) {
|
|
68
|
+
const archive = validateArchive(input);
|
|
69
|
+
assertCompatibilityTags(archive.compatibility, policy);
|
|
70
|
+
return archive;
|
|
71
|
+
}
|
|
32
72
|
var canonical = (value) => {
|
|
33
73
|
if (Array.isArray(value))
|
|
34
74
|
return `[${value.map(canonical).join(",")}]`;
|
|
@@ -48,6 +88,8 @@ function validateArchive(value) {
|
|
|
48
88
|
const { sha256, ...content } = doc;
|
|
49
89
|
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))
|
|
50
90
|
throw new Error("unsupported or corrupt fleet archive");
|
|
91
|
+
if (doc.compatibility !== void 0)
|
|
92
|
+
validateCompatibilityTags(doc.compatibility);
|
|
51
93
|
for (const [namespace, entry] of Object.entries(doc.namespaces)) {
|
|
52
94
|
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)
|
|
53
95
|
throw new Error("invalid archive namespace");
|
|
@@ -63,6 +105,7 @@ function inspectArchive(input) {
|
|
|
63
105
|
format: archive.format,
|
|
64
106
|
createdAt: archive.createdAt,
|
|
65
107
|
sha256: archive.sha256,
|
|
108
|
+
...archive.compatibility ? { compatibility: archive.compatibility } : {},
|
|
66
109
|
namespaces: Object.fromEntries(Object.entries(archive.namespaces).map(([name, ns]) => [
|
|
67
110
|
name,
|
|
68
111
|
{
|
|
@@ -705,11 +748,28 @@ var ingressSupport = {
|
|
|
705
748
|
streaming: true,
|
|
706
749
|
signing: "vendor request signing is not used; webhook signatures remain payload based"
|
|
707
750
|
},
|
|
751
|
+
cognito: {
|
|
752
|
+
publicOrigin: true,
|
|
753
|
+
pathPrefix: true,
|
|
754
|
+
namespaces: "path-or-header",
|
|
755
|
+
streaming: true,
|
|
756
|
+
signing: "JWT issuer and JWKS use the configured public namespace; SigV4 verification is not modelled"
|
|
757
|
+
},
|
|
758
|
+
medplum: {
|
|
759
|
+
publicOrigin: true,
|
|
760
|
+
pathPrefix: true,
|
|
761
|
+
namespaces: "path-or-header",
|
|
762
|
+
streaming: true,
|
|
763
|
+
signing: "FHIR, OAuth and storage URLs use the configured public namespace"
|
|
764
|
+
},
|
|
708
765
|
other: {
|
|
709
766
|
publicOrigin: false,
|
|
710
767
|
reason: "host/path-sensitive signing and hosted URL rewriting are not certified; use a direct endpoint"
|
|
711
768
|
}
|
|
712
769
|
};
|
|
770
|
+
function supportsPublicIngress(service) {
|
|
771
|
+
return service === "stripe" || service === "cognito" || service === "medplum";
|
|
772
|
+
}
|
|
713
773
|
function advertisedHttpBase(entry) {
|
|
714
774
|
if (entry.publicPath !== void 0 && !entry.publicOrigin)
|
|
715
775
|
throw new Error("publicPath requires publicOrigin");
|
|
@@ -1248,7 +1308,7 @@ data: ${JSON.stringify(data)}
|
|
|
1248
1308
|
{
|
|
1249
1309
|
protocol: c.protocol,
|
|
1250
1310
|
coverage: c.coverage,
|
|
1251
|
-
ingress: c.targetName
|
|
1311
|
+
ingress: supportsPublicIngress(c.targetName ?? "") ? ingressSupport[c.targetName] : ingressSupport.other,
|
|
1252
1312
|
target: c.targetName,
|
|
1253
1313
|
outboundPolicy: c.outboundPolicy ?? "unsupported",
|
|
1254
1314
|
version: 1,
|
|
@@ -2332,11 +2392,12 @@ data: ${JSON.stringify(data)}
|
|
|
2332
2392
|
format: "mockingbird.fleet/v1",
|
|
2333
2393
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2334
2394
|
sourceId: this.ctx.id,
|
|
2395
|
+
...this.ctx.options.archiveCompatibility ? { compatibility: structuredClone(this.ctx.options.archiveCompatibility.tags) } : {},
|
|
2335
2396
|
namespaces: contents
|
|
2336
2397
|
});
|
|
2337
2398
|
}
|
|
2338
2399
|
async restoreArchive(input, selectedNamespace) {
|
|
2339
|
-
const archive =
|
|
2400
|
+
const archive = assertArchiveCompatibility(input, this.ctx.options.archiveCompatibility);
|
|
2340
2401
|
const entries = Object.entries(archive.namespaces).filter(([ns]) => selectedNamespace === void 0 || ns === selectedNamespace);
|
|
2341
2402
|
if (!entries.length)
|
|
2342
2403
|
throw new Error("selected namespace absent from archive");
|
|
@@ -2621,6 +2682,9 @@ var fleet_config_schema_default = {
|
|
|
2621
2682
|
adminControls: {
|
|
2622
2683
|
$ref: "#/$defs/controls"
|
|
2623
2684
|
},
|
|
2685
|
+
idBase: {
|
|
2686
|
+
$ref: "#/$defs/idBase"
|
|
2687
|
+
},
|
|
2624
2688
|
namespace: {
|
|
2625
2689
|
type: "string",
|
|
2626
2690
|
pattern: "^[A-Za-z0-9_.-]{1,64}$"
|
|
@@ -2710,6 +2774,12 @@ var fleet_config_schema_default = {
|
|
|
2710
2774
|
adminControls: {
|
|
2711
2775
|
$ref: "#/$defs/controls"
|
|
2712
2776
|
},
|
|
2777
|
+
idBase: {
|
|
2778
|
+
$ref: "#/$defs/idBase"
|
|
2779
|
+
},
|
|
2780
|
+
settings: {
|
|
2781
|
+
type: "object"
|
|
2782
|
+
},
|
|
2713
2783
|
fixtures: {
|
|
2714
2784
|
type: "object"
|
|
2715
2785
|
},
|
|
@@ -2756,6 +2826,18 @@ var fleet_config_schema_default = {
|
|
|
2756
2826
|
}
|
|
2757
2827
|
}
|
|
2758
2828
|
},
|
|
2829
|
+
idBase: {
|
|
2830
|
+
anyOf: [
|
|
2831
|
+
{
|
|
2832
|
+
type: "integer",
|
|
2833
|
+
minimum: 0
|
|
2834
|
+
},
|
|
2835
|
+
{
|
|
2836
|
+
type: "string",
|
|
2837
|
+
pattern: "^(boot|[0-9]+)$"
|
|
2838
|
+
}
|
|
2839
|
+
]
|
|
2840
|
+
},
|
|
2759
2841
|
controls: {
|
|
2760
2842
|
type: "object",
|
|
2761
2843
|
additionalProperties: false,
|
|
@@ -2905,6 +2987,8 @@ async function preflightFleet(config, options) {
|
|
|
2905
2987
|
throw new Error("protected archive policy requires a protected repository; configure its protector before startup");
|
|
2906
2988
|
resolveAdminPrefix(config.adminPrefix);
|
|
2907
2989
|
normalizeBootControls(config.adminControls);
|
|
2990
|
+
if (config.idBase !== void 0)
|
|
2991
|
+
normalizeIdBase(config.idBase, "idBase");
|
|
2908
2992
|
const targets = /* @__PURE__ */ new Map();
|
|
2909
2993
|
const ports = /* @__PURE__ */ new Set();
|
|
2910
2994
|
for (const [name, entry] of Object.entries(config.services)) {
|
|
@@ -2920,7 +3004,7 @@ async function preflightFleet(config, options) {
|
|
|
2920
3004
|
if (entry.target !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(entry.target))
|
|
2921
3005
|
throw new Error("target must name a supported service suffix");
|
|
2922
3006
|
const service = entry.target ?? name;
|
|
2923
|
-
if (advertisedHttpBase(entry) && service
|
|
3007
|
+
if (advertisedHttpBase(entry) && !supportsPublicIngress(service))
|
|
2924
3008
|
throw new Error(`public ingress unsupported for ${service}; use a direct endpoint to preserve signed targets`);
|
|
2925
3009
|
const target = await options.load(service);
|
|
2926
3010
|
const protocol = "protocol" in target ? target.protocol : "http";
|
|
@@ -2936,6 +3020,13 @@ async function preflightFleet(config, options) {
|
|
|
2936
3020
|
throw new Error("invalid protocol namespace selector");
|
|
2937
3021
|
}
|
|
2938
3022
|
}
|
|
3023
|
+
if (entry.idBase !== void 0)
|
|
3024
|
+
normalizeIdBase(entry.idBase, "idBase");
|
|
3025
|
+
if (entry.settings !== void 0) {
|
|
3026
|
+
if (protocol !== "http" || !("create" in target))
|
|
3027
|
+
throw new Error("settings: only HTTP services take boot settings");
|
|
3028
|
+
checkSettings(target, entry.settings, "settings");
|
|
3029
|
+
}
|
|
2939
3030
|
const port = entry.port ?? target.defaultPort;
|
|
2940
3031
|
if (port !== 0) {
|
|
2941
3032
|
const key = `${entry.host ?? "127.0.0.1"}:${port}`;
|
|
@@ -2971,7 +3062,7 @@ async function preflightFleet(config, options) {
|
|
|
2971
3062
|
break;
|
|
2972
3063
|
}
|
|
2973
3064
|
}
|
|
2974
|
-
targets.set(name, { ...target, packageVersion: packageVersion ?? "3.
|
|
3065
|
+
targets.set(name, { ...target, packageVersion: packageVersion ?? "3.7.0" });
|
|
2975
3066
|
} catch (error) {
|
|
2976
3067
|
throw new Error(`service ${name}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
2977
3068
|
}
|
|
@@ -3015,6 +3106,11 @@ async function preflightFleet(config, options) {
|
|
|
3015
3106
|
return ordered;
|
|
3016
3107
|
}
|
|
3017
3108
|
function validateFleetPolicies(options) {
|
|
3109
|
+
if (options.archiveCompatibility) {
|
|
3110
|
+
validateCompatibilityTags(options.archiveCompatibility.tags);
|
|
3111
|
+
if (options.archiveCompatibility.missing !== void 0 && !["allow", "reject"].includes(options.archiveCompatibility.missing))
|
|
3112
|
+
throw new Error("archiveCompatibility.missing must be allow or reject");
|
|
3113
|
+
}
|
|
3018
3114
|
if (options.journal && !options.repository)
|
|
3019
3115
|
throw new Error("durable operation journal requires an archive repository");
|
|
3020
3116
|
if (options.cors) {
|
|
@@ -3286,6 +3382,7 @@ var httpChild = async (target, entry, options, admission, generation, privateAcc
|
|
|
3286
3382
|
options.onLog?.(entry2);
|
|
3287
3383
|
},
|
|
3288
3384
|
...entry.adminControls !== void 0 ? { adminControls: entry.adminControls } : {},
|
|
3385
|
+
...entry.settings !== void 0 ? { settings: checkSettings(target, entry.settings, "settings") } : {},
|
|
3289
3386
|
...entry.fixtures !== void 0 ? { fixtures: entry.fixtures } : {},
|
|
3290
3387
|
...(advertisedHttpBase(entry) ?? entry.baseUrl) !== void 0 ? { baseUrl: advertisedHttpBase(entry) ?? entry.baseUrl } : {}
|
|
3291
3388
|
});
|
|
@@ -3304,6 +3401,8 @@ var httpChild = async (target, entry, options, admission, generation, privateAcc
|
|
|
3304
3401
|
].some((method) => typeof created[method] !== "function"))
|
|
3305
3402
|
throw new Error("HTTP target does not implement the fleet runtime protocol; build/install matching supported service versions");
|
|
3306
3403
|
const runtime = created;
|
|
3404
|
+
if (entry.idBase !== void 0)
|
|
3405
|
+
runtime.setIdBase?.(entry.idBase);
|
|
3307
3406
|
const unobserve = runtime.webhooks?.observeDeliveries(observer.delivery);
|
|
3308
3407
|
if (options.outbound && runtime.webhooks)
|
|
3309
3408
|
runtime.webhooks.setTransportPolicy(ownedTransport(options.outbound));
|
|
@@ -3902,6 +4001,7 @@ async function startFleet(config, options) {
|
|
|
3902
4001
|
...entry,
|
|
3903
4002
|
adminPrefix: resolveAdminPrefix(entry.adminPrefix ?? adminPrefix),
|
|
3904
4003
|
...adminKey !== void 0 ? { adminKey } : {},
|
|
4004
|
+
...(entry.idBase ?? config.idBase) !== void 0 ? { idBase: entry.idBase ?? config.idBase } : {},
|
|
3905
4005
|
// Fleet-wide controls, with the service's own keys replacing them.
|
|
3906
4006
|
...config.adminControls !== void 0 || entry.adminControls !== void 0 ? { adminControls: { ...config.adminControls, ...entry.adminControls } } : {}
|
|
3907
4007
|
}, options, (namespace, request) => management?.admit(namespace, request), (namespace) => management?.generation(namespace), (namespace, request) => management?.privateRequest(namespace, request) ?? false, {
|
|
@@ -4007,10 +4107,44 @@ async function startFleet(config, options) {
|
|
|
4007
4107
|
}
|
|
4008
4108
|
}
|
|
4009
4109
|
|
|
4010
|
-
// ../../adapters/node/dist/fleet-
|
|
4011
|
-
import { readFile as readFile4 } from "node:fs/promises";
|
|
4110
|
+
// ../../adapters/node/dist/fleet-loader.js
|
|
4012
4111
|
import { createRequire as createRequire2 } from "node:module";
|
|
4013
4112
|
import { resolve as resolve2 } from "node:path";
|
|
4113
|
+
import { pathToFileURL } from "node:url";
|
|
4114
|
+
var suffix = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4115
|
+
function createInstalledServiceLoader(options) {
|
|
4116
|
+
if (!options.projectRoot)
|
|
4117
|
+
throw new Error("consumer projectRoot required");
|
|
4118
|
+
const allowed = new Set(options.services);
|
|
4119
|
+
for (const name of allowed)
|
|
4120
|
+
if (!suffix.test(name))
|
|
4121
|
+
throw new Error("invalid service suffix");
|
|
4122
|
+
const require2 = createRequire2(resolve2(options.projectRoot, "package.json"));
|
|
4123
|
+
const targets = new Map((options.targets ?? []).map((target) => [target.name, target]));
|
|
4124
|
+
return async (name) => {
|
|
4125
|
+
if (!suffix.test(name) || !allowed.has(name))
|
|
4126
|
+
throw new Error("service is not declared in loader allowlist");
|
|
4127
|
+
const own = targets.get(name);
|
|
4128
|
+
if (own)
|
|
4129
|
+
return own;
|
|
4130
|
+
const specifier = `@crvouga/mockingbird-service-${name}/server`;
|
|
4131
|
+
let location;
|
|
4132
|
+
try {
|
|
4133
|
+
location = require2.resolve(specifier);
|
|
4134
|
+
} catch {
|
|
4135
|
+
throw new Error(`cannot load service "${name}": install @crvouga/mockingbird-service-${name} in the consumer project; its /server export is required`);
|
|
4136
|
+
}
|
|
4137
|
+
const mod = await import(pathToFileURL(location).href);
|
|
4138
|
+
if (!mod.serveTarget || mod.serveTarget.name !== name || ("protocol" in mod.serveTarget ? typeof mod.serveTarget.start !== "function" : typeof mod.serveTarget.create !== "function"))
|
|
4139
|
+
throw new Error(`${specifier} exports no matching serveTarget`);
|
|
4140
|
+
return mod.serveTarget;
|
|
4141
|
+
};
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
// ../../adapters/node/dist/fleet-tools.js
|
|
4145
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
4146
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
4147
|
+
import { resolve as resolve3 } from "node:path";
|
|
4014
4148
|
|
|
4015
4149
|
// ../../adapters/node/dist/fleet-client.js
|
|
4016
4150
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
@@ -4024,6 +4158,14 @@ var FleetClientError = class extends Error {
|
|
|
4024
4158
|
this.details = details;
|
|
4025
4159
|
}
|
|
4026
4160
|
};
|
|
4161
|
+
var FleetClientResponseError = class extends FleetClientError {
|
|
4162
|
+
code;
|
|
4163
|
+
constructor(code, status, origin) {
|
|
4164
|
+
super(status, { code, body: "omitted", ...origin ? { origin } : {} });
|
|
4165
|
+
this.code = code;
|
|
4166
|
+
this.name = "FleetClientResponseError";
|
|
4167
|
+
}
|
|
4168
|
+
};
|
|
4027
4169
|
var FleetClient = class {
|
|
4028
4170
|
base;
|
|
4029
4171
|
options;
|
|
@@ -4036,7 +4178,14 @@ var FleetClient = class {
|
|
|
4036
4178
|
if (url.username || url.password)
|
|
4037
4179
|
throw new Error("fleet client URL must not contain credentials");
|
|
4038
4180
|
url.searchParams.set("namespace", options.namespace ?? this.options.namespace ?? "default");
|
|
4181
|
+
const limit = options.maxResponseBytes ?? this.options.maxResponseBytes ?? 64 * 1024 * 1024;
|
|
4182
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
4183
|
+
throw new Error("invalid response byte limit");
|
|
4184
|
+
const deadline = AbortSignal.timeout(this.options.timeoutMs ?? 3e4);
|
|
4185
|
+
const signal = options.signal ? AbortSignal.any([options.signal, deadline]) : deadline;
|
|
4186
|
+
signal.throwIfAborted();
|
|
4039
4187
|
const response = await (this.options.fetch ?? fetch)(url, {
|
|
4188
|
+
redirect: "manual",
|
|
4040
4189
|
method: options.method ?? (options.body === void 0 ? "GET" : "POST"),
|
|
4041
4190
|
headers: {
|
|
4042
4191
|
"content-type": "application/json",
|
|
@@ -4044,11 +4193,71 @@ var FleetClient = class {
|
|
|
4044
4193
|
...options.idempotencyKey ? { "idempotency-key": options.idempotencyKey } : {}
|
|
4045
4194
|
},
|
|
4046
4195
|
...options.body !== void 0 ? { body: JSON.stringify(options.body) } : {},
|
|
4047
|
-
signal
|
|
4196
|
+
signal
|
|
4048
4197
|
});
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
throw new
|
|
4198
|
+
if (response.status >= 300 && response.status < 400) {
|
|
4199
|
+
await response.body?.cancel();
|
|
4200
|
+
throw new FleetClientResponseError("redirect", response.status, url.origin);
|
|
4201
|
+
}
|
|
4202
|
+
if (Number(response.headers.get("content-length")) > limit) {
|
|
4203
|
+
await response.body?.cancel();
|
|
4204
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4205
|
+
}
|
|
4206
|
+
const reader = response.body?.getReader();
|
|
4207
|
+
const chunks = [];
|
|
4208
|
+
let size = 0;
|
|
4209
|
+
const abort = () => {
|
|
4210
|
+
void reader?.cancel(signal.reason).catch(() => {
|
|
4211
|
+
});
|
|
4212
|
+
};
|
|
4213
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
4214
|
+
try {
|
|
4215
|
+
if (reader)
|
|
4216
|
+
while (true) {
|
|
4217
|
+
signal.throwIfAborted();
|
|
4218
|
+
const { done, value } = await reader.read();
|
|
4219
|
+
signal.throwIfAborted();
|
|
4220
|
+
if (done)
|
|
4221
|
+
break;
|
|
4222
|
+
size += value.byteLength;
|
|
4223
|
+
if (size > limit) {
|
|
4224
|
+
await reader.cancel();
|
|
4225
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4226
|
+
}
|
|
4227
|
+
chunks.push(value);
|
|
4228
|
+
}
|
|
4229
|
+
} finally {
|
|
4230
|
+
signal.removeEventListener("abort", abort);
|
|
4231
|
+
if (signal.aborted)
|
|
4232
|
+
await reader?.cancel(signal.reason).catch(() => {
|
|
4233
|
+
});
|
|
4234
|
+
reader?.releaseLock();
|
|
4235
|
+
}
|
|
4236
|
+
const bytes = new Uint8Array(size);
|
|
4237
|
+
let offset = 0;
|
|
4238
|
+
for (const chunk of chunks) {
|
|
4239
|
+
bytes.set(chunk, offset);
|
|
4240
|
+
offset += chunk.byteLength;
|
|
4241
|
+
}
|
|
4242
|
+
const text2 = new TextDecoder().decode(bytes);
|
|
4243
|
+
let data;
|
|
4244
|
+
try {
|
|
4245
|
+
data = text2.length ? JSON.parse(text2) : void 0;
|
|
4246
|
+
} catch {
|
|
4247
|
+
if (response.ok)
|
|
4248
|
+
throw new FleetClientResponseError("invalid_json", response.status);
|
|
4249
|
+
}
|
|
4250
|
+
if (!response.ok) {
|
|
4251
|
+
const error = data && typeof data === "object" ? data.error : void 0;
|
|
4252
|
+
const detail = { body: "omitted" };
|
|
4253
|
+
if (error && typeof error === "object")
|
|
4254
|
+
for (const key of ["type", "code"]) {
|
|
4255
|
+
const value = error[key];
|
|
4256
|
+
if (typeof value === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(value))
|
|
4257
|
+
detail[key] = value;
|
|
4258
|
+
}
|
|
4259
|
+
throw new FleetClientError(response.status, detail);
|
|
4260
|
+
}
|
|
4052
4261
|
return data;
|
|
4053
4262
|
}
|
|
4054
4263
|
discover() {
|
|
@@ -4114,17 +4323,52 @@ function renderConnections(manifest, privateManifest, namespace, mapping) {
|
|
|
4114
4323
|
const child = manifest.services[entry.service], secret = privateManifest.services[entry.service];
|
|
4115
4324
|
if (!child || !secret)
|
|
4116
4325
|
throw new Error(`missing service mapping ${entry.service}`);
|
|
4326
|
+
let endpoint;
|
|
4117
4327
|
if (child.protocol === "http") {
|
|
4118
4328
|
const template = child.namespaces.path;
|
|
4119
4329
|
if (typeof template !== "string")
|
|
4120
4330
|
throw new Error(`missing HTTP namespace mapping ${entry.service}`);
|
|
4121
|
-
|
|
4331
|
+
endpoint = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
|
|
4122
4332
|
} else {
|
|
4123
|
-
const
|
|
4124
|
-
if (!
|
|
4333
|
+
const selected = secret.namespaces?.[namespace];
|
|
4334
|
+
if (!selected)
|
|
4125
4335
|
throw new Error(`missing namespace mapping ${namespace}/${entry.service}`);
|
|
4126
|
-
|
|
4336
|
+
endpoint = selected;
|
|
4127
4337
|
}
|
|
4338
|
+
const url = new URL(endpoint);
|
|
4339
|
+
const field = entry.field ?? "url";
|
|
4340
|
+
let value;
|
|
4341
|
+
switch (field) {
|
|
4342
|
+
case "url":
|
|
4343
|
+
value = endpoint;
|
|
4344
|
+
break;
|
|
4345
|
+
case "hostname":
|
|
4346
|
+
value = url.hostname.replace(/^\[|\]$/g, "");
|
|
4347
|
+
break;
|
|
4348
|
+
case "port":
|
|
4349
|
+
value = url.port;
|
|
4350
|
+
break;
|
|
4351
|
+
case "username":
|
|
4352
|
+
value = decodeURIComponent(url.username);
|
|
4353
|
+
break;
|
|
4354
|
+
case "password":
|
|
4355
|
+
value = decodeURIComponent(url.password);
|
|
4356
|
+
break;
|
|
4357
|
+
case "pathname":
|
|
4358
|
+
value = decodeURIComponent(url.pathname);
|
|
4359
|
+
break;
|
|
4360
|
+
case "database":
|
|
4361
|
+
value = decodeURIComponent(url.pathname.replace(/^\//, ""));
|
|
4362
|
+
break;
|
|
4363
|
+
default:
|
|
4364
|
+
throw new Error("unsupported connection field");
|
|
4365
|
+
}
|
|
4366
|
+
if (!value) {
|
|
4367
|
+
if (typeof entry.fallback !== "string")
|
|
4368
|
+
throw new Error(`missing connection component ${field}`);
|
|
4369
|
+
value = entry.fallback;
|
|
4370
|
+
}
|
|
4371
|
+
result[variable] = value;
|
|
4128
4372
|
}
|
|
4129
4373
|
return result;
|
|
4130
4374
|
}
|
|
@@ -4148,7 +4392,7 @@ async function doctorFleet(config, options, probes = []) {
|
|
|
4148
4392
|
const plan = [];
|
|
4149
4393
|
try {
|
|
4150
4394
|
const targets = await preflightFleet(config, options);
|
|
4151
|
-
const require2 =
|
|
4395
|
+
const require2 = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
4152
4396
|
for (const [service, target] of targets) {
|
|
4153
4397
|
let version = "development";
|
|
4154
4398
|
try {
|
|
@@ -4203,7 +4447,7 @@ async function doctorFleet(config, options, probes = []) {
|
|
|
4203
4447
|
};
|
|
4204
4448
|
}
|
|
4205
4449
|
async function rehearseFleet(config, options, input, probes = [], timeoutMs = 3e4) {
|
|
4206
|
-
const archive =
|
|
4450
|
+
const archive = assertArchiveCompatibility(input, options.archiveCompatibility);
|
|
4207
4451
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4208
4452
|
const isolated = {
|
|
4209
4453
|
...config,
|
|
@@ -4215,7 +4459,7 @@ async function rehearseFleet(config, options, input, probes = [], timeoutMs = 3e
|
|
|
4215
4459
|
};
|
|
4216
4460
|
let fleet;
|
|
4217
4461
|
try {
|
|
4218
|
-
fleet = await startFleet(isolated,
|
|
4462
|
+
fleet = await startFleet(isolated, options);
|
|
4219
4463
|
const client = new FleetClient(fleet.manifest.adminBase, {
|
|
4220
4464
|
...config.adminKey ? { adminKey: config.adminKey } : {}
|
|
4221
4465
|
});
|
|
@@ -4442,6 +4686,16 @@ var COMMON_SERVE_OPTIONS = {
|
|
|
4442
4686
|
value: "<seed>",
|
|
4443
4687
|
description: "Seed for every random choice (env MOCKINGBIRD_SEED)"
|
|
4444
4688
|
},
|
|
4689
|
+
"id-base": {
|
|
4690
|
+
type: "string",
|
|
4691
|
+
value: "<n|boot>",
|
|
4692
|
+
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)"
|
|
4693
|
+
},
|
|
4694
|
+
settings: {
|
|
4695
|
+
type: "string",
|
|
4696
|
+
value: "<json|file>",
|
|
4697
|
+
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)"
|
|
4698
|
+
},
|
|
4445
4699
|
"admin-controls": {
|
|
4446
4700
|
type: "string",
|
|
4447
4701
|
value: "<json|file>",
|
|
@@ -4536,19 +4790,40 @@ var readJsonFile = async (path, label) => {
|
|
|
4536
4790
|
}
|
|
4537
4791
|
};
|
|
4538
4792
|
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4793
|
+
var readJsonOption = async (source, label) => {
|
|
4794
|
+
const trimmed = source.trim();
|
|
4795
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
4796
|
+
try {
|
|
4797
|
+
return JSON.parse(trimmed);
|
|
4798
|
+
} catch {
|
|
4799
|
+
throw new Error(`${label}: not valid JSON`);
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4802
|
+
return readJsonFile(source, label);
|
|
4803
|
+
};
|
|
4804
|
+
var resolveServeIdBase = (values, env = process.env) => {
|
|
4805
|
+
const source = asString(values["id-base"]) ?? env.MOCKINGBIRD_ID_BASE;
|
|
4806
|
+
if (source === void 0 || source.trim() === "")
|
|
4807
|
+
return void 0;
|
|
4808
|
+
normalizeIdBase(source.trim(), "--id-base");
|
|
4809
|
+
return source.trim();
|
|
4810
|
+
};
|
|
4811
|
+
var resolveServeSettings = async (target, values, env = process.env) => {
|
|
4812
|
+
const flag = asString(values.settings);
|
|
4813
|
+
const source = flag ?? env.MOCKINGBIRD_SETTINGS;
|
|
4814
|
+
if (source === void 0 || source.trim() === "")
|
|
4815
|
+
return void 0;
|
|
4816
|
+
const label = flag !== void 0 ? "--settings" : "MOCKINGBIRD_SETTINGS";
|
|
4817
|
+
const parsed = await readJsonOption(source, label);
|
|
4818
|
+
if (!isObject2(parsed))
|
|
4819
|
+
throw new Error(`${label}: expected a JSON object`);
|
|
4820
|
+
return checkSettings(target, parsed, label);
|
|
4821
|
+
};
|
|
4539
4822
|
var resolveServeControls = async (values, env = process.env, base) => {
|
|
4540
4823
|
const source = asString(values["admin-controls"]) ?? env.MOCKINGBIRD_ADMIN_CONTROLS;
|
|
4541
4824
|
let document = isObject2(base) ? { ...base } : {};
|
|
4542
4825
|
if (source !== void 0 && source.trim() !== "") {
|
|
4543
|
-
|
|
4544
|
-
if (source.trim().startsWith("{")) {
|
|
4545
|
-
try {
|
|
4546
|
-
parsed = JSON.parse(source);
|
|
4547
|
-
} catch {
|
|
4548
|
-
throw new Error("--admin-controls: not valid JSON");
|
|
4549
|
-
}
|
|
4550
|
-
} else
|
|
4551
|
-
parsed = await readJsonFile(source, "--admin-controls");
|
|
4826
|
+
const parsed = source.trim().startsWith("{") ? await readJsonOption(source, "--admin-controls") : await readJsonFile(source, "--admin-controls");
|
|
4552
4827
|
if (!isObject2(parsed))
|
|
4553
4828
|
throw new Error("--admin-controls: expected a JSON object");
|
|
4554
4829
|
document = { ...document, ...parsed };
|
|
@@ -4590,26 +4865,7 @@ var resolveServeControls = async (values, env = process.env, base) => {
|
|
|
4590
4865
|
normalizeBootControls(document, "adminControls");
|
|
4591
4866
|
return document;
|
|
4592
4867
|
};
|
|
4593
|
-
var loadTarget =
|
|
4594
|
-
if (name === own.name)
|
|
4595
|
-
return own;
|
|
4596
|
-
const specifier = `@crvouga/mockingbird-service-${name}/server`;
|
|
4597
|
-
try {
|
|
4598
|
-
let mod;
|
|
4599
|
-
try {
|
|
4600
|
-
mod = await import(specifier);
|
|
4601
|
-
} catch {
|
|
4602
|
-
const fromProject = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
4603
|
-
mod = await import(pathToFileURL(fromProject.resolve(specifier)).href);
|
|
4604
|
-
}
|
|
4605
|
-
if (!mod.serveTarget)
|
|
4606
|
-
throw new Error(`${specifier} exports no serveTarget`);
|
|
4607
|
-
return mod.serveTarget;
|
|
4608
|
-
} catch (error) {
|
|
4609
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
4610
|
-
throw new Error(`cannot load service "${name}": ${reason}. Install @crvouga/mockingbird-service-${name}.`);
|
|
4611
|
-
}
|
|
4612
|
-
};
|
|
4868
|
+
var loadTarget = (name, own) => createInstalledServiceLoader({ projectRoot: process.cwd(), services: [name], targets: [own] })(name);
|
|
4613
4869
|
var start = async (target, values, config) => {
|
|
4614
4870
|
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
4615
4871
|
const runtime = await target.create(values, {
|
|
@@ -4617,8 +4873,11 @@ var start = async (target, values, config) => {
|
|
|
4617
4873
|
adminKey: config.adminKey,
|
|
4618
4874
|
seed: config.seed,
|
|
4619
4875
|
onLog: formatLog(config.log),
|
|
4876
|
+
...config.settings !== void 0 ? { settings: config.settings } : {},
|
|
4620
4877
|
...config.adminControls !== void 0 ? { adminControls: config.adminControls } : {}
|
|
4621
4878
|
});
|
|
4879
|
+
if (config.idBase !== void 0)
|
|
4880
|
+
runtime.setIdBase?.(config.idBase);
|
|
4622
4881
|
const listening = await listen(runtime, { port: config.port, host: config.host });
|
|
4623
4882
|
target.listening?.(listening);
|
|
4624
4883
|
console.log(`${target.name} emulator listening on ${listening.url}`);
|
|
@@ -4664,6 +4923,11 @@ var serveCommand = (target) => ({
|
|
|
4664
4923
|
const adminControls = await resolveServeControls(values, process.env, config.adminControls);
|
|
4665
4924
|
if (adminControls !== void 0)
|
|
4666
4925
|
config.adminControls = adminControls;
|
|
4926
|
+
if (values.settings !== void 0)
|
|
4927
|
+
throw new Error("--settings serves a single service; give each service its own `settings` in the config");
|
|
4928
|
+
const idBase = config.idBase ?? resolveServeIdBase(values);
|
|
4929
|
+
if (idBase !== void 0)
|
|
4930
|
+
config.idBase = idBase;
|
|
4667
4931
|
const fleet = await startFleet(config, {
|
|
4668
4932
|
load: (name) => loadTarget(name, target),
|
|
4669
4933
|
onLog: formatLog(config.log ?? log),
|
|
@@ -4693,8 +4957,12 @@ var serveCommand = (target) => ({
|
|
|
4693
4957
|
let listening;
|
|
4694
4958
|
try {
|
|
4695
4959
|
const adminControls = await resolveServeControls(values);
|
|
4960
|
+
const idBase = resolveServeIdBase(values);
|
|
4961
|
+
const settings = await resolveServeSettings(target, values);
|
|
4696
4962
|
listening = await start(target, values, {
|
|
4697
4963
|
...adminControls !== void 0 ? { adminControls } : {},
|
|
4964
|
+
...idBase !== void 0 ? { idBase } : {},
|
|
4965
|
+
...settings !== void 0 ? { settings } : {},
|
|
4698
4966
|
adminPrefix: resolveAdminPrefix(asString(values["admin-prefix"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX),
|
|
4699
4967
|
port: port === void 0 ? target.defaultPort : Number.parseInt(port, 10),
|
|
4700
4968
|
host: asString(values.host) ?? "127.0.0.1",
|
|
@@ -4710,6 +4978,84 @@ var serveCommand = (target) => ({
|
|
|
4710
4978
|
}
|
|
4711
4979
|
});
|
|
4712
4980
|
|
|
4981
|
+
// src/boot.ts
|
|
4982
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4983
|
+
var strings = (value, where) => {
|
|
4984
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string"))
|
|
4985
|
+
throw new Error(`${where} must be an array of strings`);
|
|
4986
|
+
return value;
|
|
4987
|
+
};
|
|
4988
|
+
var KEYS = [
|
|
4989
|
+
"workspaces",
|
|
4990
|
+
"legacyEnvironmentIds",
|
|
4991
|
+
"apiKeys",
|
|
4992
|
+
"webhookId",
|
|
4993
|
+
"contactsEnabled",
|
|
4994
|
+
"validation"
|
|
4995
|
+
];
|
|
4996
|
+
var parseBootSettings = (input) => {
|
|
4997
|
+
for (const key of Object.keys(input))
|
|
4998
|
+
if (!KEYS.includes(key)) throw new Error(`unknown setting ${JSON.stringify(key)}`);
|
|
4999
|
+
const out = {};
|
|
5000
|
+
if (input.workspaces !== void 0) out.workspaces = strings(input.workspaces, "workspaces");
|
|
5001
|
+
if (input.legacyEnvironmentIds !== void 0) {
|
|
5002
|
+
const aliases = input.legacyEnvironmentIds;
|
|
5003
|
+
if (!isRecord(aliases) || Object.values(aliases).some((id) => typeof id !== "string"))
|
|
5004
|
+
throw new Error("legacyEnvironmentIds must be an object of workspace ids by environment id");
|
|
5005
|
+
out.legacyEnvironmentIds = aliases;
|
|
5006
|
+
}
|
|
5007
|
+
if (input.apiKeys !== void 0) out.apiKeys = strings(input.apiKeys, "apiKeys");
|
|
5008
|
+
if (input.webhookId !== void 0) {
|
|
5009
|
+
if (typeof input.webhookId !== "string") throw new Error("webhookId must be a string");
|
|
5010
|
+
out.webhookId = input.webhookId;
|
|
5011
|
+
}
|
|
5012
|
+
if (input.contactsEnabled !== void 0) {
|
|
5013
|
+
if (typeof input.contactsEnabled !== "boolean")
|
|
5014
|
+
throw new Error("contactsEnabled must be a boolean");
|
|
5015
|
+
out.contactsEnabled = input.contactsEnabled;
|
|
5016
|
+
}
|
|
5017
|
+
if (input.validation !== void 0) {
|
|
5018
|
+
if (input.validation !== "present-only" && input.validation !== "finished-validates-all")
|
|
5019
|
+
throw new Error('validation must be "present-only" or "finished-validates-all"');
|
|
5020
|
+
out.validation = input.validation;
|
|
5021
|
+
}
|
|
5022
|
+
return out;
|
|
5023
|
+
};
|
|
5024
|
+
var parseSurveysDocument = (input, legacyEnvironmentIds = {}) => {
|
|
5025
|
+
const list = Array.isArray(input) ? input : isRecord(input) ? input.surveys : void 0;
|
|
5026
|
+
if (!Array.isArray(list)) throw new Error("expected [survey] or {surveys: [survey]}");
|
|
5027
|
+
return list.map((entry, index) => {
|
|
5028
|
+
const where = `surveys[${index}]`;
|
|
5029
|
+
if (!isRecord(entry)) throw new Error(`${where} must be an object`);
|
|
5030
|
+
if (typeof entry.id !== "string" || entry.id === "")
|
|
5031
|
+
throw new Error(`${where}.id must be a non-empty string`);
|
|
5032
|
+
if (typeof entry.name !== "string") throw new Error(`${where}.name must be a string`);
|
|
5033
|
+
const { environmentId, ...rest } = entry;
|
|
5034
|
+
for (const key of ["workspaceId", "environmentId", "type", "status"])
|
|
5035
|
+
if (entry[key] !== void 0 && entry[key] !== null && typeof entry[key] !== "string")
|
|
5036
|
+
throw new Error(`${where}.${key} must be a string`);
|
|
5037
|
+
const owner = entry.workspaceId ?? environmentId;
|
|
5038
|
+
return {
|
|
5039
|
+
...rest,
|
|
5040
|
+
id: entry.id,
|
|
5041
|
+
name: entry.name,
|
|
5042
|
+
type: entry.type ?? "app",
|
|
5043
|
+
status: entry.status ?? "inProgress",
|
|
5044
|
+
workspaceId: owner ? legacyEnvironmentIds[owner] ?? owner : null
|
|
5045
|
+
};
|
|
5046
|
+
});
|
|
5047
|
+
};
|
|
5048
|
+
var appendSurveys = (base, extra) => {
|
|
5049
|
+
const seen = new Set(base.map((survey) => survey.id));
|
|
5050
|
+
const out = [...base];
|
|
5051
|
+
for (const survey of extra) {
|
|
5052
|
+
if (seen.has(survey.id)) continue;
|
|
5053
|
+
seen.add(survey.id);
|
|
5054
|
+
out.push(survey);
|
|
5055
|
+
}
|
|
5056
|
+
return out;
|
|
5057
|
+
};
|
|
5058
|
+
|
|
4713
5059
|
// src/server.ts
|
|
4714
5060
|
var DEFAULT_PORT = 8813;
|
|
4715
5061
|
var createServer2 = async (options = {}) => {
|
|
@@ -4722,9 +5068,24 @@ var createServer2 = async (options = {}) => {
|
|
|
4722
5068
|
return { ...listening, runtime };
|
|
4723
5069
|
};
|
|
4724
5070
|
var text = (value) => typeof value === "string" ? value : void 0;
|
|
5071
|
+
var loadSurveysFile = (path, mode = "append", legacyEnvironmentIds = DEFAULT_SETTINGS.legacyEnvironmentIds) => {
|
|
5072
|
+
let raw;
|
|
5073
|
+
try {
|
|
5074
|
+
raw = readFileSync(path, "utf8");
|
|
5075
|
+
} catch {
|
|
5076
|
+
throw new Error(`formbricks surveys not found: ${path}`);
|
|
5077
|
+
}
|
|
5078
|
+
try {
|
|
5079
|
+
const surveys = parseSurveysDocument(JSON.parse(raw), legacyEnvironmentIds);
|
|
5080
|
+
return appendSurveys(mode === "replace" ? [] : CORPUS_SURVEYS, surveys);
|
|
5081
|
+
} catch (error) {
|
|
5082
|
+
throw new Error(`formbricks surveys ${path}: ${error.message}`);
|
|
5083
|
+
}
|
|
5084
|
+
};
|
|
4725
5085
|
var serveTarget = {
|
|
4726
5086
|
name: "formbricks",
|
|
4727
5087
|
defaultPort: DEFAULT_PORT,
|
|
5088
|
+
parseSettings: (settings) => parseBootSettings(settings),
|
|
4728
5089
|
options: {
|
|
4729
5090
|
"webhook-url": {
|
|
4730
5091
|
type: "string",
|
|
@@ -4745,6 +5106,16 @@ var serveTarget = {
|
|
|
4745
5106
|
type: "string",
|
|
4746
5107
|
value: "<id>",
|
|
4747
5108
|
description: "An extra workspace id that serves the survey corpus"
|
|
5109
|
+
},
|
|
5110
|
+
surveys: {
|
|
5111
|
+
type: "string",
|
|
5112
|
+
value: "<file.json>",
|
|
5113
|
+
description: "Surveys every namespace starts with, as a list or {surveys: [...]}, added after the corpus surveys (a repeated id is skipped)"
|
|
5114
|
+
},
|
|
5115
|
+
"surveys-mode": {
|
|
5116
|
+
type: "string",
|
|
5117
|
+
value: "<append|replace>",
|
|
5118
|
+
description: "With --surveys: add to the corpus (default) or use the file as the whole corpus"
|
|
4748
5119
|
}
|
|
4749
5120
|
},
|
|
4750
5121
|
create: (values, common) => {
|
|
@@ -4752,10 +5123,28 @@ var serveTarget = {
|
|
|
4752
5123
|
const token = text(values["webhook-token"]);
|
|
4753
5124
|
const secret = text(values["webhook-secret"]);
|
|
4754
5125
|
const workspace = text(values["workspace-id"]);
|
|
5126
|
+
const surveysPath = text(values.surveys);
|
|
5127
|
+
const mode = text(values["surveys-mode"]);
|
|
5128
|
+
if (mode !== void 0 && mode !== "append" && mode !== "replace")
|
|
5129
|
+
throw new Error('--surveys-mode must be "append" or "replace"');
|
|
5130
|
+
if (mode !== void 0 && surveysPath === void 0)
|
|
5131
|
+
throw new Error("--surveys-mode needs --surveys");
|
|
5132
|
+
const boot = common.settings;
|
|
5133
|
+
const settings = {
|
|
5134
|
+
...boot,
|
|
5135
|
+
...workspace ? { workspaces: [workspace, ...boot?.workspaces ?? DEFAULT_SETTINGS.workspaces] } : {}
|
|
5136
|
+
};
|
|
4755
5137
|
const target = url && token ? `${url}${url.includes("?") ? "&" : "?"}token=${encodeURIComponent(token)}` : url;
|
|
4756
5138
|
return createRuntime({
|
|
4757
5139
|
...target ? { webhooks: { url: target, ...secret ? { secret } : {} } } : {},
|
|
4758
|
-
...
|
|
5140
|
+
...Object.keys(settings).length > 0 ? { settings } : {},
|
|
5141
|
+
...surveysPath ? {
|
|
5142
|
+
surveys: loadSurveysFile(
|
|
5143
|
+
surveysPath,
|
|
5144
|
+
mode,
|
|
5145
|
+
settings.legacyEnvironmentIds ?? DEFAULT_SETTINGS.legacyEnvironmentIds
|
|
5146
|
+
)
|
|
5147
|
+
} : {},
|
|
4759
5148
|
...common.adminPrefix !== void 0 ? { adminPrefix: common.adminPrefix } : {},
|
|
4760
5149
|
...common.adminKey !== void 0 ? { adminKey: common.adminKey } : {},
|
|
4761
5150
|
...common.adminControls !== void 0 ? { adminControls: common.adminControls } : {},
|
|
@@ -4774,6 +5163,7 @@ export {
|
|
|
4774
5163
|
serveCommand,
|
|
4775
5164
|
DEFAULT_PORT,
|
|
4776
5165
|
createServer2 as createServer,
|
|
5166
|
+
loadSurveysFile,
|
|
4777
5167
|
serveTarget
|
|
4778
5168
|
};
|
|
4779
|
-
//# sourceMappingURL=chunk-
|
|
5169
|
+
//# sourceMappingURL=chunk-M3VADEIL.js.map
|