@crvouga/mockingbird-service-slack 1.0.0 → 1.0.2

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/dist/server.d.ts CHANGED
@@ -170,82 +170,6 @@ type FaultRegistry$1 = {
170
170
  take(candidate: FaultCandidate$1): Promise<FaultHit$1[]>;
171
171
  };
172
172
 
173
- /** One handled request, as the structured log sees it. */
174
- type RequestLog$1 = {
175
- service: string;
176
- namespace: string;
177
- operationId: string | undefined;
178
- method: string;
179
- path: string;
180
- status: number;
181
- durationMs: number;
182
- /** True when the path matched no operation in the contract. */
183
- unmatched: boolean;
184
- /** Set when a fault rule produced the response. */
185
- faultId?: string;
186
- /** Resource ids the handler touched (`userId`, `orderId`, …), when the service reports them. */
187
- ids?: Record<string, string>;
188
- /** Set when the service created a resource the request referred to but that did not exist. */
189
- adopted?: boolean;
190
- };
191
- type MetricsReport$1 = {
192
- requests: number;
193
- /** Counts keyed `<operationId> <status>`. */
194
- byOperation: Record<string, number>;
195
- /**
196
- * Paths that matched no operation, most frequent first.
197
- *
198
- * This is the early-warning signal: a consumer calling something the mock does
199
- * not implement shows up here as a count, before it fails a suite as a 404.
200
- */
201
- unmatched: {
202
- method: string;
203
- path: string;
204
- count: number;
205
- }[];
206
- faults: number;
207
- totalDurationMs: number;
208
- };
209
- type Metrics$1 = {
210
- record(entry: RequestLog$1): void;
211
- report(): MetricsReport$1;
212
- reset(): void;
213
- };
214
-
215
- /** One journal entry: a request log stamped with when (on the mock clock) it was handled. */
216
- type JournalEntry$1 = RequestLog$1 & {
217
- at: string;
218
- };
219
- type JournalQuery$1 = {
220
- /** Only this namespace. Omit for every namespace, oldest first across all of them. */
221
- namespace?: string;
222
- operationId?: string;
223
- status?: number;
224
- /** Only entries at or after this instant (epoch ms). */
225
- since?: number;
226
- /** At most this many, the most recent kept. */
227
- limit?: number;
228
- };
229
- type Journal$1 = {
230
- readonly size: number;
231
- record(entry: JournalEntry$1): void;
232
- list(query?: JournalQuery$1): JournalEntry$1[];
233
- /** Forget one namespace's entries, or every namespace's. */
234
- clear(namespace?: string): void;
235
- };
236
-
237
- /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
238
- type CredentialRegistry$1 = {
239
- set(credential: string, namespace: string): void;
240
- get(credential: string): string | undefined;
241
- remove(credential: string): boolean;
242
- clear(): void;
243
- entries(): {
244
- credential: string;
245
- namespace: string;
246
- }[];
247
- };
248
-
249
173
  /** A stable identifier for a point in a {@link Timeline}. */
250
174
  type CheckpointId$1 = string;
251
175
  /** An immutable node in a timeline's checkpoint DAG. */
@@ -336,6 +260,110 @@ interface FetchAPI$2 {
336
260
  fetch(request: Request): Promise<Response>;
337
261
  }
338
262
 
