@crvouga/mockingbird-service-junction 3.3.0 → 3.3.1

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.
@@ -9,7 +9,7 @@ import {
9
9
  pullCorpus,
10
10
  resolveAdminPrefix,
11
11
  restoreClock
12
- } from "./chunk-PKEFSWT3.js";
12
+ } from "./chunk-7VCGZYMN.js";
13
13
  import {
14
14
  defaultCorpus
15
15
  } from "./chunk-2FZJPMTR.js";
@@ -1137,4 +1137,4 @@ export {
1137
1137
  createServer2 as createServer,
1138
1138
  serveTarget
1139
1139
  };
1140
- //# sourceMappingURL=chunk-YDXAOFS2.js.map
1140
+ //# sourceMappingURL=chunk-S2GN6HLD.js.map
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  runCli,
5
5
  serveCommand,
6
6
  serveTarget
7
- } from "./chunk-YDXAOFS2.js";
7
+ } from "./chunk-S2GN6HLD.js";
8
8
  import {
9
9
  DEFAULT_JUNCTION_BASE_URL,
10
10
  createRuntime,
@@ -12,7 +12,7 @@ import {
12
12
  isSandboxKey,
13
13
  pullCorpus,
14
14
  verifyAgainstReal
15
- } from "./chunk-PKEFSWT3.js";
15
+ } from "./chunk-7VCGZYMN.js";
16
16
  import {
17
17
  defaultCorpus
18
18
  } from "./chunk-2FZJPMTR.js";
