@crvouga/mockingbird-service-slack 3.1.0 → 3.3.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/API_EVIDENCE.md +3 -0
- package/CHANGELOG.md +14 -2
- package/DISCOVERY.md +23 -0
- package/LICENSE_EMULATE +202 -0
- package/README.md +17 -17
- package/SUPPORT.md +56 -2
- package/THIRD_PARTY_NOTICES.md +39 -0
- package/dist/chunk-6MIIKZZB.js +12637 -0
- package/dist/chunk-6MIIKZZB.js.map +7 -0
- package/dist/chunk-6Z2MR3PO.js +97 -0
- package/dist/chunk-6Z2MR3PO.js.map +7 -0
- package/dist/{chunk-AJMQBCFN.js → chunk-ZFHCM6E3.js} +191 -26
- package/dist/chunk-ZFHCM6E3.js.map +7 -0
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/crypto-II2ETGQQ.js +21 -0
- package/dist/crypto-II2ETGQQ.js.map +7 -0
- package/dist/helpers-5D4ROPWG.js +86 -0
- package/dist/helpers-5D4ROPWG.js.map +7 -0
- package/dist/index.d.ts +579 -92
- package/dist/index.js +2 -1
- package/dist/server.d.ts +998 -194
- package/dist/server.js +3 -2
- package/openapi.yaml +4081 -1945
- package/package.json +15 -5
- package/routes.json +72 -0
- package/dist/chunk-A2QC6SAR.js +0 -4177
- package/dist/chunk-A2QC6SAR.js.map +0 -7
- package/dist/chunk-AJMQBCFN.js.map +0 -7
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// ../../http/provider/dist/vendor/core/crypto.js
|
|
2
|
+
import { hmac } from "@noble/hashes/hmac.js";
|
|
3
|
+
import { sha1 } from "@noble/hashes/legacy.js";
|
|
4
|
+
import { md5 } from "@noble/hashes/legacy.js";
|
|
5
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
6
|
+
import { Buffer } from "buffer";
|
|
7
|
+
var digest = (algorithm) => {
|
|
8
|
+
if (algorithm === "sha256")
|
|
9
|
+
return sha256;
|
|
10
|
+
if (algorithm === "sha1")
|
|
11
|
+
return sha1;
|
|
12
|
+
if (algorithm === "md5")
|
|
13
|
+
return md5;
|
|
14
|
+
throw new Error(`Unsupported digest ${algorithm}`);
|
|
15
|
+
};
|
|
16
|
+
var bytes = (input) => typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
17
|
+
function createHash(algorithm) {
|
|
18
|
+
const parts = [];
|
|
19
|
+
const hash = {
|
|
20
|
+
update(input) {
|
|
21
|
+
parts.push(bytes(input));
|
|
22
|
+
return hash;
|
|
23
|
+
},
|
|
24
|
+
digest(encoding) {
|
|
25
|
+
const result = Buffer.from(digest(algorithm)(Buffer.concat(parts)));
|
|
26
|
+
return encoding === "base64url" ? result.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "") : encoding ? result.toString(encoding) : result;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return hash;
|
|
30
|
+
}
|
|
31
|
+
function createHmac(algorithm, key) {
|
|
32
|
+
const parts = [];
|
|
33
|
+
const hash = {
|
|
34
|
+
update(input) {
|
|
35
|
+
parts.push(bytes(input));
|
|
36
|
+
return hash;
|
|
37
|
+
},
|
|
38
|
+
digest(encoding) {
|
|
39
|
+
const result = Buffer.from(hmac(digest(algorithm), bytes(key), Buffer.concat(parts)));
|
|
40
|
+
return encoding === "base64url" ? result.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "") : encoding ? result.toString(encoding) : result;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
return hash;
|
|
44
|
+
}
|
|
45
|
+
var source;
|
|
46
|
+
function useRandom(next) {
|
|
47
|
+
source = next;
|
|
48
|
+
}
|
|
49
|
+
function withRandom(next, run) {
|
|
50
|
+
const previous = source;
|
|
51
|
+
source = next;
|
|
52
|
+
try {
|
|
53
|
+
return run();
|
|
54
|
+
} finally {
|
|
55
|
+
source = previous;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function random() {
|
|
59
|
+
return source ? source() : Math.random();
|
|
60
|
+
}
|
|
61
|
+
function randomBytes(length) {
|
|
62
|
+
if (!source)
|
|
63
|
+
return Buffer.from(crypto.getRandomValues(new Uint8Array(length)));
|
|
64
|
+
const out = new Uint8Array(length);
|
|
65
|
+
for (let i = 0; i < length; i++)
|
|
66
|
+
out[i] = Math.floor(source() * 256);
|
|
67
|
+
return Buffer.from(out);
|
|
68
|
+
}
|
|
69
|
+
function randomUUID() {
|
|
70
|
+
if (!source)
|
|
71
|
+
return crypto.randomUUID();
|
|
72
|
+
const b = randomBytes(16);
|
|
73
|
+
b[6] = b[6] & 15 | 64;
|
|
74
|
+
b[8] = b[8] & 63 | 128;
|
|
75
|
+
const hex = b.toString("hex");
|
|
76
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
77
|
+
}
|
|
78
|
+
function timingSafeEqual(a, b) {
|
|
79
|
+
if (a.length !== b.length)
|
|
80
|
+
throw new Error("Buffers must have equal lengths");
|
|
81
|
+
let difference = 0;
|
|
82
|
+
for (let i = 0; i < a.length; i++)
|
|
83
|
+
difference |= a[i] ^ b[i];
|
|
84
|
+
return difference === 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export {
|
|
88
|
+
createHash,
|
|
89
|
+
createHmac,
|
|
90
|
+
useRandom,
|
|
91
|
+
withRandom,
|
|
92
|
+
random,
|
|
93
|
+
randomBytes,
|
|
94
|
+
randomUUID,
|
|
95
|
+
timingSafeEqual
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=chunk-6Z2MR3PO.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../http/provider/src/vendor/core/crypto.ts"],
|
|
4
|
+
"sourcesContent": ["import { hmac } from \"@noble/hashes/hmac.js\"\nimport { sha1 } from \"@noble/hashes/legacy.js\"\nimport { md5 } from \"@noble/hashes/legacy.js\"\nimport { sha256 } from \"@noble/hashes/sha2.js\"\nimport { Buffer } from \"buffer\"\n\nconst digest = (algorithm: string) => {\n if (algorithm === \"sha256\") return sha256\n if (algorithm === \"sha1\") return sha1\n if (algorithm === \"md5\") return md5\n throw new Error(`Unsupported digest ${algorithm}`)\n}\nconst bytes = (input: string | Uint8Array) => typeof input === \"string\" ? new TextEncoder().encode(input) : input\ninterface Hash {\n update(input: string | Uint8Array): Hash\n digest(): Buffer\n digest(encoding: string): string\n}\nexport function createHash(algorithm: string): Hash {\n const parts: Uint8Array[] = []\n const hash = {\n update(input: string | Uint8Array) { parts.push(bytes(input)); return hash },\n digest(encoding?: string): Buffer | string {\n const result = Buffer.from(digest(algorithm)(Buffer.concat(parts)))\n return encoding === \"base64url\" ? result.toString(\"base64\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\") : encoding ? result.toString(encoding as BufferEncoding) : result\n },\n }\n return hash as Hash\n}\nexport function createHmac(algorithm: string, key: string | Uint8Array): Hash {\n const parts: Uint8Array[] = []\n const hash = {\n update(input: string | Uint8Array) { parts.push(bytes(input)); return hash },\n digest(encoding?: string): Buffer | string {\n const result = Buffer.from(hmac(digest(algorithm), bytes(key), Buffer.concat(parts)))\n return encoding === \"base64url\" ? result.toString(\"base64\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\") : encoding ? result.toString(encoding as BufferEncoding) : result\n },\n }\n return hash as Hash\n}\n/**\n * Mockingbird: where ids and tokens come from. With a seeded stream in place, everything the\n * vendor code mints replays from the seed; without one it is the platform's own randomness.\n */\nlet source: (() => number) | undefined\n/** Mint from `next` (a seeded stream of `[0, 1)`) until told otherwise. */\nexport function useRandom(next: (() => number) | undefined): void { source = next }\n/** Mint from `next` for one synchronous section, then put the previous source back. */\nexport function withRandom<T>(next: (() => number) | undefined, run: () => T): T {\n const previous = source\n source = next\n try { return run() } finally { source = previous }\n}\n/** `Math.random`, from the seeded stream when one is in place. */\nexport function random(): number { return source ? source() : Math.random() }\nexport function randomBytes(length: number): Buffer {\n if (!source) return Buffer.from(crypto.getRandomValues(new Uint8Array(length)))\n const out = new Uint8Array(length)\n for (let i = 0; i < length; i++) out[i] = Math.floor(source() * 256)\n return Buffer.from(out)\n}\nexport function randomUUID(): string {\n if (!source) return crypto.randomUUID()\n const b = randomBytes(16)\n b[6] = (b[6] & 0x0f) | 0x40\n b[8] = (b[8] & 0x3f) | 0x80\n const hex = b.toString(\"hex\")\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\nexport function timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) throw new Error(\"Buffers must have equal lengths\")\n let difference = 0\n for (let i = 0; i < a.length; i++) difference |= a[i] ^ b[i]\n return difference === 0\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -4,11 +4,14 @@ import {
|
|
|
4
4
|
createClock,
|
|
5
5
|
createRuntime,
|
|
6
6
|
markSocketClosed,
|
|
7
|
+
normalizeBootControls,
|
|
7
8
|
openSocketCount,
|
|
8
9
|
parseDuration,
|
|
10
|
+
parseFaultHeader,
|
|
9
11
|
resolveAdminPrefix,
|
|
12
|
+
restoreClock,
|
|
10
13
|
unbindSocketTransport
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-6MIIKZZB.js";
|
|
12
15
|
|
|
13
16
|
// ../../adapters/node/dist/cli.js
|
|
14
17
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
@@ -55,6 +58,8 @@ var serve = async (api, options = {}) => {
|
|
|
55
58
|
req.socket.destroy();
|
|
56
59
|
return;
|
|
57
60
|
}
|
|
61
|
+
if (aborted.signal.aborted)
|
|
62
|
+
return;
|
|
58
63
|
res.writeHead(500, { "content-type": "application/json" });
|
|
59
64
|
res.end(JSON.stringify({
|
|
60
65
|
error: {
|
|
@@ -86,6 +91,7 @@ var serve = async (api, options = {}) => {
|
|
|
86
91
|
}
|
|
87
92
|
res.end();
|
|
88
93
|
} catch {
|
|
94
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
89
95
|
res.destroy();
|
|
90
96
|
} finally {
|
|
91
97
|
reader.releaseLock();
|
|
@@ -168,10 +174,12 @@ var httpChild = async (target, entry, options) => {
|
|
|
168
174
|
adminPrefix: resolveAdminPrefix(entry.adminPrefix),
|
|
169
175
|
adminKey: entry.adminKey,
|
|
170
176
|
seed: entry.seed,
|
|
171
|
-
onLog: options.onLog
|
|
177
|
+
onLog: options.onLog,
|
|
178
|
+
...entry.adminControls !== void 0 ? { adminControls: entry.adminControls } : {},
|
|
179
|
+
...entry.fixtures !== void 0 ? { fixtures: entry.fixtures } : {},
|
|
180
|
+
...entry.baseUrl !== void 0 ? { baseUrl: entry.baseUrl } : {}
|
|
172
181
|
});
|
|
173
182
|
const adminPrefix = resolveAdminPrefix(entry.adminPrefix);
|
|
174
|
-
runtime.isolateNamespaces();
|
|
175
183
|
const locked = /* @__PURE__ */ new Set();
|
|
176
184
|
const active = /* @__PURE__ */ new Map();
|
|
177
185
|
const api = {
|
|
@@ -433,19 +441,12 @@ async function startFleet(config, options) {
|
|
|
433
441
|
return json(400, { error: "freeze must be boolean" });
|
|
434
442
|
const response2 = await transaction(namespace, selected, async (_name, child) => {
|
|
435
443
|
const childClock = child.clock(namespace);
|
|
436
|
-
childClock
|
|
437
|
-
childClock.set(target);
|
|
438
|
-
if (!frozen)
|
|
439
|
-
childClock.unfreeze();
|
|
444
|
+
restoreClock(childClock, { now: target, frozen });
|
|
440
445
|
await child.settle?.(namespace);
|
|
441
446
|
return childClock.state();
|
|
442
447
|
});
|
|
443
|
-
if (response2.ok)
|
|
444
|
-
current
|
|
445
|
-
current.set(target);
|
|
446
|
-
if (!frozen)
|
|
447
|
-
current.unfreeze();
|
|
448
|
-
}
|
|
448
|
+
if (response2.ok)
|
|
449
|
+
restoreClock(current, { now: target, frozen });
|
|
449
450
|
return response2;
|
|
450
451
|
}
|
|
451
452
|
if (!route)
|
|
@@ -464,13 +465,8 @@ async function startFleet(config, options) {
|
|
|
464
465
|
return json(404, { error: "no snapshot in this namespace" });
|
|
465
466
|
const restored = new Map([...point.values].map(([name]) => [name, children.get(name)]));
|
|
466
467
|
const response2 = await transaction(namespace, restored, async (name, child) => child.restore(namespace, point.values.get(name)));
|
|
467
|
-
if (response2.ok)
|
|
468
|
-
|
|
469
|
-
current.freeze();
|
|
470
|
-
current.set(point.clock.now);
|
|
471
|
-
if (!point.clock.frozen)
|
|
472
|
-
current.unfreeze();
|
|
473
|
-
}
|
|
468
|
+
if (response2.ok)
|
|
469
|
+
restoreClock(clock(namespace), point.clock);
|
|
474
470
|
return response2;
|
|
475
471
|
}
|
|
476
472
|
const snapshotId = randomUUID();
|
|
@@ -496,6 +492,8 @@ async function startFleet(config, options) {
|
|
|
496
492
|
for (const [name, entry] of Object.entries(config.services)) {
|
|
497
493
|
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name))
|
|
498
494
|
throw new Error("invalid service name");
|
|
495
|
+
if (config.adminControls !== void 0 || entry.adminControls !== void 0)
|
|
496
|
+
normalizeBootControls({ ...config.adminControls, ...entry.adminControls }, `services.${name}.adminControls`);
|
|
499
497
|
try {
|
|
500
498
|
const target = await options.load(name);
|
|
501
499
|
if (entry.protocol && entry.protocol !== ("protocol" in target ? target.protocol : "http"))
|
|
@@ -504,7 +502,9 @@ async function startFleet(config, options) {
|
|
|
504
502
|
const child = "start" in target ? await target.start(entry) : await httpChild(target, {
|
|
505
503
|
...entry,
|
|
506
504
|
adminPrefix: resolveAdminPrefix(entry.adminPrefix ?? adminPrefix),
|
|
507
|
-
...adminKey !== void 0 ? { adminKey } : {}
|
|
505
|
+
...adminKey !== void 0 ? { adminKey } : {},
|
|
506
|
+
// Fleet-wide controls, with the service's own keys replacing them.
|
|
507
|
+
...config.adminControls !== void 0 || entry.adminControls !== void 0 ? { adminControls: { ...config.adminControls, ...entry.adminControls } } : {}
|
|
508
508
|
}, options);
|
|
509
509
|
children.set(name, child);
|
|
510
510
|
if (!await child.ready())
|
|
@@ -637,7 +637,51 @@ var COMMON_SERVE_OPTIONS = {
|
|
|
637
637
|
value: "<key>",
|
|
638
638
|
description: "Require x-mockingbird-admin-key on /__admin/* (env MOCKINGBIRD_ADMIN_KEY)"
|
|
639
639
|
},
|
|
640
|
-
seed: {
|
|
640
|
+
seed: {
|
|
641
|
+
type: "string",
|
|
642
|
+
value: "<seed>",
|
|
643
|
+
description: "Seed for every random choice (env MOCKINGBIRD_SEED)"
|
|
644
|
+
},
|
|
645
|
+
"admin-controls": {
|
|
646
|
+
type: "string",
|
|
647
|
+
value: "<json|file>",
|
|
648
|
+
description: "Admin controls to boot with, as JSON or a JSON file: clock, latency, faults, snapshot, namespaces (env MOCKINGBIRD_ADMIN_CONTROLS)"
|
|
649
|
+
},
|
|
650
|
+
clock: {
|
|
651
|
+
type: "string",
|
|
652
|
+
value: "<instant>",
|
|
653
|
+
description: "Start the clock at this instant (epoch ms or ISO-8601)"
|
|
654
|
+
},
|
|
655
|
+
freeze: { type: "boolean", description: "Freeze the clock: it moves only when told to" },
|
|
656
|
+
"auto-advance": {
|
|
657
|
+
type: "string",
|
|
658
|
+
value: "<duration>",
|
|
659
|
+
description: "Step the clock this much before every request (e.g. 1s)"
|
|
660
|
+
},
|
|
661
|
+
latency: {
|
|
662
|
+
type: "string",
|
|
663
|
+
value: "<duration>",
|
|
664
|
+
description: "Baseline response time for every request (e.g. 250ms)"
|
|
665
|
+
},
|
|
666
|
+
jitter: {
|
|
667
|
+
type: "string",
|
|
668
|
+
value: "<duration>",
|
|
669
|
+
description: "Seeded extra latency between 0 and this"
|
|
670
|
+
},
|
|
671
|
+
"virtual-time": {
|
|
672
|
+
type: "boolean",
|
|
673
|
+
description: "Spend latency, delays and timeouts on the mock clock instead of really waiting"
|
|
674
|
+
},
|
|
675
|
+
fault: {
|
|
676
|
+
type: "string",
|
|
677
|
+
value: "<fault>",
|
|
678
|
+
description: 'A fault to boot with, as in x-mockingbird-fault: 503, rate_limited, "status=503; delay=2s"'
|
|
679
|
+
},
|
|
680
|
+
snapshot: {
|
|
681
|
+
type: "string",
|
|
682
|
+
value: "<file>",
|
|
683
|
+
description: "Start from a snapshot document (GET /__admin/snapshots/:id)"
|
|
684
|
+
},
|
|
641
685
|
log: {
|
|
642
686
|
type: "string",
|
|
643
687
|
value: "<pretty|json|off>",
|
|
@@ -684,6 +728,68 @@ var formatLog = (format) => {
|
|
|
684
728
|
};
|
|
685
729
|
};
|
|
686
730
|
var asString = (value) => typeof value === "string" ? value : void 0;
|
|
731
|
+
var readJsonFile = async (path, label) => {
|
|
732
|
+
try {
|
|
733
|
+
return JSON.parse(await readFile2(path, "utf8"));
|
|
734
|
+
} catch (error) {
|
|
735
|
+
throw new Error(`${label}: cannot read ${path}: ${error instanceof Error ? error.message : error}`);
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
739
|
+
var resolveServeControls = async (values, env = process.env, base) => {
|
|
740
|
+
const source = asString(values["admin-controls"]) ?? env.MOCKINGBIRD_ADMIN_CONTROLS;
|
|
741
|
+
let document = isObject2(base) ? { ...base } : {};
|
|
742
|
+
if (source !== void 0 && source.trim() !== "") {
|
|
743
|
+
let parsed;
|
|
744
|
+
if (source.trim().startsWith("{")) {
|
|
745
|
+
try {
|
|
746
|
+
parsed = JSON.parse(source);
|
|
747
|
+
} catch {
|
|
748
|
+
throw new Error("--admin-controls: not valid JSON");
|
|
749
|
+
}
|
|
750
|
+
} else
|
|
751
|
+
parsed = await readJsonFile(source, "--admin-controls");
|
|
752
|
+
if (!isObject2(parsed))
|
|
753
|
+
throw new Error("--admin-controls: expected a JSON object");
|
|
754
|
+
document = { ...document, ...parsed };
|
|
755
|
+
}
|
|
756
|
+
const clock = isObject2(document.clock) ? { ...document.clock } : {};
|
|
757
|
+
const now = asString(values.clock);
|
|
758
|
+
if (now !== void 0)
|
|
759
|
+
clock.now = now;
|
|
760
|
+
if (values.freeze === true)
|
|
761
|
+
clock.frozen = true;
|
|
762
|
+
const autoAdvance = asString(values["auto-advance"]);
|
|
763
|
+
if (autoAdvance !== void 0)
|
|
764
|
+
clock.autoAdvance = autoAdvance;
|
|
765
|
+
if (Object.keys(clock).length > 0)
|
|
766
|
+
document.clock = clock;
|
|
767
|
+
const delay = asString(values.latency);
|
|
768
|
+
const jitter = asString(values.jitter);
|
|
769
|
+
if (delay !== void 0 || jitter !== void 0) {
|
|
770
|
+
const latency = isObject2(document.latency) ? { ...document.latency } : document.latency !== void 0 ? { delay: document.latency } : {};
|
|
771
|
+
if (delay !== void 0)
|
|
772
|
+
latency.delay = delay;
|
|
773
|
+
if (jitter !== void 0)
|
|
774
|
+
latency.jitter = jitter;
|
|
775
|
+
document.latency = latency;
|
|
776
|
+
}
|
|
777
|
+
if (values["virtual-time"] === true)
|
|
778
|
+
document.virtualTime = true;
|
|
779
|
+
const fault = asString(values.fault);
|
|
780
|
+
if (fault !== void 0)
|
|
781
|
+
document.faults = [
|
|
782
|
+
...Array.isArray(document.faults) ? document.faults : [],
|
|
783
|
+
parseFaultHeader(fault, "--fault")
|
|
784
|
+
];
|
|
785
|
+
const snapshot = asString(values.snapshot);
|
|
786
|
+
if (snapshot !== void 0)
|
|
787
|
+
document.snapshot = await readJsonFile(snapshot, "--snapshot");
|
|
788
|
+
if (Object.keys(document).length === 0)
|
|
789
|
+
return void 0;
|
|
790
|
+
normalizeBootControls(document, "adminControls");
|
|
791
|
+
return document;
|
|
792
|
+
};
|
|
687
793
|
var loadTarget = async (name, own) => {
|
|
688
794
|
if (name === own.name)
|
|
689
795
|
return own;
|
|
@@ -710,7 +816,8 @@ var start = async (target, values, config) => {
|
|
|
710
816
|
adminPrefix,
|
|
711
817
|
adminKey: config.adminKey,
|
|
712
818
|
seed: config.seed,
|
|
713
|
-
onLog: formatLog(config.log)
|
|
819
|
+
onLog: formatLog(config.log),
|
|
820
|
+
...config.adminControls !== void 0 ? { adminControls: config.adminControls } : {}
|
|
714
821
|
});
|
|
715
822
|
const listening = await listen(runtime, { port: config.port, host: config.host });
|
|
716
823
|
target.listening?.(listening);
|
|
@@ -750,6 +857,9 @@ var serveCommand = (target) => ({
|
|
|
750
857
|
const adminKey2 = config.adminKey ?? asString(values["admin-key"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY;
|
|
751
858
|
if (adminKey2 !== void 0)
|
|
752
859
|
config.adminKey = adminKey2;
|
|
860
|
+
const adminControls = await resolveServeControls(values, process.env, config.adminControls);
|
|
861
|
+
if (adminControls !== void 0)
|
|
862
|
+
config.adminControls = adminControls;
|
|
753
863
|
const fleet = await startFleet(config, {
|
|
754
864
|
load: (name) => loadTarget(name, target),
|
|
755
865
|
onLog: formatLog(config.log ?? log),
|
|
@@ -775,10 +885,12 @@ var serveCommand = (target) => ({
|
|
|
775
885
|
}
|
|
776
886
|
const port = asString(values.port);
|
|
777
887
|
const adminKey = asString(values["admin-key"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY;
|
|
778
|
-
const seed = asString(values.seed);
|
|
888
|
+
const seed = asString(values.seed) ?? process.env.MOCKINGBIRD_SEED;
|
|
779
889
|
let listening;
|
|
780
890
|
try {
|
|
891
|
+
const adminControls = await resolveServeControls(values);
|
|
781
892
|
listening = await start(target, values, {
|
|
893
|
+
...adminControls !== void 0 ? { adminControls } : {},
|
|
782
894
|
adminPrefix: resolveAdminPrefix(asString(values["admin-prefix"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX),
|
|
783
895
|
port: port === void 0 ? target.defaultPort : Number.parseInt(port, 10),
|
|
784
896
|
host: asString(values.host) ?? "127.0.0.1",
|
|
@@ -794,6 +906,56 @@ var serveCommand = (target) => ({
|
|
|
794
906
|
}
|
|
795
907
|
});
|
|
796
908
|
|
|
909
|
+
// ../../adapters/node/dist/fixtures.js
|
|
910
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
911
|
+
var providerServeOptions = {
|
|
912
|
+
fixtures: {
|
|
913
|
+
type: "string",
|
|
914
|
+
value: "<json-file>",
|
|
915
|
+
description: "Load synthetic provider fixtures from a JSON object"
|
|
916
|
+
},
|
|
917
|
+
"base-url": {
|
|
918
|
+
type: "string",
|
|
919
|
+
value: "<url>",
|
|
920
|
+
description: "Public HTTP(S) base URL advertised in provider responses"
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
async function providerServeValues(values, defaults = {}) {
|
|
924
|
+
const options = {};
|
|
925
|
+
if (values.fixtures !== void 0) {
|
|
926
|
+
if (typeof values.fixtures !== "string")
|
|
927
|
+
throw new Error("--fixtures requires a JSON file");
|
|
928
|
+
let parsed;
|
|
929
|
+
try {
|
|
930
|
+
parsed = JSON.parse(await readFile3(values.fixtures, "utf8"));
|
|
931
|
+
} catch {
|
|
932
|
+
throw new Error("Cannot read --fixtures as JSON; supply a synthetic provider fixture object");
|
|
933
|
+
}
|
|
934
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
935
|
+
throw new Error("--fixtures must contain a JSON object");
|
|
936
|
+
options.fixtures = parsed;
|
|
937
|
+
} else if (defaults.fixtures !== void 0) {
|
|
938
|
+
if (defaults.fixtures === null || typeof defaults.fixtures !== "object" || Array.isArray(defaults.fixtures))
|
|
939
|
+
throw new Error("fleet fixtures must contain a JSON object");
|
|
940
|
+
options.fixtures = defaults.fixtures;
|
|
941
|
+
}
|
|
942
|
+
const advertised = values["base-url"] ?? defaults.baseUrl;
|
|
943
|
+
if (advertised !== void 0) {
|
|
944
|
+
let url;
|
|
945
|
+
try {
|
|
946
|
+
if (typeof advertised !== "string")
|
|
947
|
+
throw new Error();
|
|
948
|
+
url = new URL(advertised);
|
|
949
|
+
} catch {
|
|
950
|
+
throw new Error("--base-url must be an absolute HTTP(S) URL");
|
|
951
|
+
}
|
|
952
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
953
|
+
throw new Error("--base-url must be HTTP(S) without credentials, query or fragment");
|
|
954
|
+
options.baseUrl = url.href.replace(/\/+$/, "");
|
|
955
|
+
}
|
|
956
|
+
return options;
|
|
957
|
+
}
|
|
958
|
+
|
|
797
959
|
// src/socket-server.ts
|
|
798
960
|
import { createHash } from "node:crypto";
|
|
799
961
|
var GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
@@ -1096,6 +1258,7 @@ var serveTarget = {
|
|
|
1096
1258
|
name: "slack",
|
|
1097
1259
|
defaultPort: DEFAULT_PORT,
|
|
1098
1260
|
options: {
|
|
1261
|
+
...providerServeOptions,
|
|
1099
1262
|
token: {
|
|
1100
1263
|
type: "string",
|
|
1101
1264
|
value: "<xoxb-\u2026>",
|
|
@@ -1106,15 +1269,17 @@ var serveTarget = {
|
|
|
1106
1269
|
description: "Answer channel_not_found for channels not created through /__admin/channels"
|
|
1107
1270
|
}
|
|
1108
1271
|
},
|
|
1109
|
-
create: (values, common) => {
|
|
1272
|
+
create: async (values, common) => {
|
|
1110
1273
|
const token = text(values.token);
|
|
1111
1274
|
return createRuntime({
|
|
1275
|
+
...await providerServeValues(values, common),
|
|
1112
1276
|
settings: {
|
|
1113
1277
|
...token ? { tokens: [token] } : {},
|
|
1114
1278
|
...values["strict-channels"] === true ? { strictChannels: true } : {}
|
|
1115
1279
|
},
|
|
1116
1280
|
...common.adminPrefix !== void 0 ? { adminPrefix: common.adminPrefix } : {},
|
|
1117
1281
|
...common.adminKey !== void 0 ? { adminKey: common.adminKey } : {},
|
|
1282
|
+
...common.adminControls !== void 0 ? { adminControls: common.adminControls } : {},
|
|
1118
1283
|
...common.seed !== void 0 ? { seed: common.seed } : {},
|
|
1119
1284
|
...common.onLog ? { onLog: common.onLog } : {}
|
|
1120
1285
|
});
|
|
@@ -1137,4 +1302,4 @@ export {
|
|
|
1137
1302
|
createServer2 as createServer,
|
|
1138
1303
|
serveTarget
|
|
1139
1304
|
};
|
|
1140
|
-
//# sourceMappingURL=chunk-
|
|
1305
|
+
//# sourceMappingURL=chunk-ZFHCM6E3.js.map
|