263
+ /**
264
+ * One problem with a request body, at a dotted path (`patient.address.city`, `items.0.sku`).
265
+ * `kind` is `media_type` when the body is present but its media type is not one the operation
266
+ * accepts (a `415` on most vendors), `syntax` when it could not be decoded, `required` when
267
+ * the operation needs a body and none arrived, and `schema` for a contract violation.
268
+ */
269
+ type BodyIssue$1 = {
270
+ path: string;
271
+ message: string;
272
+ kind?: "media_type" | "syntax" | "required" | "schema";
273
+ };
274
+
275
+ /**
276
+ * What the mock received from a request it rejected, so a 4xx can be attributed after the
277
+ * fact (an empty body, a missing `content-type`, a schema violation) without logging the body.
278
+ */
279
+ type RejectedRequest$1 = {
280
+ /** The raw `content-type` header, or `null` when the request sent none. */
281
+ contentType: string | null;
282
+ /** Bytes of body received from `content-length` (`0` for none), or `null` when the client sent no length (a streamed / chunked body). */
283
+ bodyBytes: number | null;
284
+ /** The raw `transfer-encoding` header (`chunked`), or `null`. */
285
+ transferEncoding: string | null;
286
+ };
287
+ /** One handled request, as the structured log sees it. */
288
+ type RequestLog$1 = {
289
+ service: string;
290
+ namespace: string;
291
+ operationId: string | undefined;
292
+ method: string;
293
+ path: string;
294
+ status: number;
295
+ durationMs: number;
296
+ /** True when the path matched no operation in the contract. */
297
+ unmatched: boolean;
298
+ /** Set when a fault rule produced the response. */
299
+ faultId?: string;
300
+ /** Resource ids the handler touched (`userId`, `orderId`, …), when the service reports them. */
301
+ ids?: Record<string, string>;
302
+ /** Set when the service created a resource the request referred to but that did not exist. */
303
+ adopted?: boolean;
304
+ /** Set on a rejection (status ≥ 400) the mock produced itself, never on a scripted fault. */
305
+ request?: RejectedRequest$1;
306
+ /** The validation issues behind a rejection, when the service found any. */
307
+ issues?: BodyIssue$1[];
308
+ };
309
+ type MetricsReport$1 = {
310
+ requests: number;
311
+ /** Counts keyed `<operationId> <status>`. */
312
+ byOperation: Record<string, number>;
313
+ /**
314
+ * Paths that matched no operation, most frequent first.
315
+ *
316
+ * This is the early-warning signal: a consumer calling something the mock does
317
+ * not implement shows up here as a count, before it fails a suite as a 404.
318
+ */
319
+ unmatched: {
320
+ method: string;
321
+ path: string;
322
+ count: number;
323
+ }[];
324
+ faults: number;
325
+ totalDurationMs: number;
326
+ };
327
+ type Metrics$1 = {
328
+ record(entry: RequestLog$1): void;
329
+ report(): MetricsReport$1;
330
+ reset(): void;
331
+ };
332
+
333
+ /** One journal entry: a request log stamped with when (on the mock clock) it was handled. */
334
+ type JournalEntry$1 = RequestLog$1 & {
335
+ at: string;
336
+ };
337
+ type JournalQuery$1 = {
338
+ /** Only this namespace. Omit for every namespace, oldest first across all of them. */
339
+ namespace?: string;
340
+ operationId?: string;
341
+ status?: number;
342
+ /** Only entries at or after this instant (epoch ms). */
343
+ since?: number;
344
+ /** At most this many, the most recent kept. */
345
+ limit?: number;
346
+ };
347
+ type Journal$1 = {
348
+ readonly size: number;
349
+ record(entry: JournalEntry$1): void;
350
+ list(query?: JournalQuery$1): JournalEntry$1[];
351
+ /** Forget one namespace's entries, or every namespace's. */
352
+ clear(namespace?: string): void;
353
+ };
354
+
355
+ /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
356
+ type CredentialRegistry$1 = {
357
+ set(credential: string, namespace: string): void;
358
+ get(credential: string): string | undefined;
359
+ remove(credential: string): boolean;
360
+ clear(): void;
361
+ entries(): {
362
+ credential: string;
363
+ namespace: string;
364
+ }[];
365
+ };
366
+
339
367
  /**
340
368
  * A point-in-time copy of everything a service namespace holds.
341
369
  *
@@ -728,82 +756,6 @@ type FaultRegistry = {
728
756
  take(candidate: FaultCandidate): Promise<FaultHit[]>;
729
757
  };
730
758
 
731
- /** One handled request, as the structured log sees it. */
732
- type RequestLog = {
733
- service: string;
734
- namespace: string;
735
- operationId: string | undefined;
736
- method: string;
737
- path: string;
738
- status: number;
739
- durationMs: number;
740
- /** True when the path matched no operation in the contract. */
741
- unmatched: boolean;
742
- /** Set when a fault rule produced the response. */
743
- faultId?: string;
744
- /** Resource ids the handler touched (`userId`, `orderId`, …), when the service reports them. */
745
- ids?: Record<string, string>;
746
- /** Set when the service created a resource the request referred to but that did not exist. */
747
- adopted?: boolean;
748
- };
749
- type MetricsReport = {
750
- requests: number;
751
- /** Counts keyed `<operationId> <status>`. */
752
- byOperation: Record<string, number>;
753
- /**
754
- * Paths that matched no operation, most frequent first.
755
- *
756
- * This is the early-warning signal: a consumer calling something the mock does
757
- * not implement shows up here as a count, before it fails a suite as a 404.
758
- */
759
- unmatched: {
760
- method: string;
761
- path: string;
762
- count: number;
763
- }[];
764
- faults: number;
765
- totalDurationMs: number;
766
- };
767
- type Metrics = {
768
- record(entry: RequestLog): void;
769
- report(): MetricsReport;
770
- reset(): void;
771
- };
772
-
773
- /** One journal entry: a request log stamped with when (on the mock clock) it was handled. */
774
- type JournalEntry = RequestLog & {
775
- at: string;
776
- };
777
- type JournalQuery = {
778
- /** Only this namespace. Omit for every namespace, oldest first across all of them. */
779
- namespace?: string;
780
- operationId?: string;
781
- status?: number;
782
- /** Only entries at or after this instant (epoch ms). */
783
- since?: number;
784
- /** At most this many, the most recent kept. */
785
- limit?: number;
786
- };
787
- type Journal = {
788
- readonly size: number;
789
- record(entry: JournalEntry): void;
790
- list(query?: JournalQuery): JournalEntry[];
791
- /** Forget one namespace's entries, or every namespace's. */
792
- clear(namespace?: string): void;
793
- };
794
-
795
- /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
796
- type CredentialRegistry = {
797
- set(credential: string, namespace: string): void;
798
- get(credential: string): string | undefined;
799
- remove(credential: string): boolean;
800
- clear(): void;
801
- entries(): {
802
- credential: string;
803
- namespace: string;
804
- }[];
805
- };
806
-
807
759
  /** A stable identifier for a point in a {@link Timeline}. */
808
760
  type CheckpointId = string;
809
761
  /** An immutable node in a timeline's checkpoint DAG. */
@@ -894,6 +846,123 @@ interface FetchAPI$1 {
894
846
  fetch(request: Request): Promise<Response>;
895
847
  }
896
848
 