@@ -194,13 +194,14 @@ var code = await runCli(
194
194
  if (values.json === true) {
195
195
  console.log(JSON.stringify(report, null, 2));
196
196
  } else {
197
+ if (report.blocked) console.error(`verify BLOCKED: ${report.blocked.message}`);
197
198
  for (const d of report.divergences) {
198
199
  console.log(`DIVERGED ${d.check} (${d.kind}${d.at ? ` at ${d.at}` : ""})`);
199
200
  console.log(` real: ${JSON.stringify(d.real)?.slice(0, 400)}`);
200
201
  console.log(` mock: ${JSON.stringify(d.mock)?.slice(0, 400)}`);
201
202
  }
202
203
  console.log(
203
- `verify: drift ${report.drift.stale}/${report.drift.checked} stale; scenario ${report.scenario.divergent}/${report.scenario.steps} divergent \u2014 ${report.ok ? "OK" : "DIVERGED"}`
204
+ `verify: drift ${report.drift.stale}/${report.drift.checked} stale; scenario ${report.scenario.divergent}/${report.scenario.steps} divergent \u2014 ${report.blocked ? "BLOCKED" : report.ok ? "OK" : "DIVERGED"}`
204
205
  );
205
206
  }
206
207
  return report.ok ? 0 : 1;
package/dist/cli.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/cli.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\n/// <reference types=\"node\" />\nimport { readFile, writeFile } from \"node:fs/promises\"\nimport { type CliValues, runCli, serveCommand } from \"@crvouga/mockingbird-adapter-node\"\nimport { defaultCorpus } from \"./corpus.js\"\nimport { DEFAULT_JUNCTION_BASE_URL, diffCorpus, isSandboxKey, pullCorpus } from \"./corpus-tools.js\"\nimport { createRuntime } from \"./runtime.js\"\nimport { parseSealedCorpus, type SealedCorpus } from \"./sealed-corpus.js\"\nimport { loadCorpus, serveTarget } from \"./server.js\"\nimport { verifyAgainstReal } from \"./verify.js\"\n\nconst asString = (value: string | boolean | undefined): string | undefined =>\n typeof value === \"string\" && value !== \"\" ? value : undefined\n\nconst realKeyOf = (values: CliValues): string | undefined =>\n asString(values[\"real-key\"]) ??\n asString(process.env.JUNCTION_API_KEY) ??\n asString(process.env.JUNCTION_API_KEY)\n\nconst readCorpus = async (source: string): Promise<SealedCorpus> =>\n source === \"default\"\n ? defaultCorpus\n : parseSealedCorpus(JSON.parse(await readFile(source, \"utf8\")))\n\nconst guardKey = (key: string | undefined, values: CliValues): string | undefined => {\n if (key === undefined) {\n console.error(\"missing --real-key (or env JUNCTION_API_KEY)\")\n return undefined\n }\n if (!isSandboxKey(key) && values[\"allow-any-key\"] !== true) {\n console.error(\n \"refusing a key that is not a sandbox team key (sk_us_\u2026 / sk_eu_\u2026); pass --allow-any-key to override\",\n )\n return undefined\n }\n return key\n}\n\nconst REAL_OPTIONS = {\n \"real-key\": {\n type: \"string\",\n value: \"<key>\",\n description: \"Junction API key (env JUNCTION_API_KEY)\",\n },\n \"real-url\": {\n type: \"string\",\n value: \"<url>\",\n description: \"Junction API base URL\",\n default: DEFAULT_JUNCTION_BASE_URL,\n },\n \"allow-any-key\": {\n type: \"boolean\",\n description: \"Allow a key that is not a sandbox team key\",\n },\n} as const\n\nconst code = await runCli(\n {\n bin: \"mockingbird-junction\",\n description: \"stateful Junction (Vital) API mock\",\n commands: {\n serve: serveCommand(serveTarget),\n\n \"corpus pull\": {\n summary: \"Record a corpus from a real Junction team (read-only GETs)\",\n usage: \"mockingbird-junction corpus pull --out <file> [--zip 10001,94105] [--base <file>]\",\n options: {\n ...REAL_OPTIONS,\n out: { type: \"string\", value: \"<file>\", description: \"Where to write the corpus\" },\n zip: {\n type: \"string\",\n value: \"<zip,zip,\u2026>\",\n description: \"ZIPs to record coverage for (default: the shipped set)\",\n },\n base: {\n type: \"string\",\n value: \"<file|default>\",\n description: \"Only refresh --zip on top of this corpus\",\n },\n \"coverage-only\": {\n type: \"boolean\",\n description: \"Skip the team's catalog and lab accounts\",\n },\n },\n async run(values) {\n const key = guardKey(realKeyOf(values), values)\n if (key === undefined) return 2\n const out = asString(values.out)\n if (out === undefined) {\n console.error(\"missing --out <file>\")\n return 2\n }\n const zips = asString(values.zip)\n ?.split(\",\")\n .map((zip) => zip.trim())\n .filter(Boolean)\n if (zips?.some((zip) => !/^\\d{5}$/.test(zip))) {\n console.error(\"--zip takes comma-separated 5-digit ZIPs\")\n return 2\n }\n const baseSource = asString(values.base)\n const corpus = await pullCorpus({\n apiKey: key,\n baseUrl: asString(values[\"real-url\"]) ?? DEFAULT_JUNCTION_BASE_URL,\n ...(zips ? { zips } : {}),\n ...(baseSource ? { base: await readCorpus(baseSource) } : {}),\n coverageOnly: values[\"coverage-only\"] === true,\n onProgress: (message) => console.log(`corpus pull: ${message}`),\n })\n await writeFile(out, `${JSON.stringify(corpus, null, 2)}\\n`)\n console.log(\n `corpus pull: wrote ${out} \u2014 ${Object.keys(corpus.observations).length} observations, ${corpus.catalog.labTests.length} lab tests, ${corpus.labAccounts.length} lab accounts, fingerprint ${corpus.fingerprint?.slice(0, 12)}`,\n )\n return 0\n },\n },\n\n \"corpus diff\": {\n summary: \"Show what changed between two corpora (exit 1 when they differ)\",\n usage: \"mockingbird-junction corpus diff <before|default> <after|default> [--json]\",\n options: { json: { type: \"boolean\", description: \"Print the diff as JSON\" } },\n async run(values, positionals) {\n const [beforePath, afterPath] = positionals\n if (beforePath === undefined || afterPath === undefined) {\n console.error(\"usage: mockingbird-junction corpus diff <before> <after>\")\n return 2\n }\n const diff = diffCorpus(await readCorpus(beforePath), await readCorpus(afterPath))\n if (values.json === true) {\n console.log(JSON.stringify(diff, null, 2))\n return diff.identical ? 0 : 1\n }\n if (diff.identical) {\n console.log(\"corpora are identical\")\n return 0\n }\n const section = (\n title: string,\n d: { added: string[]; removed: string[]; changed?: string[] },\n ) => {\n const total = d.added.length + d.removed.length + (d.changed?.length ?? 0)\n if (total === 0) return\n console.log(`${title}:`)\n for (const id of d.added) console.log(` + ${id}`)\n for (const id of d.removed) console.log(` - ${id}`)\n for (const id of d.changed ?? []) console.log(` ~ ${id}`)\n }\n section(\"ZIPs\", diff.zips)\n section(\"lab tests\", diff.labTests)\n section(\"lab accounts\", diff.labAccounts)\n const o = diff.observations\n console.log(\n `observations: +${o.added.length} -${o.removed.length} ~${o.changed.length} (--json lists them)`,\n )\n return 1\n },\n },\n\n verify: {\n summary: \"Replay the corpus and a stateful scenario against real Junction and the mock\",\n usage: \"mockingbird-junction verify --real-key <sk_us_\u2026> [--corpus <file>] [--orders]\",\n options: {\n ...REAL_OPTIONS,\n corpus: {\n type: \"string\",\n value: \"<default|file>\",\n description: \"Corpus the mock serves and drift is checked against\",\n default: \"default\",\n },\n sample: {\n type: \"string\",\n value: \"<n>\",\n description: \"Re-fetch at most n recorded observations (default: all)\",\n },\n \"skip-drift\": { type: \"boolean\", description: \"Only run the stateful scenario\" },\n orders: {\n type: \"boolean\",\n description: \"Also place and cancel an order on the real team\",\n },\n json: { type: \"boolean\", description: \"Print the report as JSON\" },\n },\n async run(values) {\n const key = guardKey(realKeyOf(values), values)\n if (key === undefined) return 2\n const corpus = await loadCorpus(asString(values.corpus) ?? \"default\")\n if (!corpus) {\n console.error(\"verify needs a corpus (--corpus default or a file)\")\n return 2\n }\n const sample = asString(values.sample)\n const report = await verifyAgainstReal({\n realKey: key,\n realUrl: asString(values[\"real-url\"]) ?? DEFAULT_JUNCTION_BASE_URL,\n mock: createRuntime({ corpus }),\n corpus,\n ...(sample !== undefined ? { sample: Number.parseInt(sample, 10) } : {}),\n skipDrift: values[\"skip-drift\"] === true,\n orders: values.orders === true,\n ...(values.json === true\n ? {}\n : { onProgress: (message: string) => console.log(`verify: ${message}`) }),\n })\n if (values.json === true) {\n console.log(JSON.stringify(report, null, 2))\n } else {\n for (const d of report.divergences) {\n console.log(`DIVERGED ${d.check} (${d.kind}${d.at ? ` at ${d.at}` : \"\"})`)\n console.log(` real: ${JSON.stringify(d.real)?.slice(0, 400)}`)\n console.log(` mock: ${JSON.stringify(d.mock)?.slice(0, 400)}`)\n }\n console.log(\n `verify: drift ${report.drift.stale}/${report.drift.checked} stale; scenario ${report.scenario.divergent}/${report.scenario.steps} divergent \u2014 ${report.ok ? \"OK\" : \"DIVERGED\"}`,\n )\n }\n return report.ok ? 0 : 1\n },\n },\n },\n },\n process.argv.slice(2),\n)\nif (code !== 0) process.exitCode = code\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["#!/usr/bin/env node\n/// <reference types=\"node\" />\nimport { readFile, writeFile } from \"node:fs/promises\"\nimport { type CliValues, runCli, serveCommand } from \"@crvouga/mockingbird-adapter-node\"\nimport { defaultCorpus } from \"./corpus.js\"\nimport { DEFAULT_JUNCTION_BASE_URL, diffCorpus, isSandboxKey, pullCorpus } from \"./corpus-tools.js\"\nimport { createRuntime } from \"./runtime.js\"\nimport { parseSealedCorpus, type SealedCorpus } from \"./sealed-corpus.js\"\nimport { loadCorpus, serveTarget } from \"./server.js\"\nimport { verifyAgainstReal } from \"./verify.js\"\n\nconst asString = (value: string | boolean | undefined): string | undefined =>\n typeof value === \"string\" && value !== \"\" ? value : undefined\n\nconst realKeyOf = (values: CliValues): string | undefined =>\n asString(values[\"real-key\"]) ??\n asString(process.env.JUNCTION_API_KEY) ??\n asString(process.env.JUNCTION_API_KEY)\n\nconst readCorpus = async (source: string): Promise<SealedCorpus> =>\n source === \"default\"\n ? defaultCorpus\n : parseSealedCorpus(JSON.parse(await readFile(source, \"utf8\")))\n\nconst guardKey = (key: string | undefined, values: CliValues): string | undefined => {\n if (key === undefined) {\n console.error(\"missing --real-key (or env JUNCTION_API_KEY)\")\n return undefined\n }\n if (!isSandboxKey(key) && values[\"allow-any-key\"] !== true) {\n console.error(\n \"refusing a key that is not a sandbox team key (sk_us_\u2026 / sk_eu_\u2026); pass --allow-any-key to override\",\n )\n return undefined\n }\n return key\n}\n\nconst REAL_OPTIONS = {\n \"real-key\": {\n type: \"string\",\n value: \"<key>\",\n description: \"Junction API key (env JUNCTION_API_KEY)\",\n },\n \"real-url\": {\n type: \"string\",\n value: \"<url>\",\n description: \"Junction API base URL\",\n default: DEFAULT_JUNCTION_BASE_URL,\n },\n \"allow-any-key\": {\n type: \"boolean\",\n description: \"Allow a key that is not a sandbox team key\",\n },\n} as const\n\nconst code = await runCli(\n {\n bin: \"mockingbird-junction\",\n description: \"stateful Junction (Vital) API mock\",\n commands: {\n serve: serveCommand(serveTarget),\n\n \"corpus pull\": {\n summary: \"Record a corpus from a real Junction team (read-only GETs)\",\n usage: \"mockingbird-junction corpus pull --out <file> [--zip 10001,94105] [--base <file>]\",\n options: {\n ...REAL_OPTIONS,\n out: { type: \"string\", value: \"<file>\", description: \"Where to write the corpus\" },\n zip: {\n type: \"string\",\n value: \"<zip,zip,\u2026>\",\n description: \"ZIPs to record coverage for (default: the shipped set)\",\n },\n base: {\n type: \"string\",\n value: \"<file|default>\",\n description: \"Only refresh --zip on top of this corpus\",\n },\n \"coverage-only\": {\n type: \"boolean\",\n description: \"Skip the team's catalog and lab accounts\",\n },\n },\n async run(values) {\n const key = guardKey(realKeyOf(values), values)\n if (key === undefined) return 2\n const out = asString(values.out)\n if (out === undefined) {\n console.error(\"missing --out <file>\")\n return 2\n }\n const zips = asString(values.zip)\n ?.split(\",\")\n .map((zip) => zip.trim())\n .filter(Boolean)\n if (zips?.some((zip) => !/^\\d{5}$/.test(zip))) {\n console.error(\"--zip takes comma-separated 5-digit ZIPs\")\n return 2\n }\n const baseSource = asString(values.base)\n const corpus = await pullCorpus({\n apiKey: key,\n baseUrl: asString(values[\"real-url\"]) ?? DEFAULT_JUNCTION_BASE_URL,\n ...(zips ? { zips } : {}),\n ...(baseSource ? { base: await readCorpus(baseSource) } : {}),\n coverageOnly: values[\"coverage-only\"] === true,\n onProgress: (message) => console.log(`corpus pull: ${message}`),\n })\n await writeFile(out, `${JSON.stringify(corpus, null, 2)}\\n`)\n console.log(\n `corpus pull: wrote ${out} \u2014 ${Object.keys(corpus.observations).length} observations, ${corpus.catalog.labTests.length} lab tests, ${corpus.labAccounts.length} lab accounts, fingerprint ${corpus.fingerprint?.slice(0, 12)}`,\n )\n return 0\n },\n },\n\n \"corpus diff\": {\n summary: \"Show what changed between two corpora (exit 1 when they differ)\",\n usage: \"mockingbird-junction corpus diff <before|default> <after|default> [--json]\",\n options: { json: { type: \"boolean\", description: \"Print the diff as JSON\" } },\n async run(values, positionals) {\n const [beforePath, afterPath] = positionals\n if (beforePath === undefined || afterPath === undefined) {\n console.error(\"usage: mockingbird-junction corpus diff <before> <after>\")\n return 2\n }\n const diff = diffCorpus(await readCorpus(beforePath), await readCorpus(afterPath))\n if (values.json === true) {\n console.log(JSON.stringify(diff, null, 2))\n return diff.identical ? 0 : 1\n }\n if (diff.identical) {\n console.log(\"corpora are identical\")\n return 0\n }\n const section = (\n title: string,\n d: { added: string[]; removed: string[]; changed?: string[] },\n ) => {\n const total = d.added.length + d.removed.length + (d.changed?.length ?? 0)\n if (total === 0) return\n console.log(`${title}:`)\n for (const id of d.added) console.log(` + ${id}`)\n for (const id of d.removed) console.log(` - ${id}`)\n for (const id of d.changed ?? []) console.log(` ~ ${id}`)\n }\n section(\"ZIPs\", diff.zips)\n section(\"lab tests\", diff.labTests)\n section(\"lab accounts\", diff.labAccounts)\n const o = diff.observations\n console.log(\n `observations: +${o.added.length} -${o.removed.length} ~${o.changed.length} (--json lists them)`,\n )\n return 1\n },\n },\n\n verify: {\n summary: \"Replay the corpus and a stateful scenario against real Junction and the mock\",\n usage: \"mockingbird-junction verify --real-key <sk_us_\u2026> [--corpus <file>] [--orders]\",\n options: {\n ...REAL_OPTIONS,\n corpus: {\n type: \"string\",\n value: \"<default|file>\",\n description: \"Corpus the mock serves and drift is checked against\",\n default: \"default\",\n },\n sample: {\n type: \"string\",\n value: \"<n>\",\n description: \"Re-fetch at most n recorded observations (default: all)\",\n },\n \"skip-drift\": { type: \"boolean\", description: \"Only run the stateful scenario\" },\n orders: {\n type: \"boolean\",\n description: \"Also place and cancel an order on the real team\",\n },\n json: { type: \"boolean\", description: \"Print the report as JSON\" },\n },\n async run(values) {\n const key = guardKey(realKeyOf(values), values)\n if (key === undefined) return 2\n const corpus = await loadCorpus(asString(values.corpus) ?? \"default\")\n if (!corpus) {\n console.error(\"verify needs a corpus (--corpus default or a file)\")\n return 2\n }\n const sample = asString(values.sample)\n const report = await verifyAgainstReal({\n realKey: key,\n realUrl: asString(values[\"real-url\"]) ?? DEFAULT_JUNCTION_BASE_URL,\n mock: createRuntime({ corpus }),\n corpus,\n ...(sample !== undefined ? { sample: Number.parseInt(sample, 10) } : {}),\n skipDrift: values[\"skip-drift\"] === true,\n orders: values.orders === true,\n ...(values.json === true\n ? {}\n : { onProgress: (message: string) => console.log(`verify: ${message}`) }),\n })\n if (values.json === true) {\n console.log(JSON.stringify(report, null, 2))\n } else {\n if (report.blocked) console.error(`verify BLOCKED: ${report.blocked.message}`)\n for (const d of report.divergences) {\n console.log(`DIVERGED ${d.check} (${d.kind}${d.at ? ` at ${d.at}` : \"\"})`)\n console.log(` real: ${JSON.stringify(d.real)?.slice(0, 400)}`)\n console.log(` mock: ${JSON.stringify(d.mock)?.slice(0, 400)}`)\n }\n console.log(\n `verify: drift ${report.drift.stale}/${report.drift.checked} stale; scenario ${report.scenario.divergent}/${report.scenario.steps} divergent \u2014 ${report.blocked ? \"BLOCKED\" : report.ok ? \"OK\" : \"DIVERGED\"}`,\n )\n }\n return report.ok ? 0 : 1\n },\n },\n },\n },\n process.argv.slice(2),\n)\nif (code !== 0) process.exitCode = code\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.d.ts CHANGED
@@ -1949,6 +1949,12 @@ type VerifyReport = {
1949
1949
  divergent: number;
1950
1950
  };
1951
1951
  divergences: Divergence[];
1952
+ /** Live access is blocked; this is not emulator or corpus drift. */
1953
+ blocked?: {
1954
+ status: number;
1955
+ reason: "authentication" | "payment-required" | "access-denied";
1956
+ message: string;
1957
+ };
1952
1958
  };