849
+ /** Options every provider constructor accepts. */
850
+ type APIOptions = {
851
+ /** Sync SQLite client. Defaults to `@crvouga/mockingbird-service-sqlite`. */
852
+ sqlite?: SqliteClient$1;
853
+ /** Clock used for `created`-style fields. Default `Date.now`. */
854
+ now?: () => number;
855
+ /**
856
+ * Storage namespace for this instance's records. Instances sharing one SQLite
857
+ * client stay isolated when their namespaces differ. Defaults to the service name.
858
+ */
859
+ namespace?: string;
860
+ };
861
+
862
+ /**
863
+ * One problem with a request body, at a dotted path (`patient.address.city`, `items.0.sku`).
864
+ * `kind` is `media_type` when the body is present but its media type is not one the operation
865
+ * accepts (a `415` on most vendors), `syntax` when it could not be decoded, `required` when
866
+ * the operation needs a body and none arrived, and `schema` for a contract violation.
867
+ */
868
+ type BodyIssue = {
869
+ path: string;
870
+ message: string;
871
+ kind?: "media_type" | "syntax" | "required" | "schema";
872
+ };
873
+
874
+ /**
875
+ * What the mock received from a request it rejected, so a 4xx can be attributed after the
876
+ * fact (an empty body, a missing `content-type`, a schema violation) without logging the body.
877
+ */
878
+ type RejectedRequest = {
879
+ /** The raw `content-type` header, or `null` when the request sent none. */
880
+ contentType: string | null;
881
+ /** Bytes of body received from `content-length` (`0` for none), or `null` when the client sent no length (a streamed / chunked body). */
882
+ bodyBytes: number | null;
883
+ /** The raw `transfer-encoding` header (`chunked`), or `null`. */
884
+ transferEncoding: string | null;
885
+ };
886
+ /** One handled request, as the structured log sees it. */
887
+ type RequestLog = {
888
+ service: string;
889
+ namespace: string;
890
+ operationId: string | undefined;
891
+ method: string;
892
+ path: string;
893
+ status: number;
894
+ durationMs: number;
895
+ /** True when the path matched no operation in the contract. */
896
+ unmatched: boolean;
897
+ /** Set when a fault rule produced the response. */
898
+ faultId?: string;
899
+ /** Resource ids the handler touched (`userId`, `orderId`, …), when the service reports them. */
900
+ ids?: Record<string, string>;
901
+ /** Set when the service created a resource the request referred to but that did not exist. */
902
+ adopted?: boolean;
903
+ /** Set on a rejection (status ≥ 400) the mock produced itself, never on a scripted fault. */
904
+ request?: RejectedRequest;
905
+ /** The validation issues behind a rejection, when the service found any. */
906
+ issues?: BodyIssue[];
907
+ };
908
+ type MetricsReport = {
909
+ requests: number;
910
+ /** Counts keyed `<operationId> <status>`. */
911
+ byOperation: Record<string, number>;
912
+ /**
913
+ * Paths that matched no operation, most frequent first.
914
+ *
915
+ * This is the early-warning signal: a consumer calling something the mock does
916
+ * not implement shows up here as a count, before it fails a suite as a 404.
917
+ */
918
+ unmatched: {
919
+ method: string;
920
+ path: string;
921
+ count: number;
922
+ }[];
923
+ faults: number;
924
+ totalDurationMs: number;
925
+ };
926
+ type Metrics = {
927
+ record(entry: RequestLog): void;
928
+ report(): MetricsReport;
929
+ reset(): void;
930
+ };
931
+
932
+ /** One journal entry: a request log stamped with when (on the mock clock) it was handled. */
933
+ type JournalEntry = RequestLog & {
934
+ at: string;
935
+ };
936
+ type JournalQuery = {
937
+ /** Only this namespace. Omit for every namespace, oldest first across all of them. */
938
+ namespace?: string;
939
+ operationId?: string;
940
+ status?: number;
941
+ /** Only entries at or after this instant (epoch ms). */
942
+ since?: number;
943
+ /** At most this many, the most recent kept. */
944
+ limit?: number;
945
+ };
946
+ type Journal = {
947
+ readonly size: number;
948
+ record(entry: JournalEntry): void;
949
+ list(query?: JournalQuery): JournalEntry[];
950
+ /** Forget one namespace's entries, or every namespace's. */
951
+ clear(namespace?: string): void;
952
+ };
953
+
954
+ /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
955
+ type CredentialRegistry = {
956
+ set(credential: string, namespace: string): void;
957
+ get(credential: string): string | undefined;
958
+ remove(credential: string): boolean;
959
+ clear(): void;
960
+ entries(): {
961
+ credential: string;
962
+ namespace: string;
963
+ }[];
964
+ };
965
+
897
966
  /**
898
967
  * A point-in-time copy of everything a service namespace holds.
899
968
  *
@@ -1075,19 +1144,6 @@ declare class OutboxStore<T extends OutboxItem = OutboxItem> {
1075
1144
  list(query?: OutboxQuery): T[];
1076
1145
  }
1077
1146
 
1078
- /** Options every provider constructor accepts. */
1079
- type APIOptions = {
1080
- /** Sync SQLite client. Defaults to `@crvouga/mockingbird-service-sqlite`. */
1081
- sqlite?: SqliteClient$1;
1082
- /** Clock used for `created`-style fields. Default `Date.now`. */
1083
- now?: () => number;
1084
- /**
1085
- * Storage namespace for this instance's records. Instances sharing one SQLite
1086
- * client stay isolated when their namespaces differ. Defaults to the service name.
1087
- */
1088
- namespace?: string;
1089
- };
1090
-
1091
1147
  /** Bind values accepted by Mockingbird's SQLite port (matches sqlite-mem / better-sqlite3). */
1092
1148
  type SqliteValue = null | number | bigint | string | Uint8Array | boolean;
1093
1149
  /** Mutation counters returned by {@link SqliteStatement.run}. */
package/dist/server.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  DEFAULT_PORT,
3
3
  createServer,
4
4
  serveTarget
5
- } from "./chunk-H2VZTZFJ.js";
6
- import "./chunk-HYPQOQ27.js";
5
+ } from "./chunk-YM73XE57.js";
6
+ import "./chunk-T6MXK2OA.js";
7
7
  export {
8
8
  DEFAULT_PORT,
9
9
  createServer,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crvouga/mockingbird-service-slack",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Stateful mock of Slack incoming webhooks and the Web API (chat.postMessage and friends) with an outbox of every alert the app sent.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../adapters/node/src/cli.ts", "../../../adapters/node/src/serve.ts", "../../../adapters/node/src/listen.ts", "../src/server.ts"],
4
- "sourcesContent": ["import { readFile } from \"node:fs/promises\"\nimport { type ParseArgsConfig, parseArgs } from \"node:util\"\nimport type { RequestLog, ServiceInstance, ServiceRuntime } from \"@crvouga/mockingbird-service\"\nimport { type Listening, listen } from \"./listen.js\"\n\nexport type CliOption = {\n type: \"string\" | \"boolean\"\n description: string\n /** Shown in help; the value placeholder, e.g. `<port>`. */\n value?: string\n default?: string | boolean\n}\n\nexport type CliValues = Record<string, string | boolean | undefined>\n\nexport type CliCommand = {\n summary: string\n usage?: string\n options?: Record<string, CliOption>\n /** Resolves to an exit code; a server command resolves only when it stops. */\n run(values: CliValues, positionals: string[]): Promise<number>\n}\n\nexport type CliSpec = {\n bin: string\n description: string\n commands: Record<string, CliCommand>\n}\n\nconst optionHelp = (options: Record<string, CliOption>): string[] =>\n Object.entries(options).map(([name, option]) => {\n const flag = `--${name}${option.type === \"string\" ? ` ${option.value ?? \"<value>\"}` : \"\"}`\n const fallback = option.default !== undefined ? ` (default: ${String(option.default)})` : \"\"\n return ` ${flag.padEnd(30)} ${option.description}${fallback}`\n })\n\nconst help = (spec: CliSpec): string =>\n [\n `${spec.bin} \u2014 ${spec.description}`,\n \"\",\n \"Usage:\",\n ` ${spec.bin} <command> [options]`,\n \"\",\n \"Commands:\",\n ...Object.entries(spec.commands).map(([name, c]) => ` ${name.padEnd(30)} ${c.summary}`),\n \"\",\n `Run \\`${spec.bin} <command> --help\\` for a command's options.`,\n ].join(\"\\n\")\n\nconst commandHelp = (spec: CliSpec, name: string, command: CliCommand): string =>\n [\n `${spec.bin} ${name} \u2014 ${command.summary}`,\n \"\",\n \"Usage:\",\n ` ${command.usage ?? `${spec.bin} ${name} [options]`}`,\n ...(command.options ? [\"\", \"Options:\", ...optionHelp(command.options)] : []),\n ].join(\"\\n\")\n\n/** Parse `argv` against `spec` and run the chosen command. Resolves to an exit code. */\nexport const runCli = async (spec: CliSpec, argv: string[]): Promise<number> => {\n // Two-word commands (`corpus pull`) win over one-word ones.\n const pair = argv.length >= 2 ? `${argv[0]} ${argv[1]}` : undefined\n const words = pair !== undefined && spec.commands[pair] ? 2 : 1\n const name = words === 2 ? pair : argv[0]\n const rest = argv.slice(words)\n if (name === undefined || name === \"--help\" || name === \"-h\" || name === \"help\") {\n console.log(help(spec))\n return 0\n }\n const command = spec.commands[name]\n if (!command) {\n console.error(`${spec.bin}: unknown command ${JSON.stringify(name)}\\n\\n${help(spec)}`)\n return 2\n }\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n console.log(commandHelp(spec, name, command))\n return 0\n }\n let parsed: { values: CliValues; positionals: string[] }\n try {\n parsed = parseArgs({\n args: rest,\n allowPositionals: true,\n strict: true,\n options: Object.fromEntries(\n Object.entries(command.options ?? {}).map(([key, option]) => [\n key,\n {\n type: option.type,\n ...(option.default !== undefined ? { default: option.default } : {}),\n },\n ]),\n ) as ParseArgsConfig[\"options\"],\n }) as { values: CliValues; positionals: string[] }\n } catch (error) {\n console.error(\n `${spec.bin} ${name}: ${error instanceof Error ? error.message : String(error)}\\n\\n${commandHelp(spec, name, command)}`,\n )\n return 2\n }\n return command.run(parsed.values, parsed.positionals)\n}\n\n// \u2500\u2500 serve \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type LogFormat = \"pretty\" | \"json\" | \"off\"\n\nexport type CommonServeOptions = {\n adminKey: string | undefined\n seed: string | undefined\n onLog: ((entry: RequestLog) => void) | undefined\n}\n\n/**\n * What a service contributes to `serve`: how to build its runtime from CLI flags,\n * and what to say at startup. Every service's `./server` entry exports one as\n * `serveTarget`, which is also how `serve --config` finds services by name.\n */\nexport type ServeTarget = {\n name: string\n defaultPort: number\n /** Serve flags beyond the common ones. */\n options?: Record<string, CliOption>\n create(\n values: CliValues,\n common: CommonServeOptions,\n ): Promise<ServiceRuntime<ServiceInstance>> | ServiceRuntime<ServiceInstance>\n /** Startup lines after the listen address, e.g. the loaded corpus version. */\n banner?(runtime: ServiceRuntime<ServiceInstance>): string[]\n}\n\nconst COMMON_SERVE_OPTIONS: Record<string, CliOption> = {\n port: { type: \"string\", value: \"<port>\", description: \"Port to listen on\" },\n host: { type: \"string\", value: \"<host>\", description: \"Interface to bind\", default: \"127.0.0.1\" },\n \"admin-key\": {\n type: \"string\",\n value: \"<key>\",\n description: \"Require x-mockingbird-admin-key on /__admin/* (env MOCKINGBIRD_ADMIN_KEY)\",\n },\n seed: { type: \"string\", value: \"<seed>\", description: \"Seed for every random choice\" },\n log: {\n type: \"string\",\n value: \"<pretty|json|off>\",\n description: \"Request log format\",\n default: \"pretty\",\n },\n \"log-requests\": {\n type: \"boolean\",\n description:\n \"One JSON line per request: namespace, operationId, status, ids touched (never bodies). Same as --log json\",\n },\n config: {\n type: \"string\",\n value: \"<file>\",\n description: \"Serve every service in a mockingbird.json config instead\",\n },\n}\n\nconst formatLog = (format: LogFormat) => {\n if (format === \"off\") return undefined\n if (format === \"json\") return (entry: RequestLog) => console.log(JSON.stringify(entry))\n return (entry: RequestLog) => {\n const op = entry.operationId ?? (entry.unmatched ? \"UNMATCHED\" : \"-\")\n const ns = entry.namespace === \"default\" ? \"\" : ` [${entry.namespace}]`\n const fault = entry.faultId ? ` fault=${entry.faultId}` : \"\"\n const adopted = entry.adopted ? \" adopted\" : \"\"\n console.log(\n `${entry.service} ${entry.method} ${entry.path} ${entry.status} ${op} ${entry.durationMs}ms${ns}${fault}${adopted}`,\n )\n }\n}\n\nconst asString = (value: string | boolean | undefined): string | undefined =>\n typeof value === \"string\" ? value : undefined\n\n/** A service entry in `mockingbird.json`. */\nexport type ConfigService = {\n port?: number\n host?: string\n adminKey?: string\n seed?: string\n /** Service-specific serve flags, by long name: `{ \"webhook-url\": \"\u2026\" }`. */\n options?: Record<string, string | boolean>\n}\n\nexport type MockingbirdConfig = {\n /** Keyed by service name: `junction` loads `@crvouga/mockingbird-service-junction`. */\n services: Record<string, ConfigService>\n log?: LogFormat\n}\n\nconst loadTarget = async (name: string, own: ServeTarget): Promise<ServeTarget> => {\n if (name === own.name) return own\n const specifier = `@crvouga/mockingbird-service-${name}/server`\n try {\n const mod = (await import(specifier)) as { serveTarget?: ServeTarget }\n if (!mod.serveTarget) throw new Error(`${specifier} exports no serveTarget`)\n return mod.serveTarget\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n throw new Error(\n `cannot load service \"${name}\": ${reason}. Install @crvouga/mockingbird-service-${name}.`,\n )\n }\n}\n\nconst start = async (\n target: ServeTarget,\n values: CliValues,\n config: { port: number; host: string; adminKey?: string; seed?: string; log: LogFormat },\n): Promise<Listening> => {\n const runtime = await target.create(values, {\n adminKey: config.adminKey,\n seed: config.seed,\n onLog: formatLog(config.log),\n })\n const listening = await listen(runtime, { port: config.port, host: config.host })\n console.log(`${target.name} mock listening on ${listening.url}`)\n console.log(`${target.name} health: GET ${listening.url}/health`)\n console.log(\n `${target.name} admin: ${listening.url}/__admin (${config.adminKey ? \"x-mockingbird-admin-key required\" : \"open \u2014 pass --admin-key to lock\"})`,\n )\n for (const line of target.banner?.(runtime) ?? []) console.log(`${target.name} ${line}`)\n return listening\n}\n\nconst untilSignal = async (servers: Listening[]): Promise<number> =>\n new Promise((resolve) => {\n const stop = async () => {\n await Promise.allSettled(servers.map((s) => s.close()))\n resolve(0)\n }\n process.once(\"SIGINT\", stop)\n process.once(\"SIGTERM\", stop)\n })\n\n/** The standard `serve` command for a service, including multi-service `--config`. */\nexport const serveCommand = (target: ServeTarget): CliCommand => ({\n summary: `Serve the ${target.name} mock over HTTP`,\n options: { ...COMMON_SERVE_OPTIONS, ...target.options },\n async run(values) {\n const log = (\n values[\"log-requests\"] === true ? \"json\" : (asString(values.log) ?? \"pretty\")\n ) as LogFormat\n if (![\"pretty\", \"json\", \"off\"].includes(log)) {\n console.error(`--log must be pretty, json or off (got ${log})`)\n return 2\n }\n const configPath = asString(values.config)\n if (configPath !== undefined) {\n const config = JSON.parse(await readFile(configPath, \"utf8\")) as MockingbirdConfig\n const servers: Listening[] = []\n try {\n for (const [name, entry] of Object.entries(config.services ?? {})) {\n const each = await loadTarget(name, target)\n servers.push(\n await start(each, entry.options ?? {}, {\n port: entry.port ?? each.defaultPort,\n host: entry.host ?? \"127.0.0.1\",\n ...(entry.adminKey !== undefined ? { adminKey: entry.adminKey } : {}),\n ...(entry.seed !== undefined ? { seed: entry.seed } : {}),\n log: config.log ?? log,\n }),\n )\n }\n } catch (error) {\n await Promise.allSettled(servers.map((s) => s.close()))\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n return untilSignal(servers)\n }\n const port = asString(values.port)\n const adminKey = asString(values[\"admin-key\"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY\n const seed = asString(values.seed)\n let listening: Listening\n try {\n listening = await start(target, values, {\n port: port === undefined ? target.defaultPort : Number.parseInt(port, 10),\n host: asString(values.host) ?? \"127.0.0.1\",\n ...(adminKey !== undefined ? { adminKey } : {}),\n ...(seed !== undefined ? { seed } : {}),\n log,\n })\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n return untilSignal([listening])\n },\n})\n", "import { createServer } from \"node:http\"\nimport type { FetchAPI } from \"@crvouga/mockingbird-core\"\n\n/** Options for {@link serve}. */\nexport type NodeServeOptions = {\n port?: number\n host?: string\n}\n\n/**\n * Serve any Mockingbird {@link FetchAPI} over `node:http`.\n * Port defaults to `0`, so the OS assigns an ephemeral port (read from `server.address()`).\n */\nexport const serve = async (api: FetchAPI, options: NodeServeOptions = {}) => {\n const server = createServer(async (req, res) => {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.from(chunk))\n }\n const body = Buffer.concat(chunks)\n const address = server.address()\n const port = typeof address === \"object\" && address !== null ? address.port : undefined\n const base = `http://${req.headers.host ?? `localhost:${port ?? 80}`}`\n const raw = req.url ?? \"/\"\n const url = new URL(raw.replace(/^\\/+/, \"/\"), base)\n const method = req.method ?? \"GET\"\n const init: RequestInit = { method, headers: req.headers as Record<string, string> }\n if (method !== \"GET\" && method !== \"HEAD\" && body.length > 0) {\n init.body = body\n }\n const aborted = new AbortController()\n res.once(\"close\", () => {\n if (!res.writableFinished) aborted.abort()\n })\n init.signal = aborted.signal\n const request = new Request(url, init)\n let response: Response\n try {\n response = await api.fetch(request)\n } catch (error) {\n // A `drop` fault: destroy the socket so the client sees the connection die.\n if ((error as { code?: string }).code === \"MOCKINGBIRD_DROP\") {\n req.socket.destroy()\n return\n }\n res.writeHead(500, { \"content-type\": \"application/json\" })\n res.end(\n JSON.stringify({\n error: {\n type: \"mockingbird_internal\",\n message: error instanceof Error ? error.message : String(error),\n },\n }),\n )\n return\n }\n // Headers#entries() joins repeated headers; Set-Cookie must stay one header per cookie.\n const headers: Record<string, string | string[]> = Object.fromEntries(response.headers)\n const cookies = response.headers.getSetCookie()\n if (cookies.length > 0) headers[\"set-cookie\"] = cookies\n if (!response.body) {\n res.writeHead(response.status, headers)\n res.end()\n return\n }\n // Stream the body chunk by chunk: event streams and long-polls must not be buffered.\n res.writeHead(response.status, headers)\n res.flushHeaders()\n const reader = response.body.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (!res.write(value)) await new Promise<void>((resolve) => res.once(\"drain\", resolve))\n }\n res.end()\n } catch {\n res.destroy()\n } finally {\n reader.releaseLock()\n }\n })\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(options.port ?? 0, options.host, resolve)\n })\n return server\n}\n", "import type { Server } from \"node:http\"\nimport type { FetchAPI } from \"@crvouga/mockingbird-core\"\nimport { serve } from \"./serve.js\"\n\nexport type ListenOptions = {\n /** Default `0`: the OS picks a free port. */\n port?: number\n /** Default `127.0.0.1`: a mock should not be reachable off the machine by accident. */\n host?: string\n}\n\n/** A running server, with the address it actually bound. */\nexport type Listening = {\n url: string\n port: number\n host: string\n server: Server\n close(): Promise<void>\n}\n\nexport const listen = async (api: FetchAPI, options: ListenOptions = {}): Promise<Listening> => {\n const host = options.host ?? \"127.0.0.1\"\n const server = await serve(api, { port: options.port ?? 0, host })\n const address = server.address()\n const port = typeof address === \"object\" && address !== null ? address.port : (options.port ?? 0)\n const shown = host.includes(\":\") ? `[${host}]` : host\n return {\n url: `http://${shown}:${port}`,\n port,\n host,\n server,\n close: () =>\n new Promise<void>((resolve, reject) => {\n // Stop accepting first, then drop keep-alive sockets so close() can finish.\n server.close((error) => {\n if (error && (error as { code?: string }).code !== \"ERR_SERVER_NOT_RUNNING\") reject(error)\n else resolve()\n })\n server.closeAllConnections?.()\n }),\n }\n}\n", "/// <reference types=\"node\" />\nimport { type Listening, listen, type ServeTarget } from \"@crvouga/mockingbird-adapter-node\"\nimport { createRuntime, type SlackRuntime, type SlackRuntimeOptions } from \"./runtime.js\"\n\n/** Port `mockingbird-slack serve` listens on when none is given. */\nexport const DEFAULT_PORT = 8808\n\nexport type SlackServerOptions = SlackRuntimeOptions & {\n /** Default `0`: the OS picks a free port. */\n port?: number\n /** Default `127.0.0.1`. */\n host?: string\n}\n\nexport type SlackServer = Listening & { runtime: SlackRuntime }\n\n/** Serve the Slack mock over `node:http`. */\nexport const createServer = async (options: SlackServerOptions = {}): Promise<SlackServer> => {\n const { port, host, ...rest } = options\n const runtime = createRuntime(rest)\n const listening = await listen(runtime, {\n port: port ?? 0,\n ...(host !== undefined ? { host } : {}),\n })\n return { ...listening, runtime }\n}\n\nconst text = (value: string | boolean | undefined) =>\n typeof value === \"string\" ? value : undefined\n\n/** How `serve` (and `serve --config`) builds the Slack mock from flags. */\nexport const serveTarget: ServeTarget = {\n name: \"slack\",\n defaultPort: DEFAULT_PORT,\n options: {\n token: {\n type: \"string\",\n value: \"<xoxb-\u2026>\",\n description:\n \"Only accept this bot token on the Web API (default: any xoxb-/xoxp- token is accepted)\",\n },\n \"strict-channels\": {\n type: \"boolean\",\n description: \"Answer channel_not_found for channels not created through /__admin/channels\",\n },\n },\n create: (values, common) => {\n const token = text(values.token)\n return createRuntime({\n settings: {\n ...(token ? { tokens: [token] } : {}),\n ...(values[\"strict-channels\"] === true ? { strictChannels: true } : {}),\n },\n ...(common.adminKey !== undefined ? { adminKey: common.adminKey } : {}),\n ...(common.seed !== undefined ? { seed: common.seed } : {}),\n ...(common.onLog ? { onLog: common.onLog } : {}),\n })\n },\n banner: () => [\n \"webhooks: point SLACK_*_WEBHOOK_URL at <this>/services/T000/B000/XXXX (any path works until you POST /__admin/hooks)\",\n \"web api: Authorization: Bearer xoxb-\u2026; @slack/web-api: new WebClient(token, {slackApiUrl: '<this>/api/'})\",\n \"outbox: GET /__admin/outbox?webhook=/services/T/B/X or ?channel=C\u2026\",\n ],\n}\n"],
5
- "mappings": ";;;;;AAAA,SAAS,gBAAgB;AACzB,SAA+B,iBAAiB;;;ACDhD,SAAS,oBAAoB;AAatB,IAAM,QAAQ,OAAO,KAAe,UAA4B,CAAA,MAAM;AAC3E,QAAM,SAAS,aAAa,OAAO,KAAK,QAAO;AAC7C,UAAM,SAAmB,CAAA;AACzB,qBAAiB,SAAS,KAAK;AAC7B,aAAO,KAAK,OAAO,KAAK,KAAK,CAAC;IAChC;AACA,UAAM,OAAO,OAAO,OAAO,MAAM;AACjC,UAAM,UAAU,OAAO,QAAO;AAC9B,UAAM,OAAO,OAAO,YAAY,YAAY,YAAY,OAAO,QAAQ,OAAO;AAC9E,UAAM,OAAO,UAAU,IAAI,QAAQ,QAAQ,aAAa,QAAQ,EAAE,EAAE;AACpE,UAAM,MAAM,IAAI,OAAO;AACvB,UAAM,MAAM,IAAI,IAAI,IAAI,QAAQ,QAAQ,GAAG,GAAG,IAAI;AAClD,UAAM,SAAS,IAAI,UAAU;AAC7B,UAAM,OAAoB,EAAE,QAAQ,SAAS,IAAI,QAAiC;AAClF,QAAI,WAAW,SAAS,WAAW,UAAU,KAAK,SAAS,GAAG;AAC5D,WAAK,OAAO;IACd;AACA,UAAM,UAAU,IAAI,gBAAe;AACnC,QAAI,KAAK,SAAS,MAAK;AACrB,UAAI,CAAC,IAAI;AAAkB,gBAAQ,MAAK;IAC1C,CAAC;AACD,SAAK,SAAS,QAAQ;AACtB,UAAM,UAAU,IAAI,QAAQ,KAAK,IAAI;AACrC,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,IAAI,MAAM,OAAO;IACpC,SAAS,OAAO;AAEd,UAAK,MAA4B,SAAS,oBAAoB;AAC5D,YAAI,OAAO,QAAO;AAClB;MACF;AACA,UAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAkB,CAAE;AACzD,UAAI,IACF,KAAK,UAAU;QACb,OAAO;UACL,MAAM;UACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;;OAEjE,CAAC;AAEJ;IACF;AAEA,UAAM,UAA6C,OAAO,YAAY,SAAS,OAAO;AACtF,UAAM,UAAU,SAAS,QAAQ,aAAY;AAC7C,QAAI,QAAQ,SAAS;AAAG,cAAQ,YAAY,IAAI;AAChD,QAAI,CAAC,SAAS,MAAM;AAClB,UAAI,UAAU,SAAS,QAAQ,OAAO;AACtC,UAAI,IAAG;AACP;IACF;AAEA,QAAI,UAAU,SAAS,QAAQ,OAAO;AACtC,QAAI,aAAY;AAChB,UAAM,SAAS,SAAS,KAAK,UAAS;AACtC,QAAI;AACF,iBAAS;AACP,cAAM,EAAE,MAAM,MAAK,IAAK,MAAM,OAAO,KAAI;AACzC,YAAI;AAAM;AACV,YAAI,CAAC,IAAI,MAAM,KAAK;AAAG,gBAAM,IAAI,QAAc,CAAC,YAAY,IAAI,KAAK,SAAS,OAAO,CAAC;MACxF;AACA,UAAI,IAAG;IACT,QAAQ;AACN,UAAI,QAAO;IACb;AACE,aAAO,YAAW;IACpB;EACF,CAAC;AACD,QAAM,IAAI,QAAc,CAAC,SAAS,WAAU;AAC1C,WAAO,KAAK,SAAS,MAAM;AAC3B,WAAO,OAAO,QAAQ,QAAQ,GAAG,QAAQ,MAAM,OAAO;EACxD,CAAC;AACD,SAAO;AACT;;;ACnEO,IAAM,SAAS,OAAO,KAAe,UAAyB,CAAA,MAA0B;AAC7F,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,SAAS,MAAM,MAAM,KAAK,EAAE,MAAM,QAAQ,QAAQ,GAAG,KAAI,CAAE;AACjE,QAAM,UAAU,OAAO,QAAO;AAC9B,QAAM,OAAO,OAAO,YAAY,YAAY,YAAY,OAAO,QAAQ,OAAQ,QAAQ,QAAQ;AAC/F,QAAM,QAAQ,KAAK,SAAS,GAAG,IAAI,IAAI,IAAI,MAAM;AACjD,SAAO;IACL,KAAK,UAAU,KAAK,IAAI,IAAI;IAC5B;IACA;IACA;IACA,OAAO,MACL,IAAI,QAAc,CAAC,SAAS,WAAU;AAEpC,aAAO,MAAM,CAAC,UAAS;AACrB,YAAI,SAAU,MAA4B,SAAS;AAA0B,iBAAO,KAAK;;AACpF,kBAAO;MACd,CAAC;AACD,aAAO,sBAAqB;IAC9B,CAAC;;AAEP;;;AFZA,IAAM,aAAa,CAAC,YAClB,OAAO,QAAQ,OAAO,EAAE,IAAI,CAAC,CAAC,MAAM,MAAM,MAAK;AAC7C,QAAM,OAAO,KAAK,IAAI,GAAG,OAAO,SAAS,WAAW,IAAI,OAAO,SAAS,SAAS,KAAK,EAAE;AACxF,QAAM,WAAW,OAAO,YAAY,SAAY,cAAc,OAAO,OAAO,OAAO,CAAC,MAAM;AAC1F,SAAO,KAAK,KAAK,OAAO,EAAE,CAAC,IAAI,OAAO,WAAW,GAAG,QAAQ;AAC9D,CAAC;AAEH,IAAM,OAAO,CAAC,SACZ;EACE,GAAG,KAAK,GAAG,WAAM,KAAK,WAAW;EACjC;EACA;EACA,KAAK,KAAK,GAAG;EACb;EACA;EACA,GAAG,OAAO,QAAQ,KAAK,QAAQ,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,KAAK,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE;EACvF;EACA,SAAS,KAAK,GAAG;EACjB,KAAK,IAAI;AAEb,IAAM,cAAc,CAAC,MAAe,MAAc,YAChD;EACE,GAAG,KAAK,GAAG,IAAI,IAAI,WAAM,QAAQ,OAAO;EACxC;EACA;EACA,KAAK,QAAQ,SAAS,GAAG,KAAK,GAAG,IAAI,IAAI,YAAY;EACrD,GAAI,QAAQ,UAAU,CAAC,IAAI,YAAY,GAAG,WAAW,QAAQ,OAAO,CAAC,IAAI,CAAA;EACzE,KAAK,IAAI;AAGN,IAAM,SAAS,OAAO,MAAe,SAAmC;AAE7E,QAAM,OAAO,KAAK,UAAU,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK;AAC1D,QAAM,QAAQ,SAAS,UAAa,KAAK,SAAS,IAAI,IAAI,IAAI;AAC9D,QAAM,OAAO,UAAU,IAAI,OAAO,KAAK,CAAC;AACxC,QAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,MAAI,SAAS,UAAa,SAAS,YAAY,SAAS,QAAQ,SAAS,QAAQ;AAC/E,YAAQ,IAAI,KAAK,IAAI,CAAC;AACtB,WAAO;EACT;AACA,QAAM,UAAU,KAAK,SAAS,IAAI;AAClC,MAAI,CAAC,SAAS;AACZ,YAAQ,MAAM,GAAG,KAAK,GAAG,qBAAqB,KAAK,UAAU,IAAI,CAAC;;EAAO,KAAK,IAAI,CAAC,EAAE;AACrF,WAAO;EACT;AACA,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;AAClD,YAAQ,IAAI,YAAY,MAAM,MAAM,OAAO,CAAC;AAC5C,WAAO;EACT;AACA,MAAI;AACJ,MAAI;AACF,aAAS,UAAU;MACjB,MAAM;MACN,kBAAkB;MAClB,QAAQ;MACR,SAAS,OAAO,YACd,OAAO,QAAQ,QAAQ,WAAW,CAAA,CAAE,EAAE,IAAI,CAAC,CAAC,KAAK,MAAM,MAAM;QAC3D;QACA;UACE,MAAM,OAAO;UACb,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAO,IAAK,CAAA;;OAEpE,CAAC;KAEL;EACH,SAAS,OAAO;AACd,YAAQ,MACN,GAAG,KAAK,GAAG,IAAI,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;;EAAO,YAAY,MAAM,MAAM,OAAO,CAAC,EAAE;AAEzH,WAAO;EACT;AACA,SAAO,QAAQ,IAAI,OAAO,QAAQ,OAAO,WAAW;AACtD;AA8BA,IAAM,uBAAkD;EACtD,MAAM,EAAE,MAAM,UAAU,OAAO,UAAU,aAAa,oBAAmB;EACzE,MAAM,EAAE,MAAM,UAAU,OAAO,UAAU,aAAa,qBAAqB,SAAS,YAAW;EAC/F,aAAa;IACX,MAAM;IACN,OAAO;IACP,aAAa;;EAEf,MAAM,EAAE,MAAM,UAAU,OAAO,UAAU,aAAa,+BAA8B;EACpF,KAAK;IACH,MAAM;IACN,OAAO;IACP,aAAa;IACb,SAAS;;EAEX,gBAAgB;IACd,MAAM;IACN,aACE;;EAEJ,QAAQ;IACN,MAAM;IACN,OAAO;IACP,aAAa;;;AAIjB,IAAM,YAAY,CAAC,WAAqB;AACtC,MAAI,WAAW;AAAO,WAAO;AAC7B,MAAI,WAAW;AAAQ,WAAO,CAAC,UAAsB,QAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;AACtF,SAAO,CAAC,UAAqB;AAC3B,UAAM,KAAK,MAAM,gBAAgB,MAAM,YAAY,cAAc;AACjE,UAAM,KAAK,MAAM,cAAc,YAAY,KAAK,KAAK,MAAM,SAAS;AACpE,UAAM,QAAQ,MAAM,UAAU,UAAU,MAAM,OAAO,KAAK;AAC1D,UAAM,UAAU,MAAM,UAAU,aAAa;AAC7C,YAAQ,IACN,GAAG,MAAM,OAAO,IAAI,MAAM,MAAM,IAAI,MAAM,IAAI,IAAI,MAAM,MAAM,IAAI,EAAE,IAAI,MAAM,UAAU,KAAK,EAAE,GAAG,KAAK,GAAG,OAAO,EAAE;EAEvH;AACF;AAEA,IAAM,WAAW,CAAC,UAChB,OAAO,UAAU,WAAW,QAAQ;AAkBtC,IAAM,aAAa,OAAO,MAAc,QAA0C;AAChF,MAAI,SAAS,IAAI;AAAM,WAAO;AAC9B,QAAM,YAAY,gCAAgC,IAAI;AACtD,MAAI;AACF,UAAM,MAAO,MAAM,OAAO;AAC1B,QAAI,CAAC,IAAI;AAAa,YAAM,IAAI,MAAM,GAAG,SAAS,yBAAyB;AAC3E,WAAO,IAAI;EACb,SAAS,OAAO;AACd,UAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,UAAM,IAAI,MACR,wBAAwB,IAAI,MAAM,MAAM,0CAA0C,IAAI,GAAG;EAE7F;AACF;AAEA,IAAM,QAAQ,OACZ,QACA,QACA,WACsB;AACtB,QAAM,UAAU,MAAM,OAAO,OAAO,QAAQ;IAC1C,UAAU,OAAO;IACjB,MAAM,OAAO;IACb,OAAO,UAAU,OAAO,GAAG;GAC5B;AACD,QAAM,YAAY,MAAM,OAAO,SAAS,EAAE,MAAM,OAAO,MAAM,MAAM,OAAO,KAAI,CAAE;AAChF,UAAQ,IAAI,GAAG,OAAO,IAAI,sBAAsB,UAAU,GAAG,EAAE;AAC/D,UAAQ,IAAI,GAAG,OAAO,IAAI,gBAAgB,UAAU,GAAG,SAAS;AAChE,UAAQ,IACN,GAAG,OAAO,IAAI,WAAW,UAAU,GAAG,aAAa,OAAO,WAAW,qCAAqC,sCAAiC,GAAG;AAEhJ,aAAW,QAAQ,OAAO,SAAS,OAAO,KAAK,CAAA;AAAI,YAAQ,IAAI,GAAG,OAAO,IAAI,IAAI,IAAI,EAAE;AACvF,SAAO;AACT;AAEA,IAAM,cAAc,OAAO,YACzB,IAAI,QAAQ,CAAC,YAAW;AACtB,QAAM,OAAO,YAAW;AACtB,UAAM,QAAQ,WAAW,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAK,CAAE,CAAC;AACtD,YAAQ,CAAC;EACX;AACA,UAAQ,KAAK,UAAU,IAAI;AAC3B,UAAQ,KAAK,WAAW,IAAI;AAC9B,CAAC;AAGI,IAAM,eAAe,CAAC,YAAqC;EAChE,SAAS,aAAa,OAAO,IAAI;EACjC,SAAS,EAAE,GAAG,sBAAsB,GAAG,OAAO,QAAO;EACrD,MAAM,IAAI,QAAM;AACd,UAAM,MACJ,OAAO,cAAc,MAAM,OAAO,SAAU,SAAS,OAAO,GAAG,KAAK;AAEtE,QAAI,CAAC,CAAC,UAAU,QAAQ,KAAK,EAAE,SAAS,GAAG,GAAG;AAC5C,cAAQ,MAAM,0CAA0C,GAAG,GAAG;AAC9D,aAAO;IACT;AACA,UAAM,aAAa,SAAS,OAAO,MAAM;AACzC,QAAI,eAAe,QAAW;AAC5B,YAAM,SAAS,KAAK,MAAM,MAAM,SAAS,YAAY,MAAM,CAAC;AAC5D,YAAM,UAAuB,CAAA;AAC7B,UAAI;AACF,mBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,YAAY,CAAA,CAAE,GAAG;AACjE,gBAAM,OAAO,MAAM,WAAW,MAAM,MAAM;AAC1C,kBAAQ,KACN,MAAM,MAAM,MAAM,MAAM,WAAW,CAAA,GAAI;YACrC,MAAM,MAAM,QAAQ,KAAK;YACzB,MAAM,MAAM,QAAQ;YACpB,GAAI,MAAM,aAAa,SAAY,EAAE,UAAU,MAAM,SAAQ,IAAK,CAAA;YAClE,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAI,IAAK,CAAA;YACtD,KAAK,OAAO,OAAO;WACpB,CAAC;QAEN;MACF,SAAS,OAAO;AACd,cAAM,QAAQ,WAAW,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAK,CAAE,CAAC;AACtD,gBAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACpE,eAAO;MACT;AACA,aAAO,YAAY,OAAO;IAC5B;AACA,UAAM,OAAO,SAAS,OAAO,IAAI;AACjC,UAAM,WAAW,SAAS,OAAO,WAAW,CAAC,KAAK,QAAQ,IAAI;AAC9D,UAAM,OAAO,SAAS,OAAO,IAAI;AACjC,QAAI;AACJ,QAAI;AACF,kBAAY,MAAM,MAAM,QAAQ,QAAQ;QACtC,MAAM,SAAS,SAAY,OAAO,cAAc,OAAO,SAAS,MAAM,EAAE;QACxE,MAAM,SAAS,OAAO,IAAI,KAAK;QAC/B,GAAI,aAAa,SAAY,EAAE,SAAQ,IAAK,CAAA;QAC5C,GAAI,SAAS,SAAY,EAAE,KAAI,IAAK,CAAA;QACpC;OACD;IACH,SAAS,OAAO;AACd,cAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACpE,aAAO;IACT;AACA,WAAO,YAAY,CAAC,SAAS,CAAC;EAChC;;;;AG5RK,IAAM,eAAe;AAYrB,IAAMA,gBAAe,OAAO,UAA8B,CAAC,MAA4B;AAC5F,QAAM,EAAE,MAAM,MAAM,GAAG,KAAK,IAAI;AAChC,QAAM,UAAU,cAAc,IAAI;AAClC,QAAM,YAAY,MAAM,OAAO,SAAS;AAAA,IACtC,MAAM,QAAQ;AAAA,IACd,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,EACvC,CAAC;AACD,SAAO,EAAE,GAAG,WAAW,QAAQ;AACjC;AAEA,IAAM,OAAO,CAAC,UACZ,OAAO,UAAU,WAAW,QAAQ;AAG/B,IAAM,cAA2B;AAAA,EACtC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,SAAS;AAAA,IACP,OAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,IACA,mBAAmB;AAAA,MACjB,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,QAAQ,CAAC,QAAQ,WAAW;AAC1B,UAAM,QAAQ,KAAK,OAAO,KAAK;AAC/B,WAAO,cAAc;AAAA,MACnB,UAAU;AAAA,QACR,GAAI,QAAQ,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;AAAA,QACnC,GAAI,OAAO,iBAAiB,MAAM,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAAA,MACvE;AAAA,MACA,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,MACrE,GAAI,OAAO,SAAS,SAAY,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,MACzD,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,IAChD,CAAC;AAAA,EACH;AAAA,EACA,QAAQ,MAAM;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
- "names": ["createServer"]
7
- }