1953
1959
  declare const verifyAgainstReal: (options: VerifyOptions) => Promise<VerifyReport>;
1954
1960
 
package/dist/index.js CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  supportedOperationIds,
54
54
  verifyAgainstReal,
55
55
  verifySvix
56
- } from "./chunk-PKEFSWT3.js";
56
+ } from "./chunk-7VCGZYMN.js";
57
57
  import {
58
58
  SEALED_CORPUS_VERSION,
59
59
  SUPPORTED_SEALED_CORPUS_VERSIONS,
package/dist/server.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  createServer,
4
4
  loadCorpus,
5
5
  serveTarget
6
- } from "./chunk-YDXAOFS2.js";
7
- import "./chunk-PKEFSWT3.js";
6
+ } from "./chunk-S2GN6HLD.js";
7
+ import "./chunk-7VCGZYMN.js";
8
8
  import "./chunk-2FZJPMTR.js";
9
9
  import "./chunk-ISDNA2TU.js";
10
10
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crvouga/mockingbird-service-junction",
3
- "version": "3.3.0",
3
+ "version": "3.3.1",
4
4
  "description": "Stateful emulator of the Junction (Vital) user API driven by its OpenAPI contract and verified by differential property tests against the Junction sandbox.",
5
5
  "license": "MIT",
6
6
  "type": "module",