@crvouga/mockingbird-service-paddle 0.1.0 → 0.2.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.
@@ -540,10 +540,10 @@ var OpenAPIReferenceError = class extends Error {
540
540
  };
541
541
  var unescapePointer = (segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~");
542
542
  var isReference = (value) => typeof value === "object" && value !== null && typeof value.$ref === "string";
543
- var resolveRef = (document2, ref) => {
543
+ var resolveRef = (document3, ref) => {
544
544
  if (!ref.startsWith("#/"))
545
545
  throw new OpenAPIReferenceError(ref);
546
- let cursor = document2;
546
+ let cursor = document3;
547
547
  for (const raw of ref.slice(2).split("/")) {
548
548
  const segment = unescapePointer(raw);
549
549
  if (typeof cursor !== "object" || cursor === null || !(segment in cursor)) {
@@ -555,14 +555,14 @@ var resolveRef = (document2, ref) => {
555
555
  throw new OpenAPIReferenceError(ref);
556
556
  return cursor;
557
557
  };
558
- var deref = (document2, value) => {
558
+ var deref = (document3, value) => {
559
559
  let current = value;
560
560
  const seen = /* @__PURE__ */ new Set();
561
561
  while (isReference(current)) {
562
562
  if (seen.has(current.$ref))
563
563
  throw new OpenAPIReferenceError(`${current.$ref} (cycle)`);
564
564
  seen.add(current.$ref);
565
- current = resolveRef(document2, current.$ref);
565
+ current = resolveRef(document3, current.$ref);
566
566
  }
567
567
  return current;
568
568
  };
@@ -580,36 +580,36 @@ var HTTP_METHODS = [
580
580
  ];
581
581
 
582
582
  // ../../openapi/core/dist/document.js
583
- var mergeParameters = (document2, item, own) => {
583
+ var mergeParameters = (document3, item, own) => {
584
584
  const merged = /* @__PURE__ */ new Map();
585
585
  for (const raw of item.parameters ?? []) {
586
- const parameter = deref(document2, raw);
586
+ const parameter = deref(document3, raw);
587
587
  merged.set(`${parameter.in}:${parameter.name}`, parameter);
588
588
  }
589
589
  for (const raw of own ?? []) {
590
- const parameter = deref(document2, raw);
590
+ const parameter = deref(document3, raw);
591
591
  merged.set(`${parameter.in}:${parameter.name}`, parameter);
592
592
  }
593
593
  return [...merged.values()];
594
594
  };
595
- var listOperations = (document2) => {
595
+ var listOperations = (document3) => {
596
596
  const operations = [];
597
- for (const [path, item] of Object.entries(document2.paths)) {
597
+ for (const [path, item] of Object.entries(document3.paths)) {
598
598
  for (const method of HTTP_METHODS) {
599
599
  const operation = item[method];
600
600
  if (operation?.operationId === void 0)
601
601
  continue;
602
602
  const responses = {};
603
603
  for (const [status, response] of Object.entries(operation.responses)) {
604
- responses[status] = deref(document2, response);
604
+ responses[status] = deref(document3, response);
605
605
  }
606
606
  operations.push({
607
607
  operationId: operation.operationId,
608
608
  method,
609
609
  path,
610
610
  operation,
611
- parameters: mergeParameters(document2, item, operation.parameters),
612
- requestBody: operation.requestBody === void 0 ? void 0 : deref(document2, operation.requestBody),
611
+ parameters: mergeParameters(document3, item, operation.parameters),
612
+ requestBody: operation.requestBody === void 0 ? void 0 : deref(document3, operation.requestBody),
613
613
  responses
614
614
  });
615
615
  }
@@ -618,7 +618,7 @@ var listOperations = (document2) => {
618
618
  };
619
619
 
620
620
  // ../../openapi/core/dist/schema.js
621
- var resolveSchema = (document2, schema) => {
621
+ var resolveSchema = (document3, schema) => {
622
622
  let current = schema;
623
623
  const seen = /* @__PURE__ */ new Set();
624
624
  while (typeof current.$ref === "string") {
@@ -627,7 +627,7 @@ var resolveSchema = (document2, schema) => {
627
627
  break;
628
628
  seen.add(ref);
629
629
  const { $ref: _ignored, ...siblings } = current;
630
- const target = resolveRef(document2, ref);
630
+ const target = resolveRef(document3, ref);
631
631
  current = { ...target, ...siblings };
632
632
  }
633
633
  if (current.nullable === true) {
@@ -698,9 +698,9 @@ var FORMAT_PATTERNS = {
698
698
  ipv4: /^(25[0-5]|2[0-4]\d|1?\d?\d)(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/
699
699
  };
700
700
  var graphemeLength = (value) => [...value].length;
701
- var validateValue = (document2, schema, value, path = []) => {
701
+ var validateValue = (document3, schema, value, path = []) => {
702
702
  const errors = [];
703
- const s = resolveSchema(document2, schema);
703
+ const s = resolveSchema(document3, schema);
704
704
  const fail2 = (message) => errors.push({ path, message });
705
705
  const actual = jsonTypeOf(value);
706
706
  if (actual === "undefined") {
@@ -762,7 +762,7 @@ var validateValue = (document2, schema, value, path = []) => {
762
762
  value.forEach((item, i) => {
763
763
  const itemSchema = s.prefixItems?.[i] ?? s.items;
764
764
  if (itemSchema)
765
- errors.push(...validateValue(document2, itemSchema, item, [...path, i]));
765
+ errors.push(...validateValue(document3, itemSchema, item, [...path, i]));
766
766
  });
767
767
  }
768
768
  if (actual === "object") {
@@ -778,16 +778,16 @@ var validateValue = (document2, schema, value, path = []) => {
778
778
  for (const key of keys) {
779
779
  const property = s.properties?.[key];
780
780
  if (property) {
781
- errors.push(...validateValue(document2, property, record[key], [...path, key]));
781
+ errors.push(...validateValue(document3, property, record[key], [...path, key]));
782
782
  continue;
783
783
  }
784
784
  if (s.additionalProperties === false)
785
785
  fail2(`unexpected property ${key}`);
786
786
  else if (typeof s.additionalProperties === "object") {
787
- errors.push(...validateValue(document2, s.additionalProperties, record[key], [...path, key]));
787
+ errors.push(...validateValue(document3, s.additionalProperties, record[key], [...path, key]));
788
788
  }
789
789
  if (s.propertyNames) {
790
- const nameErrors = validateValue(document2, s.propertyNames, key, [...path, key]);
790
+ const nameErrors = validateValue(document3, s.propertyNames, key, [...path, key]);
791
791
  if (nameErrors.length > 0)
792
792
  fail2(`property name ${key} is invalid: ${nameErrors[0]?.message}`);
793
793
  }
@@ -795,15 +795,15 @@ var validateValue = (document2, schema, value, path = []) => {
795
795
  }
796
796
  if (s.allOf)
797
797
  for (const branch of s.allOf)
798
- errors.push(...validateValue(document2, branch, value, path));
799
- if (s.anyOf && !s.anyOf.some((branch) => validateValue(document2, branch, value).length === 0))
798
+ errors.push(...validateValue(document3, branch, value, path));
799
+ if (s.anyOf && !s.anyOf.some((branch) => validateValue(document3, branch, value).length === 0))
800
800
  fail2("matches no anyOf branch");
801
801
  if (s.oneOf) {
802
- const matches2 = s.oneOf.filter((branch) => validateValue(document2, branch, value).length === 0).length;
802
+ const matches2 = s.oneOf.filter((branch) => validateValue(document3, branch, value).length === 0).length;
803
803
  if (matches2 !== 1)
804
804
  fail2(`matches ${matches2} oneOf branches, expected exactly 1`);
805
805
  }
806
- if (s.not && validateValue(document2, s.not, value).length === 0)
806
+ if (s.not && validateValue(document3, s.not, value).length === 0)
807
807
  fail2("matches forbidden `not` schema");
808
808
  return errors;
809
809
  };
@@ -1314,6 +1314,1232 @@ var clearNamespace = (sqlite, namespace) => {
1314
1314
  });
1315
1315
  };
1316
1316
 
1317
+ // ../../ui/dist/reset.js
1318
+ var CSS_RESET = `*,
1319
+ *::before,
1320
+ *::after {
1321
+ box-sizing: border-box;
1322
+ margin: 0;
1323
+ padding: 0;
1324
+ }
1325
+
1326
+ * {
1327
+ scrollbar-width: thin;
1328
+ scrollbar-color: color-mix(in srgb, CanvasText 35%, Canvas) Canvas;
1329
+ }
1330
+
1331
+ *::-webkit-scrollbar {
1332
+ width: 12px;
1333
+ height: 12px;
1334
+ }
1335
+
1336
+ *::-webkit-scrollbar-track,
1337
+ *::-webkit-scrollbar-corner {
1338
+ background: Canvas;
1339
+ }
1340
+
1341
+ *::-webkit-scrollbar-thumb {
1342
+ background: color-mix(in srgb, CanvasText 35%, Canvas);
1343
+ border: 3px solid Canvas;
1344
+ border-radius: 999px;
1345
+ }
1346
+
1347
+ html {
1348
+ hanging-punctuation: first allow-end last;
1349
+ -webkit-text-size-adjust: none;
1350
+ text-size-adjust: none;
1351
+ tab-size: 4;
1352
+ font-family:
1353
+ ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI Variable", "Segoe UI",
1354
+ "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
1355
+ font-size: 16px;
1356
+ line-height: 1.5;
1357
+ -webkit-font-smoothing: antialiased;
1358
+ -moz-osx-font-smoothing: grayscale;
1359
+ text-rendering: optimizeLegibility;
1360
+ -webkit-tap-highlight-color: transparent;
1361
+ scroll-behavior: smooth;
1362
+ background: Canvas;
1363
+ color: CanvasText;
1364
+ }
1365
+
1366
+ body {
1367
+ min-height: 100svh;
1368
+ line-height: 1.5;
1369
+ background: Canvas;
1370
+ color: CanvasText;
1371
+ }
1372
+
1373
+ h1 {
1374
+ font-size: 2em;
1375
+ }
1376
+
1377
+ h2 {
1378
+ font-size: 1.5em;
1379
+ }
1380
+
1381
+ h3 {
1382
+ font-size: 1.17em;
1383
+ }
1384
+
1385
+ h4 {
1386
+ font-size: 1em;
1387
+ }
1388
+
1389
+ h5 {
1390
+ font-size: 0.83em;
1391
+ }
1392
+
1393
+ h6 {
1394
+ font-size: 0.67em;
1395
+ }
1396
+
1397
+ h1,
1398
+ h2,
1399
+ h3,
1400
+ h4,
1401
+ h5,
1402
+ h6 {
1403
+ font-weight: 700;
1404
+ line-height: 1.2;
1405
+ text-wrap: balance;
1406
+ overflow-wrap: break-word;
1407
+ }
1408
+
1409
+ p,
1410
+ li,
1411
+ figcaption,
1412
+ dd,
1413
+ dt,
1414
+ blockquote {
1415
+ overflow-wrap: break-word;
1416
+ }
1417
+
1418
+ p,
1419
+ li,
1420
+ figcaption,
1421
+ blockquote {
1422
+ text-wrap: pretty;
1423
+ }
1424
+
1425
+ ul,
1426
+ ol,
1427
+ menu {
1428
+ list-style: none;
1429
+ }
1430
+
1431
+ a {
1432
+ color: inherit;
1433
+ text-decoration: underline;
1434
+ text-decoration-thickness: 1px;
1435
+ text-underline-offset: 0.15em;
1436
+ text-decoration-skip-ink: auto;
1437
+ }
1438
+
1439
+ b,
1440
+ strong {
1441
+ font-weight: 700;
1442
+ }
1443
+
1444
+ small {
1445
+ font-size: 0.875em;
1446
+ }
1447
+
1448
+ code,
1449
+ kbd,
1450
+ samp,
1451
+ pre {
1452
+ font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
1453
+ font-size: 1em;
1454
+ }
1455
+
1456
+ sub,
1457
+ sup {
1458
+ font-size: 75%;
1459
+ line-height: 0;
1460
+ position: relative;
1461
+ vertical-align: baseline;
1462
+ }
1463
+
1464
+ sub {
1465
+ bottom: -0.25em;
1466
+ }
1467
+
1468
+ sup {
1469
+ top: -0.5em;
1470
+ }
1471
+
1472
+ abbr[title] {
1473
+ text-decoration: underline dotted;
1474
+ text-underline-offset: 0.15em;
1475
+ }
1476
+
1477
+ mark {
1478
+ background: Mark;
1479
+ color: MarkText;
1480
+ }
1481
+
1482
+ hr {
1483
+ height: 0;
1484
+ border: 0;
1485
+ border-top: 1px solid color-mix(in srgb, CanvasText 20%, transparent);
1486
+ color: inherit;
1487
+ }
1488
+
1489
+ img,
1490
+ picture,
1491
+ video,
1492
+ canvas {
1493
+ display: block;
1494
+ max-width: 100%;
1495
+ }
1496
+
1497
+ img,
1498
+ video {
1499
+ height: auto;
1500
+ }
1501
+
1502
+ svg {
1503
+ overflow: hidden;
1504
+ }
1505
+
1506
+ iframe {
1507
+ border: 0;
1508
+ max-width: 100%;
1509
+ }
1510
+
1511
+ table {
1512
+ border-collapse: collapse;
1513
+ border-spacing: 0;
1514
+ }
1515
+
1516
+ fieldset {
1517
+ border: 0;
1518
+ min-inline-size: 0;
1519
+ }
1520
+
1521
+ legend {
1522
+ padding: 0;
1523
+ }
1524
+
1525
+ button,
1526
+ input,
1527
+ select,
1528
+ textarea,
1529
+ optgroup {
1530
+ font: inherit;
1531
+ letter-spacing: inherit;
1532
+ color: inherit;
1533
+ margin: 0;
1534
+ vertical-align: middle;
1535
+ }
1536
+
1537
+ button,
1538
+ input[type="button"],
1539
+ input[type="submit"],
1540
+ input[type="reset"] {
1541
+ appearance: none;
1542
+ background: none;
1543
+ border: 0;
1544
+ padding: 0;
1545
+ cursor: pointer;
1546
+ text-align: center;
1547
+ }
1548
+
1549
+ input,
1550
+ textarea,
1551
+ select {
1552
+ background-color: Canvas;
1553
+ border: 1px solid color-mix(in srgb, CanvasText 28%, transparent);
1554
+ border-radius: 0;
1555
+ padding: 0.5em 0.65em;
1556
+ }
1557
+
1558
+ input[type="checkbox"],
1559
+ input[type="radio"],
1560
+ input[type="range"],
1561
+ input[type="file"],
1562
+ input[type="color"],
1563
+ input[type="button"],
1564
+ input[type="submit"],
1565
+ input[type="reset"],
1566
+ input[type="image"],
1567
+ input[type="hidden"] {
1568
+ background: none;
1569
+ border: 0;
1570
+ padding: 0;
1571
+ border-radius: 0;
1572
+ }
1573
+
1574
+ input[type="checkbox"],
1575
+ input[type="radio"] {
1576
+ accent-color: CanvasText;
1577
+ }
1578
+
1579
+ input[type="search"] {
1580
+ appearance: none;
1581
+ background-color: Canvas;
1582
+ border: 1px solid color-mix(in srgb, CanvasText 28%, transparent);
1583
+ }
1584
+
1585
+ input[type="search"]::-webkit-search-decoration,
1586
+ input[type="search"]::-webkit-search-cancel-button,
1587
+ input[type="search"]::-webkit-search-results-button,
1588
+ input[type="search"]::-webkit-search-results-decoration {
1589
+ -webkit-appearance: none;
1590
+ display: none;
1591
+ }
1592
+
1593
+ input[type="number"] {
1594
+ appearance: textfield;
1595
+ background-color: Canvas;
1596
+ border: 1px solid color-mix(in srgb, CanvasText 28%, transparent);
1597
+ }
1598
+
1599
+ input[type="number"]::-webkit-inner-spin-button,
1600
+ input[type="number"]::-webkit-outer-spin-button {
1601
+ -webkit-appearance: none;
1602
+ margin: 0;
1603
+ }
1604
+
1605
+ textarea {
1606
+ resize: vertical;
1607
+ }
1608
+
1609
+ ::placeholder {
1610
+ opacity: 1;
1611
+ color: color-mix(in srgb, CanvasText 45%, transparent);
1612
+ }
1613
+
1614
+ :focus-visible {
1615
+ outline: 2px solid CanvasText;
1616
+ outline-offset: 2px;
1617
+ }
1618
+
1619
+ :focus:not(:focus-visible) {
1620
+ outline: none;
1621
+ }
1622
+
1623
+ :disabled,
1624
+ [disabled] {
1625
+ cursor: default;
1626
+ opacity: 0.6;
1627
+ }
1628
+
1629
+ label,
1630
+ summary,
1631
+ select,
1632
+ [role="button"] {
1633
+ cursor: pointer;
1634
+ }
1635
+
1636
+ summary {
1637
+ display: list-item;
1638
+ }
1639
+
1640
+ details {
1641
+ display: block;
1642
+ }
1643
+
1644
+ dialog {
1645
+ margin: auto;
1646
+ padding: 1rem;
1647
+ border: 1px solid color-mix(in srgb, CanvasText 20%, transparent);
1648
+ background: Canvas;
1649
+ color: CanvasText;
1650
+ max-width: calc(100vw - 2rem);
1651
+ max-height: calc(100svh - 2rem);
1652
+ }
1653
+
1654
+ dialog:not([open]) {
1655
+ display: none;
1656
+ }
1657
+
1658
+ ::backdrop {
1659
+ background: color-mix(in srgb, CanvasText 40%, transparent);
1660
+ }
1661
+
1662
+ [hidden] {
1663
+ display: none !important;
1664
+ }
1665
+
1666
+ ::selection {
1667
+ background: Highlight;
1668
+ color: HighlightText;
1669
+ }
1670
+
1671
+ @media (prefers-reduced-motion: reduce) {
1672
+ *,
1673
+ *::before,
1674
+ *::after {
1675
+ animation-duration: 0.01ms !important;
1676
+ animation-iteration-count: 1 !important;
1677
+ transition-duration: 0.01ms !important;
1678
+ scroll-behavior: auto !important;
1679
+ }
1680
+ }
1681
+
1682
+ @media (pointer: coarse) {
1683
+ input,
1684
+ select,
1685
+ textarea {
1686
+ font-size: max(16px, 1em);
1687
+ }
1688
+ }`;
1689
+
1690
+ // ../core/dist/admin-client.js
1691
+ function isRecord2(value) {
1692
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1693
+ }
1694
+ function mountAdminBrand(doc, host, service, catalog) {
1695
+ const clip = (value, max) => {
1696
+ if (typeof value !== "string")
1697
+ return null;
1698
+ const trimmed = value.trim();
1699
+ if (trimmed === "")
1700
+ return null;
1701
+ return trimmed.length > max ? trimmed.slice(0, max) : trimmed;
1702
+ };
1703
+ const httpUrl = (value) => {
1704
+ if (typeof value !== "string" || value.length > 2e3)
1705
+ return null;
1706
+ try {
1707
+ const url = new URL(value);
1708
+ if (url.protocol !== "https:" && url.protocol !== "http:")
1709
+ return null;
1710
+ return url.href;
1711
+ } catch {
1712
+ return null;
1713
+ }
1714
+ };
1715
+ const hexColor = (value) => {
1716
+ if (typeof value !== "string")
1717
+ return null;
1718
+ const raw = value.trim();
1719
+ return /^#[0-9a-fA-F]{3,8}$/.test(raw) ? raw : null;
1720
+ };
1721
+ const hostname = (value) => {
1722
+ try {
1723
+ return new URL(value).hostname.replace(/^www\./, "");
1724
+ } catch {
1725
+ return value;
1726
+ }
1727
+ };
1728
+ host.replaceChildren();
1729
+ host.hidden = true;
1730
+ if (!isRecord2(catalog) || !Object.hasOwn(catalog, service))
1731
+ return;
1732
+ const row = catalog[service];
1733
+ if (!isRecord2(row))
1734
+ return;
1735
+ const vendor = clip(row.vendor, 80);
1736
+ const website = httpUrl(row.website);
1737
+ const guide = httpUrl(row.guide);
1738
+ const docs = httpUrl(row.docs);
1739
+ const logo = httpUrl(row.logo);
1740
+ const color = hexColor(row.color);
1741
+ const description = clip(row.description, 280);
1742
+ if (vendor === null || website === null && guide === null && docs === null)
1743
+ return;
1744
+ const add = (node) => {
1745
+ host.append(node);
1746
+ return node;
1747
+ };
1748
+ if (logo !== null) {
1749
+ const img = doc.createElement("img");
1750
+ img.alt = "";
1751
+ img.src = logo;
1752
+ img.width = 16;
1753
+ img.height = 16;
1754
+ img.decoding = "async";
1755
+ img.referrerPolicy = "no-referrer";
1756
+ if (color !== null)
1757
+ img.style.borderColor = color;
1758
+ add(img);
1759
+ }
1760
+ const name = doc.createElement("span");
1761
+ name.className = "vendor-name";
1762
+ name.textContent = vendor;
1763
+ if (description !== null)
1764
+ name.title = description;
1765
+ add(name);
1766
+ const sep = () => {
1767
+ const node = doc.createElement("span");
1768
+ node.className = "vendor-sep";
1769
+ node.setAttribute("aria-hidden", "true");
1770
+ node.textContent = "\xB7";
1771
+ return node;
1772
+ };
1773
+ const link = (href, label, title) => {
1774
+ const node = doc.createElement("a");
1775
+ node.className = "vendor-link";
1776
+ node.href = href;
1777
+ node.target = "_blank";
1778
+ node.rel = "noopener noreferrer";
1779
+ node.referrerPolicy = "no-referrer";
1780
+ node.textContent = label;
1781
+ node.title = title;
1782
+ return node;
1783
+ };
1784
+ if (website !== null) {
1785
+ add(sep());
1786
+ add(link(website, hostname(website), `${vendor} website`));
1787
+ }
1788
+ if (guide !== null) {
1789
+ add(sep());
1790
+ add(link(guide, "Docs", `Docs for ${vendor}`));
1791
+ }
1792
+ if (docs !== null) {
1793
+ add(sep());
1794
+ add(link(docs, "API", `${vendor} API reference`));
1795
+ }
1796
+ host.removeAttribute("hidden");
1797
+ host.hidden = false;
1798
+ }
1799
+ function startAdminBrand(env) {
1800
+ const requested = env.params.get("brands");
1801
+ let brandsUrl = env.brandsUrl;
1802
+ if (requested) {
1803
+ try {
1804
+ const url = new URL(requested, env.location.href);
1805
+ const local = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1" || url.hostname === "[::1]" || url.origin === env.location.origin;
1806
+ if ((url.protocol === "https:" || url.protocol === "http:") && local)
1807
+ brandsUrl = url.href;
1808
+ } catch {
1809
+ brandsUrl = env.brandsUrl;
1810
+ }
1811
+ }
1812
+ const vendorHost = env.$("vendor");
1813
+ const brandRoot = env.document.querySelector("[data-mockingbird-admin]");
1814
+ const brandService = brandRoot?.getAttribute("data-service") || "";
1815
+ if (vendorHost === null)
1816
+ return;
1817
+ env.fetch(brandsUrl, {
1818
+ headers: { accept: "application/json" },
1819
+ signal: AbortSignal.timeout(5e3)
1820
+ }).then(async (response) => {
1821
+ if (!response.ok)
1822
+ return null;
1823
+ const catalog = await response.json();
1824
+ return catalog;
1825
+ }).then((catalog) => {
1826
+ mountAdminBrand(env.document, vendorHost, brandService, catalog);
1827
+ }).catch(() => {
1828
+ });
1829
+ }
1830
+ function faultPresetList(value) {
1831
+ if (!isRecord2(value))
1832
+ throw new Error("Fault presets response was not an object");
1833
+ if (!Object.hasOwn(value, "presets") || value.presets === void 0 || value.presets === null) {
1834
+ return { presets: [] };
1835
+ }
1836
+ if (!Array.isArray(value.presets))
1837
+ throw new Error("Fault presets response was not a list");
1838
+ return {
1839
+ presets: value.presets.flatMap((item) => {
1840
+ if (!isRecord2(item) || typeof item.name !== "string")
1841
+ return [];
1842
+ return [{ name: item.name }];
1843
+ })
1844
+ };
1845
+ }
1846
+ function bootAdmin(config) {
1847
+ const fieldKinds = ["string", "number", "boolean", "null", "object", "array", "unknown"];
1848
+ const sources = ["declared", "inferred", "mixed"];
1849
+ const isFieldKind = (value) => typeof value === "string" && fieldKinds.some((kind) => kind === value);
1850
+ const isSource = (value) => typeof value === "string" && sources.some((source) => source === value);
1851
+ const readJson2 = (text) => {
1852
+ const value = JSON.parse(text);
1853
+ return value;
1854
+ };
1855
+ const esc = (value) => String(value ?? "").replace(/[&<>"']/g, (char) => {
1856
+ switch (char) {
1857
+ case "&":
1858
+ return "&amp;";
1859
+ case "<":
1860
+ return "&lt;";
1861
+ case ">":
1862
+ return "&gt;";
1863
+ case '"':
1864
+ return "&quot;";
1865
+ default:
1866
+ return "&#39;";
1867
+ }
1868
+ });
1869
+ const el = (id, kind) => {
1870
+ const node = document.getElementById(id);
1871
+ if (!(node instanceof kind))
1872
+ throw new Error(`admin shell is missing #${id}`);
1873
+ return node;
1874
+ };
1875
+ const errorMessage = (data, fallback) => {
1876
+ if (!isRecord2(data))
1877
+ return fallback;
1878
+ const error = data.error;
1879
+ if (!isRecord2(error) || typeof error.message !== "string" || error.message === "") {
1880
+ return fallback;
1881
+ }
1882
+ return error.message;
1883
+ };
1884
+ const requireList = (value, label) => {
1885
+ if (value === void 0 || value === null)
1886
+ return [];
1887
+ if (!Array.isArray(value))
1888
+ throw new Error(`${label} was not a list`);
1889
+ return value;
1890
+ };
1891
+ const state = {
1892
+ namespace: "default",
1893
+ key: sessionStorage.getItem("mockingbird-admin-key") || "",
1894
+ view: "overview",
1895
+ collection: "",
1896
+ shape: null,
1897
+ route: null,
1898
+ editing: null
1899
+ };
1900
+ const standard = new Set(config.standardRoutes);
1901
+ const banner = el("banner", HTMLElement);
1902
+ const keyInput = el("admin-key", HTMLInputElement);
1903
+ keyInput.value = state.key;
1904
+ const params = new URLSearchParams(location.search);
1905
+ const queryKey = params.get("key");
1906
+ if (queryKey) {
1907
+ state.key = queryKey;
1908
+ keyInput.value = state.key;
1909
+ sessionStorage.setItem("mockingbird-admin-key", state.key);
1910
+ params.delete("key");
1911
+ const next = params.toString();
1912
+ history.replaceState(null, "", location.pathname + (next ? `?${next}` : ""));
1913
+ }
1914
+ const queryNamespace = params.get("namespace");
1915
+ if (queryNamespace)
1916
+ state.namespace = queryNamespace;
1917
+ const showError = (error) => {
1918
+ banner.textContent = error instanceof Error ? error.message : String(error);
1919
+ banner.classList.add("show");
1920
+ };
1921
+ const clearError = () => {
1922
+ banner.classList.remove("show");
1923
+ };
1924
+ const api = async (method, path, body) => {
1925
+ const headers = { accept: "application/json" };
1926
+ if (state.key !== "")
1927
+ headers[config.adminKeyHeader] = state.key;
1928
+ if (state.namespace !== "")
1929
+ headers["x-mockingbird-namespace"] = state.namespace;
1930
+ if (body !== void 0)
1931
+ headers["content-type"] = "application/json";
1932
+ const init = { method, headers };
1933
+ if (body !== void 0)
1934
+ init.body = JSON.stringify(body);
1935
+ const response = await fetch(config.adminPrefix + path, init);
1936
+ const text = await response.text();
1937
+ let data = null;
1938
+ if (text !== "") {
1939
+ try {
1940
+ data = readJson2(text);
1941
+ } catch {
1942
+ data = { raw: text };
1943
+ }
1944
+ }
1945
+ if (response.status === 401) {
1946
+ keyInput.focus();
1947
+ throw new Error(errorMessage(data, "Admin key required"));
1948
+ }
1949
+ if (!response.ok) {
1950
+ throw new Error(errorMessage(data, `${response.status} ${method} ${path}`));
1951
+ }
1952
+ return data;
1953
+ };
1954
+ const originGet = async (path) => {
1955
+ const response = await fetch(path, { headers: { accept: "application/json" } });
1956
+ if (!response.ok)
1957
+ throw new Error(`${response.status} ${path}`);
1958
+ const value = await response.json();
1959
+ return value;
1960
+ };
1961
+ const panelApi = {
1962
+ get: (path) => api("GET", path),
1963
+ send: (method, path, body) => api(method, path, body),
1964
+ namespace: () => state.namespace
1965
+ };
1966
+ const isPanelScript = (value) => typeof value === "function";
1967
+ const setTheme = (theme) => {
1968
+ if (theme)
1969
+ document.documentElement.dataset.theme = theme;
1970
+ else
1971
+ delete document.documentElement.dataset.theme;
1972
+ };
1973
+ const storedTheme = localStorage.getItem("mockingbird-admin-theme");
1974
+ if (storedTheme)
1975
+ setTheme(storedTheme);
1976
+ el("theme", HTMLButtonElement).addEventListener("click", () => {
1977
+ const current = document.documentElement.dataset.theme;
1978
+ const dark = current ? current === "dark" : matchMedia("(prefers-color-scheme: dark)").matches;
1979
+ const next = dark ? "light" : "dark";
1980
+ localStorage.setItem("mockingbird-admin-theme", next);
1981
+ setTheme(next);
1982
+ });
1983
+ const show = (view) => {
1984
+ state.view = view;
1985
+ for (const button of document.querySelectorAll("#nav button")) {
1986
+ if (!(button instanceof HTMLButtonElement))
1987
+ continue;
1988
+ button.setAttribute("aria-current", button.dataset.view === view ? "true" : "false");
1989
+ }
1990
+ for (const section of document.querySelectorAll("main .view")) {
1991
+ if (!(section instanceof HTMLElement))
1992
+ continue;
1993
+ section.hidden = section.id !== `view-${view}`;
1994
+ }
1995
+ };
1996
+ el("nav", HTMLElement).addEventListener("click", (event) => {
1997
+ const target = event.target;
1998
+ if (!(target instanceof Element))
1999
+ return;
2000
+ const button = target.closest("button[data-view]");
2001
+ if (!(button instanceof HTMLButtonElement))
2002
+ return;
2003
+ const view = button.dataset.view;
2004
+ if (view === void 0)
2005
+ return;
2006
+ show(view);
2007
+ refresh().catch(showError);
2008
+ });
2009
+ const cards = (items) => `<div class="grid">${items.map((item) => `<article class="card"><div class="k">${item.k}</div><div class="v">${item.v}</div></article>`).join("")}</div>`;
2010
+ const table = (columns, rows) => {
2011
+ if (rows.length === 0)
2012
+ return '<p class="empty">Nothing here yet.</p>';
2013
+ const head = `<tr>${columns.map((column) => `<th>${column.label}</th>`).join("")}</tr>`;
2014
+ const body = rows.map((row) => {
2015
+ const cells = columns.map((column) => `<td data-label="${column.label}">${column.cell(row)}</td>`).join("");
2016
+ const attrs = "attrs" in row && typeof row.attrs === "string" ? row.attrs : "";
2017
+ return `<tr${attrs}>${cells}</tr>`;
2018
+ }).join("");
2019
+ return `<table><thead>${head}</thead><tbody>${body}</tbody></table>`;
2020
+ };
2021
+ const preview = (value) => {
2022
+ const text = JSON.stringify(value) ?? "null";
2023
+ return esc(text.length > 180 ? `${text.slice(0, 180)}\u2026` : text);
2024
+ };
2025
+ const when = (epoch) => {
2026
+ const date = new Date(epoch);
2027
+ return Number.isNaN(date.getTime()) ? String(epoch) : date.toISOString();
2028
+ };
2029
+ const clockCard = (epoch) => {
2030
+ const date = new Date(epoch);
2031
+ if (Number.isNaN(date.getTime()))
2032
+ return esc(String(epoch));
2033
+ const iso = date.toISOString();
2034
+ return `${esc(iso.slice(0, 10))}<span class="clock-time">${esc(iso.slice(11, 19))} UTC</span>`;
2035
+ };
2036
+ const decodeClock = (value) => {
2037
+ if (!isRecord2(value) || typeof value.now !== "number" || typeof value.offsetMs !== "number" || typeof value.frozen !== "boolean") {
2038
+ throw new Error("Clock response was not a clock");
2039
+ }
2040
+ return { now: value.now, offsetMs: value.offsetMs, frozen: value.frozen };
2041
+ };
2042
+ const decodeField = (value) => {
2043
+ if (!isRecord2(value) || typeof value.name !== "string" || !isFieldKind(value.kind)) {
2044
+ return void 0;
2045
+ }
2046
+ const field = {
2047
+ name: value.name,
2048
+ kind: value.kind,
2049
+ optional: value.optional === true
2050
+ };
2051
+ if (typeof value.description === "string")
2052
+ field.description = value.description;
2053
+ if (Array.isArray(value.fields)) {
2054
+ field.fields = value.fields.flatMap((item) => {
2055
+ const child = decodeField(item);
2056
+ return child === void 0 ? [] : [child];
2057
+ });
2058
+ }
2059
+ return field;
2060
+ };
2061
+ const decodeCollection = (value) => {
2062
+ if (!isRecord2(value) || typeof value.name !== "string")
2063
+ return void 0;
2064
+ const fields = Array.isArray(value.fields) ? value.fields.flatMap((item) => {
2065
+ const field = decodeField(item);
2066
+ return field === void 0 ? [] : [field];
2067
+ }) : [];
2068
+ const collection = {
2069
+ name: value.name,
2070
+ label: typeof value.label === "string" ? value.label : value.name,
2071
+ count: typeof value.count === "number" ? value.count : 0,
2072
+ source: isSource(value.source) ? value.source : "inferred",
2073
+ fields
2074
+ };
2075
+ if (typeof value.description === "string")
2076
+ collection.description = value.description;
2077
+ return collection;
2078
+ };
2079
+ const decodeState = (value) => {
2080
+ if (!isRecord2(value) || !Array.isArray(value.collections)) {
2081
+ throw new Error("State response has no collection list");
2082
+ }
2083
+ return {
2084
+ namespace: typeof value.namespace === "string" ? value.namespace : state.namespace,
2085
+ storageNamespace: typeof value.storageNamespace === "string" ? value.storageNamespace : "",
2086
+ collections: value.collections.flatMap((item) => {
2087
+ const collection = decodeCollection(item);
2088
+ return collection === void 0 ? [] : [collection];
2089
+ })
2090
+ };
2091
+ };
2092
+ const decodeRecords = (value) => requireList(isRecord2(value) ? value.records : void 0, "Records").flatMap((item) => {
2093
+ if (!isRecord2(item) || typeof item.id !== "string")
2094
+ return [];
2095
+ return [
2096
+ {
2097
+ id: item.id,
2098
+ seq: typeof item.seq === "number" ? item.seq : 0,
2099
+ value: item.value,
2100
+ attrs: ` class="clickable" data-id="${esc(item.id)}"`
2101
+ }
2102
+ ];
2103
+ });
2104
+ const textOf = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : "";
2105
+ const decodeJournal = (value) => requireList(isRecord2(value) ? value.requests : void 0, "Journal").flatMap((item) => {
2106
+ if (!isRecord2(item))
2107
+ return [];
2108
+ return [
2109
+ {
2110
+ at: textOf(item.at),
2111
+ method: textOf(item.method),
2112
+ path: textOf(item.path),
2113
+ status: textOf(item.status),
2114
+ durationMs: textOf(item.durationMs),
2115
+ operationId: textOf(item.operationId)
2116
+ }
2117
+ ];
2118
+ });
2119
+ const decodeFaults = (value) => requireList(isRecord2(value) ? value.faults : void 0, "Faults").flatMap((item) => {
2120
+ if (!isRecord2(item))
2121
+ return [];
2122
+ return [
2123
+ {
2124
+ id: textOf(item.id),
2125
+ method: typeof item.method === "string" ? item.method : void 0,
2126
+ pathPrefix: typeof item.pathPrefix === "string" ? item.pathPrefix : void 0,
2127
+ operationId: typeof item.operationId === "string" ? item.operationId : void 0,
2128
+ status: typeof item.status === "number" ? item.status : void 0,
2129
+ effect: typeof item.effect === "string" ? item.effect : void 0,
2130
+ drop: typeof item.drop === "boolean" ? item.drop : void 0,
2131
+ latencyMs: typeof item.latencyMs === "number" ? item.latencyMs : void 0
2132
+ }
2133
+ ];
2134
+ });
2135
+ const loadNamespaces = async () => {
2136
+ const data = await api("GET", "/namespaces");
2137
+ const select = el("namespace", HTMLSelectElement);
2138
+ const listed = requireList(isRecord2(data) ? data.namespaces : void 0, "Namespaces");
2139
+ const fallback = isRecord2(data) && typeof data.default === "string" && data.default !== "" ? data.default : "default";
2140
+ const names = (listed.length > 0 ? listed.map((name) => String(name)) : [fallback]).slice();
2141
+ if (!names.includes(state.namespace))
2142
+ names.unshift(state.namespace);
2143
+ select.innerHTML = names.map((name) => `<option value="${esc(name)}">${esc(name)}</option>`).join("");
2144
+ select.value = state.namespace;
2145
+ };
2146
+ const renderOverview = async () => {
2147
+ const [health, shape, clock, journal] = await Promise.all([
2148
+ originGet("/health"),
2149
+ api("GET", "/state"),
2150
+ api("GET", "/clock"),
2151
+ api("GET", "/requests?limit=8")
2152
+ ]);
2153
+ if (!isRecord2(health))
2154
+ throw new Error("Health response was not an object");
2155
+ const decoded = decodeState(shape);
2156
+ state.shape = decoded;
2157
+ const time = decodeClock(clock);
2158
+ el("overview-cards", HTMLElement).innerHTML = cards([
2159
+ {
2160
+ k: "Service",
2161
+ v: esc(typeof health.service === "string" && health.service !== "" ? health.service : config.service)
2162
+ },
2163
+ {
2164
+ k: "Status",
2165
+ v: esc(typeof health.status === "string" && health.status !== "" ? health.status : "ok")
2166
+ },
2167
+ { k: "Namespace", v: esc(state.namespace) },
2168
+ { k: "Collections", v: String(decoded.collections.length) },
2169
+ {
2170
+ k: "Records",
2171
+ v: String(decoded.collections.reduce((sum, item) => sum + item.count, 0))
2172
+ },
2173
+ { k: "Clock", v: clockCard(time.now) }
2174
+ ]);
2175
+ el("overview-requests", HTMLElement).innerHTML = table([
2176
+ { label: "Method", cell: (row) => esc(row.method) },
2177
+ { label: "Path", cell: (row) => esc(row.path) },
2178
+ {
2179
+ label: "Status",
2180
+ cell: (row) => `<span class="status-${row.status.charAt(0)}">${esc(row.status)}</span>`
2181
+ },
2182
+ { label: "Operation", cell: (row) => esc(row.operationId) }
2183
+ ], decodeJournal(journal));
2184
+ };
2185
+ const schemaChips = (collection) => {
2186
+ if (collection.fields.length === 0) {
2187
+ return '<p class="empty">No fields yet. Add a record or declare the collection on the service.</p>';
2188
+ }
2189
+ return `<div class="chips">${collection.fields.map((field) => `<span class="chip">${esc(field.name)} <i>${esc(field.kind)}${field.optional ? "?" : ""}</i></span>`).join("")}</div>`;
2190
+ };
2191
+ const renderState = async () => {
2192
+ const shape = decodeState(await api("GET", "/state"));
2193
+ state.shape = shape;
2194
+ const host = el("collections", HTMLElement);
2195
+ if (shape.collections.length === 0) {
2196
+ host.innerHTML = '<p class="empty">This namespace has no collections yet.</p>';
2197
+ el("schema", HTMLElement).innerHTML = "";
2198
+ el("records", HTMLElement).innerHTML = "";
2199
+ return;
2200
+ }
2201
+ if (!shape.collections.some((item) => item.name === state.collection)) {
2202
+ const first = shape.collections[0];
2203
+ if (first === void 0)
2204
+ return;
2205
+ state.collection = first.name;
2206
+ }
2207
+ host.innerHTML = shape.collections.map((item) => `<button type="button" class="collection" data-collection="${esc(item.name)}" aria-current="${item.name === state.collection ? "true" : "false"}"><strong>${esc(item.label)}</strong><small>${esc(item.count)} \xB7 ${esc(item.source)}</small></button>`).join("");
2208
+ const selected = shape.collections.find((item) => item.name === state.collection);
2209
+ if (selected === void 0)
2210
+ return;
2211
+ const description = selected.description ? `<p class="lede">${esc(selected.description)}</p>` : "";
2212
+ el("schema", HTMLElement).innerHTML = `<h3>${esc(selected.label)}</h3>${description}${schemaChips(selected)}`;
2213
+ const page = await api("GET", `/state/${encodeURIComponent(state.collection)}?limit=50`);
2214
+ el("records", HTMLElement).innerHTML = table([
2215
+ { label: "Id", cell: (row) => `<code>${esc(row.id)}</code>` },
2216
+ { label: "Seq", cell: (row) => esc(row.seq) },
2217
+ { label: "Value", cell: (row) => preview(row.value) }
2218
+ ], decodeRecords(page));
2219
+ };
2220
+ const renderClock = async () => {
2221
+ const clock = decodeClock(await api("GET", "/clock"));
2222
+ el("clock-readout", HTMLElement).innerHTML = `<div class="k">Now</div><div class="v">${esc(when(clock.now))}</div><p>${esc(clock.now)} ms \xB7 offset ${esc(clock.offsetMs)} ms ${clock.frozen ? "<span class='badge warn'>frozen</span>" : "<span class='badge ok'>live</span>"}</p>`;
2223
+ const freeze = el("freeze", HTMLButtonElement);
2224
+ freeze.textContent = clock.frozen ? "Unfreeze" : "Freeze";
2225
+ freeze.dataset.frozen = clock.frozen ? "1" : "0";
2226
+ };
2227
+ const renderFaults = async () => {
2228
+ const [faults, presets] = await Promise.all([
2229
+ api("GET", "/faults"),
2230
+ api("GET", "/faults/presets").catch(() => ({ presets: [] }))
2231
+ ]);
2232
+ const select = el("fault-preset", HTMLSelectElement);
2233
+ const current = select.value;
2234
+ const list = faultPresetList(presets).presets;
2235
+ select.innerHTML = `<option value="">Custom rule</option>${list.map((preset) => `<option value="${esc(preset.name)}">${esc(preset.name)}</option>`).join("")}`;
2236
+ select.value = current;
2237
+ el("fault-list", HTMLElement).innerHTML = table([
2238
+ { label: "Id", cell: (row) => esc(row.id) },
2239
+ {
2240
+ label: "Match",
2241
+ cell: (row) => esc([row.method, row.pathPrefix, row.operationId].filter((part) => Boolean(part)).join(" ") || "all")
2242
+ },
2243
+ {
2244
+ label: "Effect",
2245
+ cell: (row) => esc(row.status ?? row.effect ?? (row.drop ? "drop" : row.latencyMs || ""))
2246
+ }
2247
+ ], decodeFaults(faults));
2248
+ };
2249
+ const renderJournal = async () => {
2250
+ const journal = await api("GET", "/requests?limit=100");
2251
+ el("journal", HTMLElement).innerHTML = table([
2252
+ { label: "When", cell: (row) => esc(row.at) },
2253
+ { label: "Method", cell: (row) => esc(row.method) },
2254
+ { label: "Path", cell: (row) => esc(row.path) },
2255
+ { label: "Status", cell: (row) => esc(row.status) },
2256
+ { label: "ms", cell: (row) => esc(row.durationMs) }
2257
+ ], decodeJournal(journal));
2258
+ };
2259
+ const renderRoutes = async () => {
2260
+ const data = await api("GET", "/");
2261
+ if (!isRecord2(data))
2262
+ throw new Error("Route list was not an object");
2263
+ const routes = requireList(data.routes, "Routes").map((route) => String(route));
2264
+ el("route-list", HTMLElement).innerHTML = routes.map((route) => {
2265
+ const extra = standard.has(route) ? "" : " <span class='badge'>extension</span>";
2266
+ const parts = route.split(" ");
2267
+ const method = parts[0] ?? "";
2268
+ const path = parts.slice(1).join(" ");
2269
+ return `<div class="route"><span class="method">${esc(method)}</span><span>${esc(path)}${extra}</span><button class="btn" type="button" data-route="${esc(route)}">Use</button></div>`;
2270
+ }).join("");
2271
+ };
2272
+ const renderers = {
2273
+ overview: renderOverview,
2274
+ state: renderState,
2275
+ clock: renderClock,
2276
+ faults: renderFaults,
2277
+ journal: renderJournal,
2278
+ routes: renderRoutes
2279
+ };
2280
+ async function refresh() {
2281
+ clearError();
2282
+ const render = renderers[state.view];
2283
+ if (render)
2284
+ await render();
2285
+ }
2286
+ el("namespace", HTMLSelectElement).addEventListener("change", () => {
2287
+ state.namespace = el("namespace", HTMLSelectElement).value;
2288
+ refresh().catch(showError);
2289
+ });
2290
+ keyInput.addEventListener("change", () => {
2291
+ state.key = keyInput.value.trim();
2292
+ sessionStorage.setItem("mockingbird-admin-key", state.key);
2293
+ refresh().catch(showError);
2294
+ });
2295
+ el("refresh", HTMLButtonElement).addEventListener("click", () => {
2296
+ refresh().catch(showError);
2297
+ });
2298
+ el("collections", HTMLElement).addEventListener("click", (event) => {
2299
+ const target = event.target;
2300
+ if (!(target instanceof Element))
2301
+ return;
2302
+ const button = target.closest("[data-collection]");
2303
+ if (!(button instanceof HTMLElement))
2304
+ return;
2305
+ const collection = button.dataset.collection;
2306
+ if (collection === void 0)
2307
+ return;
2308
+ state.collection = collection;
2309
+ renderState().catch(showError);
2310
+ });
2311
+ el("records", HTMLElement).addEventListener("click", (event) => {
2312
+ const target = event.target;
2313
+ if (!(target instanceof Element))
2314
+ return;
2315
+ const row = target.closest("[data-id]");
2316
+ if (!(row instanceof HTMLElement))
2317
+ return;
2318
+ const id = row.dataset.id;
2319
+ if (id === void 0)
2320
+ return;
2321
+ openEditor(id).catch(showError);
2322
+ });
2323
+ const editor = el("editor", HTMLDialogElement);
2324
+ const editorId = el("editor-id", HTMLInputElement);
2325
+ const editorValue = el("editor-value", HTMLTextAreaElement);
2326
+ const editorDelete = el("editor-delete", HTMLButtonElement);
2327
+ async function openEditor(id) {
2328
+ state.editing = id;
2329
+ el("editor-title", HTMLElement).textContent = id ? "Edit record" : "New record";
2330
+ editorId.value = id ?? "";
2331
+ editorId.readOnly = id !== null;
2332
+ editorDelete.hidden = id === null;
2333
+ if (id) {
2334
+ const record = await api("GET", `/state/${encodeURIComponent(state.collection)}/${encodeURIComponent(id)}`);
2335
+ if (!isRecord2(record))
2336
+ throw new Error("Record response was not an object");
2337
+ editorValue.value = JSON.stringify(record.value, null, 2) ?? "";
2338
+ } else {
2339
+ editorValue.value = "{\n \n}";
2340
+ }
2341
+ editor.showModal();
2342
+ }
2343
+ el("new-record", HTMLButtonElement).addEventListener("click", () => {
2344
+ openEditor(null).catch(showError);
2345
+ });
2346
+ el("editor-form", HTMLFormElement).addEventListener("submit", (event) => {
2347
+ const submitter = event.submitter;
2348
+ if (!(submitter instanceof HTMLButtonElement) || submitter.value !== "save")
2349
+ return;
2350
+ event.preventDefault();
2351
+ let value;
2352
+ try {
2353
+ value = readJson2(editorValue.value);
2354
+ } catch {
2355
+ showError(new Error("Value is not JSON"));
2356
+ return;
2357
+ }
2358
+ const id = editorId.value.trim();
2359
+ const path = `/state/${encodeURIComponent(state.collection)}`;
2360
+ const request = state.editing ? api("PUT", `${path}/${encodeURIComponent(id)}`, { value }) : api("POST", path, { id: id || void 0, value });
2361
+ request.then(() => {
2362
+ editor.close();
2363
+ return renderState();
2364
+ }).catch(showError);
2365
+ });
2366
+ editorDelete.addEventListener("click", () => {
2367
+ const id = state.editing;
2368
+ if (!id)
2369
+ return;
2370
+ api("DELETE", `/state/${encodeURIComponent(state.collection)}/${encodeURIComponent(id)}`).then(() => {
2371
+ editor.close();
2372
+ return renderState();
2373
+ }).catch(showError);
2374
+ });
2375
+ for (const button of document.querySelectorAll("[data-advance]")) {
2376
+ if (!(button instanceof HTMLButtonElement))
2377
+ continue;
2378
+ button.addEventListener("click", () => {
2379
+ const raw = button.dataset.advance;
2380
+ if (raw === void 0)
2381
+ return;
2382
+ api("POST", "/clock", { advance: Number(raw) }).then(() => renderClock()).catch(showError);
2383
+ });
2384
+ }
2385
+ el("freeze", HTMLButtonElement).addEventListener("click", () => {
2386
+ const frozen = el("freeze", HTMLButtonElement).dataset.frozen === "1";
2387
+ api("POST", "/clock", { freeze: !frozen }).then(() => renderClock()).catch(showError);
2388
+ });
2389
+ el("clock-reset", HTMLButtonElement).addEventListener("click", () => {
2390
+ api("POST", "/clock", { reset: true }).then(() => renderClock()).catch(showError);
2391
+ });
2392
+ el("clock-set", HTMLFormElement).addEventListener("submit", (event) => {
2393
+ event.preventDefault();
2394
+ const raw = el("clock-instant", HTMLInputElement).value.trim();
2395
+ const set = /^-?\d+$/.test(raw) ? Number(raw) : raw;
2396
+ api("POST", "/clock", { set }).then(() => renderClock()).catch(showError);
2397
+ });
2398
+ el("fault-form", HTMLFormElement).addEventListener("submit", (event) => {
2399
+ event.preventDefault();
2400
+ const preset = el("fault-preset", HTMLSelectElement).value;
2401
+ if (preset !== "") {
2402
+ api("POST", "/faults", { preset }).then(() => renderFaults()).catch(showError);
2403
+ return;
2404
+ }
2405
+ const status = Number(el("fault-status", HTMLInputElement).value);
2406
+ if (!Number.isFinite(status)) {
2407
+ showError(new Error("Status must be a number, or choose a preset"));
2408
+ return;
2409
+ }
2410
+ const path = el("fault-path", HTMLInputElement).value;
2411
+ const method = el("fault-method", HTMLInputElement).value;
2412
+ api("POST", "/faults", {
2413
+ status,
2414
+ ...path !== "" ? { pathPrefix: path } : {},
2415
+ ...method !== "" ? { method } : {}
2416
+ }).then(() => renderFaults()).catch(showError);
2417
+ });
2418
+ el("fault-clear", HTMLButtonElement).addEventListener("click", () => {
2419
+ api("DELETE", "/faults").then(() => renderFaults()).catch(showError);
2420
+ });
2421
+ el("journal-clear", HTMLButtonElement).addEventListener("click", () => {
2422
+ api("DELETE", "/requests").then(() => renderJournal()).catch(showError);
2423
+ });
2424
+ el("route-list", HTMLElement).addEventListener("click", (event) => {
2425
+ const target = event.target;
2426
+ if (!(target instanceof Element))
2427
+ return;
2428
+ const button = target.closest("[data-route]");
2429
+ if (!(button instanceof HTMLElement))
2430
+ return;
2431
+ const route = button.dataset.route;
2432
+ if (route === void 0)
2433
+ return;
2434
+ state.route = route;
2435
+ el("route-title", HTMLElement).textContent = route;
2436
+ const method = route.split(" ")[0] ?? "";
2437
+ el("route-body", HTMLTextAreaElement).disabled = method === "GET" || method === "DELETE";
2438
+ });
2439
+ el("route-form", HTMLFormElement).addEventListener("submit", (event) => {
2440
+ event.preventDefault();
2441
+ const send = async () => {
2442
+ if (state.route === null)
2443
+ throw new Error("Choose a route first");
2444
+ const parts = state.route.split(" ");
2445
+ const method = parts[0];
2446
+ const path = parts.slice(1).join(" ");
2447
+ if (method === void 0)
2448
+ throw new Error("Choose a route first");
2449
+ const concrete = path.replace(/:([A-Za-z0-9_]+)/g, (_match, key) => prompt(`Value for ${key}`) || "");
2450
+ let body;
2451
+ const routeBody = el("route-body", HTMLTextAreaElement);
2452
+ if (method !== "GET" && method !== "DELETE" && routeBody.value.trim() !== "") {
2453
+ try {
2454
+ body = readJson2(routeBody.value);
2455
+ } catch {
2456
+ throw new Error("Body is not JSON");
2457
+ }
2458
+ }
2459
+ const data = await api(method, concrete, body);
2460
+ el("route-result", HTMLElement).textContent = JSON.stringify(data, null, 2);
2461
+ };
2462
+ send().catch(showError);
2463
+ });
2464
+ const decodePanel = (value) => {
2465
+ if (!isRecord2(value) || typeof value.id !== "string" || typeof value.title !== "string") {
2466
+ return void 0;
2467
+ }
2468
+ const panel = {
2469
+ id: value.id,
2470
+ title: value.title,
2471
+ description: typeof value.description === "string" ? value.description : "",
2472
+ html: typeof value.html === "string" ? value.html : ""
2473
+ };
2474
+ if (typeof value.script === "string")
2475
+ panel.script = value.script;
2476
+ return panel;
2477
+ };
2478
+ const mountPanels = (panels) => {
2479
+ const nav = el("nav", HTMLElement);
2480
+ const views = el("views", HTMLElement);
2481
+ for (const panel of panels) {
2482
+ const button = document.createElement("button");
2483
+ button.type = "button";
2484
+ button.dataset.view = panel.id;
2485
+ button.textContent = panel.title;
2486
+ nav.append(button);
2487
+ const section = document.createElement("section");
2488
+ section.className = "view";
2489
+ section.id = `view-${panel.id}`;
2490
+ section.hidden = true;
2491
+ const title = document.createElement("h2");
2492
+ title.textContent = panel.title;
2493
+ const lede = document.createElement("p");
2494
+ lede.className = "lede";
2495
+ lede.textContent = panel.description;
2496
+ const body = document.createElement("div");
2497
+ body.className = "panel-body";
2498
+ body.id = `panel-${panel.id}`;
2499
+ body.innerHTML = panel.html;
2500
+ section.append(title, lede, body);
2501
+ views.append(section);
2502
+ if (panel.script === void 0)
2503
+ continue;
2504
+ try {
2505
+ const compiled = new Function("root", "api", panel.script);
2506
+ if (!isPanelScript(compiled))
2507
+ throw new Error("panel script did not compile");
2508
+ compiled(body, panelApi);
2509
+ } catch (error) {
2510
+ const note = document.createElement("p");
2511
+ note.className = "banner show";
2512
+ note.textContent = error instanceof Error ? error.message : String(error);
2513
+ body.append(note);
2514
+ }
2515
+ }
2516
+ };
2517
+ startAdminBrand({
2518
+ document,
2519
+ $: (id) => document.getElementById(id),
2520
+ params,
2521
+ location: { href: location.href, origin: location.origin },
2522
+ fetch,
2523
+ brandsUrl: config.brandsUrl
2524
+ });
2525
+ loadNamespaces().then(() => api("GET", "/ui/manifest")).then((manifest) => {
2526
+ const panels = requireList(isRecord2(manifest) ? manifest.panels : void 0, "Panels").flatMap((panel) => {
2527
+ const decoded = decodePanel(panel);
2528
+ return decoded === void 0 ? [] : [decoded];
2529
+ });
2530
+ mountPanels(panels);
2531
+ return refresh();
2532
+ }).catch(showError);
2533
+ }
2534
+ var clientPrelude = [isRecord2, mountAdminBrand, startAdminBrand, faultPresetList, bootAdmin].map((fn) => fn.toString()).join("\n");
2535
+ var adminClientSource = (config) => {
2536
+ const payload = JSON.stringify(config).replace(/</g, "\\u003c");
2537
+ return `<script>
2538
+ ${clientPrelude}
2539
+ bootAdmin(${payload});
2540
+ </script>`;
2541
+ };
2542
+
1317
2543
  // ../core/dist/surface.js
1318
2544
  var defineMock = (runtime) => runtime;
1319
2545
  var STANDARD_ADMIN_ROUTES = [
@@ -1382,94 +2608,106 @@ var escapeHtml = (value) => value.replace(/[&<>"']/g, (char) => {
1382
2608
  return "&#39;";
1383
2609
  }
1384
2610
  });
2611
+ var ADMIN_BRANDS_URL = "https://mockingbird.chrisvouga.dev/brands.json";
1385
2612
  var renderAdminDocument = (service) => {
1386
2613
  const name = escapeHtml(service);
1387
- const standard = JSON.stringify(STANDARD_ADMIN_ROUTES);
2614
+ const script = adminClientSource({
2615
+ standardRoutes: STANDARD_ADMIN_ROUTES,
2616
+ adminPrefix: ADMIN_PREFIX,
2617
+ adminKeyHeader: ADMIN_KEY_HEADER,
2618
+ brandsUrl: ADMIN_BRANDS_URL,
2619
+ service
2620
+ });
1388
2621
  return `<!DOCTYPE html>
1389
2622
  <html lang="en">
1390
2623
  <head>
1391
2624
  <meta charset="utf-8">
1392
2625
  <meta name="viewport" content="width=device-width, initial-scale=1">
1393
2626
  <meta name="color-scheme" content="light dark">
1394
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' rx='3' fill='%233d4f3a'/%3E%3C/svg%3E">
2627
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' rx='2' fill='%2327272a'/%3E%3C/svg%3E">
1395
2628
  <title>${name} admin</title>
1396
2629
  <style>
2630
+ ${CSS_RESET}
1397
2631
  :root {
1398
2632
  color-scheme: light;
1399
- --bg: #f6f5f2;
2633
+ --bg: #fafafa;
1400
2634
  --bg-elev: #ffffff;
1401
- --bg-muted: #eeece6;
1402
- --bg-inset: #f3f1eb;
1403
- --line: #e2dfd6;
1404
- --line-strong: #d0ccc1;
1405
- --ink: #1c1915;
1406
- --muted: #5e584f;
1407
- --faint: #8a8378;
1408
- --accent: #3d4f3a;
1409
- --accent-ink: #f7f6f2;
1410
- --accent-soft: #e5ece2;
1411
- --ok: #1f7a45;
1412
- --ok-soft: #e5f4eb;
1413
- --warn: #9a6700;
1414
- --warn-soft: #fbf3df;
1415
- --err: #a33b32;
1416
- --err-soft: #fdecea;
1417
- --shadow: 0 1px 2px rgb(28 25 21 / 0.05), 0 12px 32px rgb(28 25 21 / 0.06);
1418
- --sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
2635
+ --bg-muted: #f4f4f5;
2636
+ --bg-inset: #f4f4f5;
2637
+ --line: #dedee3;
2638
+ --line-strong: #c4c4cc;
2639
+ --ink: #18181b;
2640
+ --muted: #62626b;
2641
+ --faint: #71717a;
2642
+ --accent: #27272a;
2643
+ --accent-ink: #ffffff;
2644
+ --accent-soft: #f4f4f5;
2645
+ --ok: #166534;
2646
+ --ok-soft: #f0fdf4;
2647
+ --warn: #a16207;
2648
+ --warn-soft: #fefce8;
2649
+ --err: #a82d32;
2650
+ --err-soft: #fef2f2;
2651
+ --shadow: none;
2652
+ --sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
1419
2653
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
1420
- --radius: 14px;
1421
- --header: 60px;
1422
- --nav: 220px;
2654
+ --radius: 10px;
2655
+ --header: 56px;
2656
+ --nav: 200px;
1423
2657
  }
1424
2658
  :root[data-theme="dark"] {
1425
2659
  color-scheme: dark;
1426
- --bg: #141311;
1427
- --bg-elev: #1e1c19;
1428
- --bg-muted: #26231f;
1429
- --bg-inset: #181715;
1430
- --line: #34302b;
1431
- --line-strong: #4a453d;
1432
- --ink: #f4f1ea;
1433
- --muted: #c4bdb1;
1434
- --faint: #8f877c;
1435
- --accent: #c5d5b8;
1436
- --accent-ink: #1a2118;
1437
- --accent-soft: #2a3328;
1438
- --ok: #8fd6a8;
1439
- --ok-soft: #1a2e22;
1440
- --warn: #f0cc78;
1441
- --warn-soft: #332911;
1442
- --err: #f0a8a2;
1443
- --err-soft: #3a201e;
1444
- --shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 16px 40px rgb(0 0 0 / 0.28);
2660
+ --bg: #111113;
2661
+ --bg-elev: #19191c;
2662
+ --bg-muted: #242428;
2663
+ --bg-inset: #111113;
2664
+ --line: #36363c;
2665
+ --line-strong: #52525b;
2666
+ --ink: #f4f4f5;
2667
+ --muted: #a9a9b2;
2668
+ --faint: #71717a;
2669
+ --accent: #e4e4e7;
2670
+ --accent-ink: #18181b;
2671
+ --accent-soft: #242428;
2672
+ --ok: #86efac;
2673
+ --ok-soft: #14241b;
2674
+ --warn: #fde68a;
2675
+ --warn-soft: #2a2410;
2676
+ --err: #ffaaaa;
2677
+ --err-soft: #2c1516;
2678
+ --shadow: none;
1445
2679
  }
1446
2680
  @media (prefers-color-scheme: dark) {
1447
2681
  :root:not([data-theme="light"]) {
1448
2682
  color-scheme: dark;
1449
- --bg: #141311;
1450
- --bg-elev: #1e1c19;
1451
- --bg-muted: #26231f;
1452
- --bg-inset: #181715;
1453
- --line: #34302b;
1454
- --line-strong: #4a453d;
1455
- --ink: #f4f1ea;
1456
- --muted: #c4bdb1;
1457
- --faint: #8f877c;
1458
- --accent: #c5d5b8;
1459
- --accent-ink: #1a2118;
1460
- --accent-soft: #2a3328;
1461
- --ok: #8fd6a8;
1462
- --ok-soft: #1a2e22;
1463
- --warn: #f0cc78;
1464
- --warn-soft: #332911;
1465
- --err: #f0a8a2;
1466
- --err-soft: #3a201e;
1467
- --shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 16px 40px rgb(0 0 0 / 0.28);
1468
- }
1469
- }
1470
- * { box-sizing: border-box; }
1471
- html, body { margin: 0; height: 100%; }
2683
+ --bg: #111113;
2684
+ --bg-elev: #19191c;
2685
+ --bg-muted: #242428;
2686
+ --bg-inset: #111113;
2687
+ --line: #36363c;
2688
+ --line-strong: #52525b;
2689
+ --ink: #f4f4f5;
2690
+ --muted: #a9a9b2;
2691
+ --faint: #71717a;
2692
+ --accent: #e4e4e7;
2693
+ --accent-ink: #18181b;
2694
+ --accent-soft: #242428;
2695
+ --ok: #86efac;
2696
+ --ok-soft: #14241b;
2697
+ --warn: #fde68a;
2698
+ --warn-soft: #2a2410;
2699
+ --err: #ffaaaa;
2700
+ --err-soft: #2c1516;
2701
+ --shadow: none;
2702
+ }
2703
+ }
2704
+ /* Fill the viewport, then grow with the content so the background covers the scroll. */
2705
+ html { height: 100%; }
1472
2706
  body {
2707
+ margin: 0;
2708
+ min-height: 100%;
2709
+ display: flex;
2710
+ flex-direction: column;
1473
2711
  font-family: var(--sans);
1474
2712
  background: var(--bg);
1475
2713
  color: var(--ink);
@@ -1478,24 +2716,37 @@ var renderAdminDocument = (service) => {
1478
2716
  padding-right: env(safe-area-inset-right);
1479
2717
  -webkit-text-size-adjust: 100%;
1480
2718
  }
1481
- button, input, select, textarea { font: inherit; color: inherit; }
1482
- button { cursor: pointer; }
1483
2719
  :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1484
- @media (prefers-reduced-motion: reduce) {
1485
- * { scroll-behavior: auto !important; transition: none !important; }
1486
- }
1487
- .app { min-height: 100%; display: flex; flex-direction: column; }
2720
+ .app { flex: 1 0 auto; display: flex; flex-direction: column; min-width: 0; width: 100%; }
1488
2721
  header.top {
1489
2722
  position: sticky; top: 0; z-index: 5;
1490
2723
  display: flex; align-items: center; gap: 12px;
1491
2724
  min-height: var(--header); padding: 10px 16px;
1492
- background: color-mix(in srgb, var(--bg-elev) 92%, transparent);
2725
+ background: var(--bg-elev);
1493
2726
  border-bottom: 1px solid var(--line);
1494
- backdrop-filter: blur(10px);
1495
- }
1496
- .brand { display: flex; flex-direction: column; min-width: 0; margin-right: auto; }
1497
- .brand strong { font-size: 15px; letter-spacing: -0.01em; }
1498
- .brand span { color: var(--faint); font-size: 12px; }
2727
+ min-width: 0; max-width: 100%;
2728
+ }
2729
+ .brand {
2730
+ display: flex; flex-flow: row wrap; align-items: center; gap: 14px;
2731
+ min-width: 0; max-width: 100%; margin-right: auto;
2732
+ }
2733
+ .brand-id { display: flex; flex-direction: column; min-width: 0; flex: none; }
2734
+ .brand-id strong { font-size: 15px; letter-spacing: -0.01em; }
2735
+ .brand-id span { color: var(--faint); font-size: 12px; }
2736
+ .vendor {
2737
+ display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
2738
+ min-width: 0; max-width: 100%; font-size: 12px; color: var(--muted);
2739
+ }
2740
+ .vendor[hidden] { display: none; }
2741
+ /* Logos are drawn for a light tile, same as the docs site, so the plate stays white. */
2742
+ .vendor img {
2743
+ width: 16px; height: 16px; padding: 2px; box-sizing: content-box;
2744
+ border-radius: 4px; border: 1px solid var(--line); background: #fff; object-fit: contain;
2745
+ }
2746
+ .vendor-name { color: var(--ink); font-weight: 600; }
2747
+ .vendor-sep { color: var(--faint); }
2748
+ .vendor-link { color: inherit; text-decoration: none; }
2749
+ .vendor-link:hover { color: var(--ink); text-decoration: underline; }
1499
2750
  .controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
1500
2751
  label.field { display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: var(--faint); }
1501
2752
  label.field input, label.field select, .controls input[type="password"] {
@@ -1513,7 +2764,7 @@ var renderAdminDocument = (service) => {
1513
2764
  record or the full nav row would widen the page past the viewport. */
1514
2765
  .layout {
1515
2766
  display: grid; grid-template-columns: var(--nav) minmax(0, 1fr);
1516
- flex: 1; min-height: 0; min-width: 0;
2767
+ flex: 1 0 auto; min-width: 0;
1517
2768
  }
1518
2769
  nav.side {
1519
2770
  border-right: 1px solid var(--line); padding: 12px;
@@ -1567,8 +2818,8 @@ var renderAdminDocument = (service) => {
1567
2818
  .banner.show { display: block; }
1568
2819
  .empty { color: var(--muted); padding: 24px 8px; }
1569
2820
  dialog {
1570
- border: 1px solid var(--line); border-radius: 16px; padding: 0; background: var(--bg-elev);
1571
- color: var(--ink); width: min(640px, calc(100vw - 24px)); box-shadow: var(--shadow);
2821
+ border: 1px solid var(--line); border-radius: var(--radius); padding: 0; background: var(--bg-elev);
2822
+ color: var(--ink); width: min(640px, calc(100vw - 24px)); box-shadow: none;
1572
2823
  }
1573
2824
  dialog::backdrop { background: rgb(20 19 17 / 0.45); }
1574
2825
  dialog form, .dialog-body { padding: 16px; display: flex; flex-direction: column; gap: 10px; }
@@ -1595,7 +2846,7 @@ var renderAdminDocument = (service) => {
1595
2846
  padding-top: max(10px, env(safe-area-inset-top));
1596
2847
  }
1597
2848
  input, select, textarea { font-size: 16px; }
1598
- .controls { width: 100%; }
2849
+ .brand, .vendor, .controls { width: 100%; }
1599
2850
  label.field, label.field select, label.field input { flex: 1; min-width: 0; }
1600
2851
  .layout { grid-template-columns: minmax(0, 1fr); }
1601
2852
  nav.side {
@@ -1626,8 +2877,11 @@ var renderAdminDocument = (service) => {
1626
2877
  <div class="app" data-service="${name}" data-mockingbird-admin>
1627
2878
  <header class="top">
1628
2879
  <div class="brand">
1629
- <strong>${name}</strong>
1630
- <span>Mockingbird admin</span>
2880
+ <div class="brand-id">
2881
+ <strong>${name}</strong>
2882
+ <span>Admin</span>
2883
+ </div>
2884
+ <div class="vendor" id="vendor" hidden></div>
1631
2885
  </div>
1632
2886
  <div class="controls">
1633
2887
  <label class="field">Namespace
@@ -1757,460 +3011,7 @@ var renderAdminDocument = (service) => {
1757
3011
  </div>
1758
3012
  </form>
1759
3013
  </dialog>
1760
- <script>
1761
- (() => {
1762
- const STANDARD = new Set(${standard})
1763
- const state = {
1764
- namespace: "default",
1765
- key: sessionStorage.getItem("mockingbird-admin-key") || "",
1766
- view: "overview",
1767
- collection: "",
1768
- shape: null,
1769
- route: null,
1770
- editing: null
1771
- }
1772
- const $ = (id) => document.getElementById(id)
1773
- const banner = $("banner")
1774
- const keyInput = $("admin-key")
1775
- keyInput.value = state.key
1776
- const params = new URLSearchParams(location.search)
1777
- if (params.get("key")) {
1778
- state.key = params.get("key")
1779
- keyInput.value = state.key
1780
- sessionStorage.setItem("mockingbird-admin-key", state.key)
1781
- params.delete("key")
1782
- const next = params.toString()
1783
- history.replaceState(null, "", location.pathname + (next ? "?" + next : ""))
1784
- }
1785
- if (params.get("namespace")) state.namespace = params.get("namespace")
1786
-
1787
- const showError = (error) => {
1788
- banner.textContent = error instanceof Error ? error.message : String(error)
1789
- banner.classList.add("show")
1790
- }
1791
- const clearError = () => banner.classList.remove("show")
1792
-
1793
- async function originGet(path) {
1794
- const response = await fetch(path, { headers: { accept: "application/json" } })
1795
- if (!response.ok) throw new Error(response.status + " " + path)
1796
- return response.json()
1797
- }
1798
- async function api(method, path, body) {
1799
- const headers = { accept: "application/json" }
1800
- if (state.key) headers["${ADMIN_KEY_HEADER}"] = state.key
1801
- if (state.namespace) headers["x-mockingbird-namespace"] = state.namespace
1802
- if (body !== undefined) headers["content-type"] = "application/json"
1803
- const response = await fetch("${ADMIN_PREFIX}" + path, {
1804
- method,
1805
- headers,
1806
- body: body === undefined ? undefined : JSON.stringify(body)
1807
- })
1808
- const text = await response.text()
1809
- let data = null
1810
- if (text) {
1811
- try { data = JSON.parse(text) } catch { data = { raw: text } }
1812
- }
1813
- if (response.status === 401) {
1814
- keyInput.focus()
1815
- throw new Error((data && data.error && data.error.message) || "Admin key required")
1816
- }
1817
- if (!response.ok) {
1818
- throw new Error((data && data.error && data.error.message) || (response.status + " " + method + " " + path))
1819
- }
1820
- return data
1821
- }
1822
- const panelApi = {
1823
- get: (path) => api("GET", path),
1824
- send: (method, path, body) => api(method, path, body),
1825
- namespace: () => state.namespace
1826
- }
1827
-
1828
- function setTheme(theme) {
1829
- if (theme) document.documentElement.dataset.theme = theme
1830
- else delete document.documentElement.dataset.theme
1831
- }
1832
- const storedTheme = localStorage.getItem("mockingbird-admin-theme")
1833
- if (storedTheme) setTheme(storedTheme)
1834
- $("theme").addEventListener("click", () => {
1835
- const current = document.documentElement.dataset.theme
1836
- const dark = current ? current === "dark" : matchMedia("(prefers-color-scheme: dark)").matches
1837
- const next = dark ? "light" : "dark"
1838
- localStorage.setItem("mockingbird-admin-theme", next)
1839
- setTheme(next)
1840
- })
1841
-
1842
- function show(view) {
1843
- state.view = view
1844
- for (const button of document.querySelectorAll("#nav button")) {
1845
- button.setAttribute("aria-current", button.dataset.view === view ? "true" : "false")
1846
- }
1847
- for (const section of document.querySelectorAll("main .view")) {
1848
- section.hidden = section.id !== "view-" + view
1849
- }
1850
- }
1851
- document.getElementById("nav").addEventListener("click", (event) => {
1852
- const button = event.target.closest("button[data-view]")
1853
- if (!button) return
1854
- show(button.dataset.view)
1855
- refresh().catch(showError)
1856
- })
1857
-
1858
- function cards(items) {
1859
- return '<div class="grid">' + items.map((item) =>
1860
- '<article class="card"><div class="k">' + item.k + '</div><div class="v">' + item.v + '</div></article>'
1861
- ).join("") + "</div>"
1862
- }
1863
- function table(columns, rows) {
1864
- if (rows.length === 0) return '<p class="empty">Nothing here yet.</p>'
1865
- const head = "<tr>" + columns.map((column) => "<th>" + column.label + "</th>").join("") + "</tr>"
1866
- const body = rows.map((row) => "<tr" + (row.attrs || "") + ">" + columns.map((column) =>
1867
- '<td data-label="' + column.label + '">' + column.cell(row) + "</td>"
1868
- ).join("") + "</tr>").join("")
1869
- return "<table><thead>" + head + "</thead><tbody>" + body + "</tbody></table>"
1870
- }
1871
- const esc = (value) => String(value ?? "").replace(/[&<>"']/g, (char) => ({
1872
- "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;"
1873
- }[char]))
1874
- const preview = (value) => {
1875
- const text = JSON.stringify(value)
1876
- return esc(text.length > 180 ? text.slice(0, 180) + "\u2026" : text)
1877
- }
1878
- const when = (epoch) => {
1879
- const date = new Date(epoch)
1880
- return Number.isNaN(date.getTime()) ? String(epoch) : date.toISOString()
1881
- }
1882
- const clockCard = (epoch) => {
1883
- const date = new Date(epoch)
1884
- if (Number.isNaN(date.getTime())) return esc(String(epoch))
1885
- const iso = date.toISOString()
1886
- return esc(iso.slice(0, 10)) + '<span class="clock-time">' + esc(iso.slice(11, 19)) + " UTC</span>"
1887
- }
1888
-
1889
- async function loadNamespaces() {
1890
- const data = await api("GET", "/namespaces")
1891
- const select = $("namespace")
1892
- const names = data.namespaces && data.namespaces.length ? data.namespaces : [data.default || "default"]
1893
- if (!names.includes(state.namespace)) names.unshift(state.namespace)
1894
- select.innerHTML = names.map((name) =>
1895
- '<option value="' + esc(name) + '">' + esc(name) + "</option>"
1896
- ).join("")
1897
- select.value = state.namespace
1898
- }
1899
-
1900
- async function renderOverview() {
1901
- const [health, shape, clock, journal] = await Promise.all([
1902
- originGet("/health"),
1903
- api("GET", "/state"),
1904
- api("GET", "/clock"),
1905
- api("GET", "/requests?limit=8")
1906
- ])
1907
- state.shape = shape
1908
- $("overview-cards").innerHTML = cards([
1909
- { k: "Service", v: esc(health.service || "${name}") },
1910
- { k: "Status", v: esc(health.status || "ok") },
1911
- { k: "Namespace", v: esc(state.namespace) },
1912
- { k: "Collections", v: String(shape.collections.length) },
1913
- { k: "Records", v: String(shape.collections.reduce((sum, item) => sum + item.count, 0)) },
1914
- { k: "Clock", v: clockCard(clock.now) }
1915
- ])
1916
- const requests = (journal && journal.requests) || []
1917
- $("overview-requests").innerHTML = table(
1918
- [
1919
- { label: "Method", cell: (row) => esc(row.method) },
1920
- { label: "Path", cell: (row) => esc(row.path) },
1921
- { label: "Status", cell: (row) => '<span class="status-' + String(row.status).charAt(0) + '">' + esc(row.status) + "</span>" },
1922
- { label: "Operation", cell: (row) => esc(row.operationId || "") }
1923
- ],
1924
- requests
1925
- )
1926
- }
1927
-
1928
- function schemaChips(collection) {
1929
- if (!collection || collection.fields.length === 0) {
1930
- return '<p class="empty">No fields yet. Add a record or declare the collection on the service.</p>'
1931
- }
1932
- return '<div class="chips">' + collection.fields.map((field) =>
1933
- '<span class="chip">' + esc(field.name) + ' <i>' + esc(field.kind) + (field.optional ? "?" : "") + "</i></span>"
1934
- ).join("") + "</div>"
1935
- }
1936
-
1937
- async function renderState() {
1938
- const shape = await api("GET", "/state")
1939
- state.shape = shape
1940
- const host = $("collections")
1941
- if (shape.collections.length === 0) {
1942
- host.innerHTML = '<p class="empty">This namespace has no collections yet.</p>'
1943
- $("schema").innerHTML = ""
1944
- $("records").innerHTML = ""
1945
- return
1946
- }
1947
- if (!shape.collections.some((item) => item.name === state.collection)) {
1948
- state.collection = shape.collections[0].name
1949
- }
1950
- host.innerHTML = shape.collections.map((item) =>
1951
- '<button type="button" class="collection" data-collection="' + esc(item.name) + '" aria-current="' +
1952
- (item.name === state.collection ? "true" : "false") + '"><strong>' + esc(item.label) +
1953
- '</strong><small>' + esc(item.count) + " \xB7 " + esc(item.source) + "</small></button>"
1954
- ).join("")
1955
- const selected = shape.collections.find((item) => item.name === state.collection)
1956
- $("schema").innerHTML = "<h3>" + esc(selected.label) + "</h3>" +
1957
- (selected.description ? "<p class=" + '"lede">' + esc(selected.description) + "</p>" : "") +
1958
- schemaChips(selected)
1959
- const page = await api("GET", "/state/" + encodeURIComponent(state.collection) + "?limit=50")
1960
- const rows = page.records.map((record) => ({
1961
- ...record,
1962
- attrs: ' class="clickable" data-id="' + esc(record.id) + '"'
1963
- }))
1964
- $("records").innerHTML = table(
1965
- [
1966
- { label: "Id", cell: (row) => "<code>" + esc(row.id) + "</code>" },
1967
- { label: "Seq", cell: (row) => esc(row.seq) },
1968
- { label: "Value", cell: (row) => preview(row.value) }
1969
- ],
1970
- rows
1971
- )
1972
- }
1973
-
1974
- async function renderClock() {
1975
- const clock = await api("GET", "/clock")
1976
- $("clock-readout").innerHTML = "<div class='k'>Now</div><div class='v'>" + esc(when(clock.now)) +
1977
- "</div><p>" + esc(clock.now) + " ms \xB7 offset " + esc(clock.offsetMs) + " ms " +
1978
- (clock.frozen ? "<span class='badge warn'>frozen</span>" : "<span class='badge ok'>live</span>") + "</p>"
1979
- $("freeze").textContent = clock.frozen ? "Unfreeze" : "Freeze"
1980
- $("freeze").dataset.frozen = clock.frozen ? "1" : "0"
1981
- }
1982
-
1983
- async function renderFaults() {
1984
- const [faults, presets] = await Promise.all([
1985
- api("GET", "/faults"),
1986
- api("GET", "/faults/presets").catch(() => ({ presets: [] }))
1987
- ])
1988
- const select = $("fault-preset")
1989
- const current = select.value
1990
- const list = presets.presets || []
1991
- select.innerHTML = '<option value="">Custom rule</option>' + list.map((preset) =>
1992
- '<option value="' + esc(preset.name) + '">' + esc(preset.name) + "</option>"
1993
- ).join("")
1994
- select.value = current
1995
- const rules = faults.faults || []
1996
- $("fault-list").innerHTML = table(
1997
- [
1998
- { label: "Id", cell: (row) => esc(row.id) },
1999
- { label: "Match", cell: (row) => esc([row.method, row.pathPrefix, row.operationId].filter(Boolean).join(" ") || "all") },
2000
- { label: "Effect", cell: (row) => esc(row.status ?? row.effect ?? (row.drop ? "drop" : row.latencyMs || "")) }
2001
- ],
2002
- rules
2003
- )
2004
- }
2005
-
2006
- async function renderJournal() {
2007
- const journal = await api("GET", "/requests?limit=100")
2008
- $("journal").innerHTML = table(
2009
- [
2010
- { label: "When", cell: (row) => esc(row.at || "") },
2011
- { label: "Method", cell: (row) => esc(row.method) },
2012
- { label: "Path", cell: (row) => esc(row.path) },
2013
- { label: "Status", cell: (row) => esc(row.status) },
2014
- { label: "ms", cell: (row) => esc(row.durationMs) }
2015
- ],
2016
- journal.requests || []
2017
- )
2018
- }
2019
-
2020
- async function renderRoutes() {
2021
- const data = await api("GET", "/")
2022
- const routes = data.routes || []
2023
- $("route-list").innerHTML = routes.map((route) => {
2024
- const extra = STANDARD.has(route) ? "" : " <span class='badge'>extension</span>"
2025
- return '<div class="route"><span class="method">' + esc(route.split(" ")[0]) +
2026
- '</span><span>' + esc(route.split(" ").slice(1).join(" ")) + extra +
2027
- '</span><button class="btn" type="button" data-route="' + esc(route) + '">Use</button></div>'
2028
- }).join("")
2029
- }
2030
-
2031
- const renderers = {
2032
- overview: renderOverview,
2033
- state: renderState,
2034
- clock: renderClock,
2035
- faults: renderFaults,
2036
- journal: renderJournal,
2037
- routes: renderRoutes
2038
- }
2039
-
2040
- async function refresh() {
2041
- clearError()
2042
- if (state.view in renderers) await renderers[state.view]()
2043
- }
2044
-
2045
- $("namespace").addEventListener("change", () => {
2046
- state.namespace = $("namespace").value
2047
- refresh().catch(showError)
2048
- })
2049
- keyInput.addEventListener("change", () => {
2050
- state.key = keyInput.value.trim()
2051
- sessionStorage.setItem("mockingbird-admin-key", state.key)
2052
- refresh().catch(showError)
2053
- })
2054
- $("refresh").addEventListener("click", () => refresh().catch(showError))
2055
-
2056
- $("collections").addEventListener("click", (event) => {
2057
- const button = event.target.closest("[data-collection]")
2058
- if (!button) return
2059
- state.collection = button.dataset.collection
2060
- renderState().catch(showError)
2061
- })
2062
- $("records").addEventListener("click", (event) => {
2063
- const row = event.target.closest("[data-id]")
2064
- if (!row) return
2065
- openEditor(row.dataset.id).catch(showError)
2066
- })
2067
-
2068
- const editor = $("editor")
2069
- async function openEditor(id) {
2070
- state.editing = id || null
2071
- $("editor-title").textContent = id ? "Edit record" : "New record"
2072
- $("editor-id").value = id || ""
2073
- $("editor-id").readOnly = Boolean(id)
2074
- $("editor-delete").hidden = !id
2075
- if (id) {
2076
- const record = await api("GET", "/state/" + encodeURIComponent(state.collection) + "/" + encodeURIComponent(id))
2077
- $("editor-value").value = JSON.stringify(record.value, null, 2)
2078
- } else {
2079
- $("editor-value").value = "{\\n \\n}"
2080
- }
2081
- editor.showModal()
2082
- }
2083
- $("new-record").addEventListener("click", () => openEditor(null).catch(showError))
2084
- $("editor-form").addEventListener("submit", (event) => {
2085
- const submitter = event.submitter
2086
- if (!submitter || submitter.value !== "save") return
2087
- event.preventDefault()
2088
- let value
2089
- try { value = JSON.parse($("editor-value").value) }
2090
- catch { showError(new Error("Value is not JSON")); return }
2091
- const id = $("editor-id").value.trim()
2092
- const path = "/state/" + encodeURIComponent(state.collection)
2093
- const request = state.editing
2094
- ? api("PUT", path + "/" + encodeURIComponent(id), { value })
2095
- : api("POST", path, { id: id || undefined, value })
2096
- request.then(() => { editor.close(); return renderState() }).catch(showError)
2097
- })
2098
- $("editor-delete").addEventListener("click", () => {
2099
- const id = state.editing
2100
- if (!id) return
2101
- api("DELETE", "/state/" + encodeURIComponent(state.collection) + "/" + encodeURIComponent(id))
2102
- .then(() => { editor.close(); return renderState() })
2103
- .catch(showError)
2104
- })
2105
-
2106
- document.querySelectorAll("[data-advance]").forEach((button) => {
2107
- button.addEventListener("click", () => {
2108
- api("POST", "/clock", { advance: Number(button.dataset.advance) }).then(renderClock).catch(showError)
2109
- })
2110
- })
2111
- $("freeze").addEventListener("click", () => {
2112
- const frozen = $("freeze").dataset.frozen === "1"
2113
- api("POST", "/clock", { freeze: !frozen }).then(renderClock).catch(showError)
2114
- })
2115
- $("clock-reset").addEventListener("click", () => {
2116
- api("POST", "/clock", { reset: true }).then(renderClock).catch(showError)
2117
- })
2118
- $("clock-set").addEventListener("submit", (event) => {
2119
- event.preventDefault()
2120
- const raw = $("clock-instant").value.trim()
2121
- const set = /^-?\\d+$/.test(raw) ? Number(raw) : raw
2122
- api("POST", "/clock", { set }).then(renderClock).catch(showError)
2123
- })
2124
-
2125
- $("fault-form").addEventListener("submit", (event) => {
2126
- event.preventDefault()
2127
- const preset = $("fault-preset").value
2128
- const body = preset
2129
- ? { preset }
2130
- : {
2131
- status: Number($("fault-status").value),
2132
- ...($("fault-path").value ? { pathPrefix: $("fault-path").value } : {}),
2133
- ...($("fault-method").value ? { method: $("fault-method").value } : {})
2134
- }
2135
- if (!preset && !Number.isFinite(body.status)) {
2136
- showError(new Error("Status must be a number, or choose a preset"))
2137
- return
2138
- }
2139
- api("POST", "/faults", body).then(renderFaults).catch(showError)
2140
- })
2141
- $("fault-clear").addEventListener("click", () => api("DELETE", "/faults").then(renderFaults).catch(showError))
2142
- $("journal-clear").addEventListener("click", () => api("DELETE", "/requests").then(renderJournal).catch(showError))
2143
-
2144
- $("route-list").addEventListener("click", (event) => {
2145
- const button = event.target.closest("[data-route]")
2146
- if (!button) return
2147
- state.route = button.dataset.route
2148
- $("route-title").textContent = state.route
2149
- const method = state.route.split(" ")[0]
2150
- $("route-body").disabled = method === "GET" || method === "DELETE"
2151
- })
2152
- $("route-form").addEventListener("submit", async (event) => {
2153
- event.preventDefault()
2154
- if (!state.route) return showError(new Error("Choose a route first"))
2155
- const [method, path] = [state.route.split(" ")[0], state.route.split(" ").slice(1).join(" ")]
2156
- const concrete = path.replace(/:([A-Za-z0-9_]+)/g, (_, key) => prompt("Value for " + key) || "")
2157
- let body
2158
- if (method !== "GET" && method !== "DELETE" && $("route-body").value.trim()) {
2159
- try { body = JSON.parse($("route-body").value) }
2160
- catch { return showError(new Error("Body is not JSON")) }
2161
- }
2162
- try {
2163
- const data = await api(method, concrete, body)
2164
- $("route-result").textContent = JSON.stringify(data, null, 2)
2165
- } catch (error) {
2166
- showError(error)
2167
- }
2168
- })
2169
-
2170
- function mountPanels(panels) {
2171
- const nav = $("nav")
2172
- const views = $("views")
2173
- for (const panel of panels) {
2174
- const button = document.createElement("button")
2175
- button.type = "button"
2176
- button.dataset.view = panel.id
2177
- button.textContent = panel.title
2178
- nav.append(button)
2179
- const section = document.createElement("section")
2180
- section.className = "view"
2181
- section.id = "view-" + panel.id
2182
- section.hidden = true
2183
- const title = document.createElement("h2")
2184
- title.textContent = panel.title
2185
- const lede = document.createElement("p")
2186
- lede.className = "lede"
2187
- lede.textContent = panel.description || ""
2188
- const body = document.createElement("div")
2189
- body.className = "panel-body"
2190
- body.id = "panel-" + panel.id
2191
- body.innerHTML = panel.html || ""
2192
- section.append(title, lede, body)
2193
- views.append(section)
2194
- if (panel.script) {
2195
- try {
2196
- const run = new Function("root", "api", panel.script)
2197
- run(body, panelApi)
2198
- } catch (error) {
2199
- const note = document.createElement("p")
2200
- note.className = "banner show"
2201
- note.textContent = error instanceof Error ? error.message : String(error)
2202
- body.append(note)
2203
- }
2204
- }
2205
- }
2206
- }
2207
-
2208
- loadNamespaces()
2209
- .then(() => api("GET", "/ui/manifest"))
2210
- .then((manifest) => { mountPanels((manifest && manifest.panels) || []); return refresh() })
2211
- .catch(showError)
2212
- })()
2213
- </script>
3014
+ ${script}
2214
3015
  </body>
2215
3016
  </html>`;
2216
3017
  };
@@ -2227,10 +3028,10 @@ var json2 = (body) => new Response(JSON.stringify(body), {
2227
3028
  });
2228
3029
  var adminUiRoutes = (service, ui) => {
2229
3030
  const shell = () => renderAdminDocument(service);
2230
- const document2 = () => ui?.render ? ui.render({ service, defaultHtml: shell }) : shell();
3031
+ const document3 = () => ui?.render ? ui.render({ service, defaultHtml: shell }) : shell();
2231
3032
  return {
2232
- "GET /ui": () => htmlResponse(document2()),
2233
- "GET /ui/": () => htmlResponse(document2()),
3033
+ "GET /ui": () => htmlResponse(document3()),
3034
+ "GET /ui/": () => htmlResponse(document3()),
2234
3035
  "GET /ui/manifest": () => json2({
2235
3036
  service,
2236
3037
  panels: (ui?.panels ?? []).map((panel) => ({
@@ -2256,11 +3057,11 @@ var EXTENSION_KEYS = {
2256
3057
  };
2257
3058
 
2258
3059
  // ../../openapi/metadata/dist/read.js
2259
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3060
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2260
3061
  var extensionOf = (holder, key) => holder[key];
2261
3062
  var operationMetadata = (operation) => {
2262
3063
  const raw = extensionOf(operation, EXTENSION_KEYS.operation);
2263
- const ext = isRecord2(raw) ? raw : {};
3064
+ const ext = isRecord3(raw) ? raw : {};
2264
3065
  const supported = ext.supported ?? true;
2265
3066
  const parity = ext.parity ?? {};
2266
3067
  return {
@@ -2370,9 +3171,9 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
2370
3171
  this.name = "OperationRegistryError";
2371
3172
  }
2372
3173
  };
2373
- var verifyOperations = (document2, handlers) => {
3174
+ var verifyOperations = (document3, handlers) => {
2374
3175
  const problems = [];
2375
- const operations = listOperations(document2);
3176
+ const operations = listOperations(document3);
2376
3177
  const seen = /* @__PURE__ */ new Set();
2377
3178
  for (const operation of operations) {
2378
3179
  if (seen.has(operation.operationId))
@@ -2488,7 +3289,7 @@ var SAMPLE = 25;
2488
3289
  var WALK_LIMIT = 1e4;
2489
3290
  var SKIP_CTORS = /* @__PURE__ */ new Set(["Hono", "HonoRequest", "Router"]);
2490
3291
  var fail = (status, message) => ({ ok: false, status, message });
2491
- var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3292
+ var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2492
3293
  var kindOf = (value) => {
2493
3294
  if (value === null)
2494
3295
  return "null";
@@ -2587,7 +3388,7 @@ var absorb = (accum, value) => {
2587
3388
  const kind = kindOf(value);
2588
3389
  accum.kinds.add(kind);
2589
3390
  accum.present++;
2590
- if (!isRecord3(value))
3391
+ if (!isRecord4(value))
2591
3392
  return;
2592
3393
  for (const [key, child] of Object.entries(value)) {
2593
3394
  const nested = accum.nested.get(key) ?? blankAccum(key);
@@ -2612,7 +3413,7 @@ var inferFields = (records) => {
2612
3413
  if (records.length === 0)
2613
3414
  return [];
2614
3415
  const sample = records.slice(0, SAMPLE);
2615
- const objects = sample.filter((record) => isRecord3(record.value));
3416
+ const objects = sample.filter((record) => isRecord4(record.value));
2616
3417
  if (objects.length === 0) {
2617
3418
  const kinds = new Set(sample.map((record) => kindOf(record.value)));
2618
3419
  const list = [...kinds];
@@ -2799,7 +3600,7 @@ var patchStateRecord = (scope, name, id, value) => {
2799
3600
  const parsed = jsonValue(value);
2800
3601
  if (!parsed.ok)
2801
3602
  return parsed;
2802
- const next = isRecord3(current.value.value) && isRecord3(parsed.value) ? { ...current.value.value, ...parsed.value } : parsed.value;
3603
+ const next = isRecord4(current.value.value) && isRecord4(parsed.value) ? { ...current.value.value, ...parsed.value } : parsed.value;
2803
3604
  return replaceStateRecord(scope, name, id, next);
2804
3605
  };
2805
3606
  var deleteStateRecord = (scope, name, id) => {
@@ -2867,7 +3668,7 @@ var stateAdminRoutes = (routes) => {
2867
3668
  const scope = open(namespace);
2868
3669
  if (!scope.ok)
2869
3670
  return fromResult(scope, 201);
2870
- if (!isRecord3(body) || !("value" in body)) {
3671
+ if (!isRecord4(body) || !("value" in body)) {
2871
3672
  return adminError2(400, 'expected {"id?": "<id>", "value": <json>}');
2872
3673
  }
2873
3674
  const id = body.id;
@@ -2885,7 +3686,7 @@ var stateAdminRoutes = (routes) => {
2885
3686
  const scope = open(namespace);
2886
3687
  if (!scope.ok)
2887
3688
  return fromResult(scope, 200);
2888
- if (!isRecord3(body) || !("value" in body))
3689
+ if (!isRecord4(body) || !("value" in body))
2889
3690
  return adminError2(400, 'expected {"value": <json>}');
2890
3691
  const replaced = replaceStateRecord(scope.value, params.collection ?? "", params.id ?? "", body.value);
2891
3692
  if (replaced.ok)
@@ -2896,7 +3697,7 @@ var stateAdminRoutes = (routes) => {
2896
3697
  const scope = open(namespace);
2897
3698
  if (!scope.ok)
2898
3699
  return fromResult(scope, 200);
2899
- if (!isRecord3(body) || !("value" in body))
3700
+ if (!isRecord4(body) || !("value" in body))
2900
3701
  return adminError2(400, 'expected {"value": <json>}');
2901
3702
  const patched = patchStateRecord(scope.value, params.collection ?? "", params.id ?? "", body.value);
2902
3703
  if (patched.ok)
@@ -2916,7 +3717,7 @@ var stateAdminRoutes = (routes) => {
2916
3717
  };
2917
3718
 
2918
3719
  // ../core/dist/version.js
2919
- var PACKAGE_VERSION = true ? "0.1.0" : UNRELEASED_VERSION;
3720
+ var PACKAGE_VERSION = true ? "0.2.0" : UNRELEASED_VERSION;
2920
3721
 
2921
3722
  // ../core/dist/signing.js
2922
3723
  var encoder = new TextEncoder();
@@ -3253,9 +4054,9 @@ var createWebhookHub = (options) => {
3253
4054
  };
3254
4055
  var json4 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
3255
4056
  var adminError3 = (status, message) => json4(status, { error: { type: "mockingbird_admin", message } });
3256
- var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4057
+ var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3257
4058
  var parseEndpoint = (value) => {
3258
- if (!isRecord4(value) || typeof value.url !== "string")
4059
+ if (!isRecord5(value) || typeof value.url !== "string")
3259
4060
  return "each endpoint needs a url";
3260
4061
  try {
3261
4062
  new URL(value.url);
@@ -3272,12 +4073,12 @@ var parseEndpoint = (value) => {
3272
4073
  const events = value.events ?? value.enabledEvents;
3273
4074
  if (Array.isArray(events))
3274
4075
  endpoint.events = events.map(String);
3275
- if (isRecord4(value.tags)) {
4076
+ if (isRecord5(value.tags)) {
3276
4077
  endpoint.tags = Object.fromEntries(Object.entries(value.tags).map(([k, v]) => [k, String(v)]));
3277
4078
  }
3278
4079
  if (typeof value.account === "string")
3279
4080
  endpoint.tags = { ...endpoint.tags, account: value.account };
3280
- if (isRecord4(value.headers)) {
4081
+ if (isRecord5(value.headers)) {
3281
4082
  endpoint.headers = Object.fromEntries(Object.entries(value.headers).map(([k, v]) => [k, String(v)]));
3282
4083
  }
3283
4084
  return endpoint;
@@ -3304,7 +4105,7 @@ var webhookAdminRoutes = (hub) => ({
3304
4105
  return json4(200, { status: "ok" });
3305
4106
  },
3306
4107
  "POST /webhooks/faults": ({ body, namespace }) => {
3307
- if (!isRecord4(body) || !["duplicate", "reorder", "drop"].includes(String(body.mode))) {
4108
+ if (!isRecord5(body) || !["duplicate", "reorder", "drop"].includes(String(body.mode))) {
3308
4109
  return adminError3(400, "mode must be duplicate, reorder or drop");
3309
4110
  }
3310
4111
  const fault = { mode: body.mode };
@@ -3320,7 +4121,7 @@ var webhookAdminRoutes = (hub) => ({
3320
4121
  }))
3321
4122
  }),
3322
4123
  "PUT /webhook-endpoints": ({ body, namespace }) => {
3323
- const list = Array.isArray(body) ? body : isRecord4(body) ? body.endpoints : void 0;
4124
+ const list = Array.isArray(body) ? body : isRecord5(body) ? body.endpoints : void 0;
3324
4125
  if (!Array.isArray(list))
3325
4126
  return adminError3(400, "expected [{url, secret?, events?}]");
3326
4127
  const parsed = [];
@@ -3388,8 +4189,8 @@ var DroppedConnectionError = class extends TypeError {
3388
4189
  this.name = "TypeError";
3389
4190
  }
3390
4191
  };
3391
- var operationMatcher = (document2) => {
3392
- const matchers = listOperations(document2).map((operation) => ({
4192
+ var operationMatcher = (document3) => {
4193
+ const matchers = listOperations(document3).map((operation) => ({
3393
4194
  operationId: operation.operationId,
3394
4195
  method: operation.method.toUpperCase(),
3395
4196
  pattern: new RegExp(`^${operation.path.split("/").map((segment) => segment.startsWith("{") ? "[^/]+" : segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("/")}/?$`),
@@ -3484,10 +4285,10 @@ var createRuntime = (options) => {
3484
4285
  const ensureBranch = (namespace, branch2, at) => {
3485
4286
  if (!BRANCH_PATTERN2.test(branch2))
3486
4287
  throw new RangeError(`branch must match ${BRANCH_PATTERN2}`);
3487
- const history = timeline(namespace);
4288
+ const history2 = timeline(namespace);
3488
4289
  if (branch2 === "main") {
3489
4290
  if (at !== void 0) {
3490
- const point = history.checkout("main", at);
4291
+ const point = history2.checkout("main", at);
3491
4292
  restoreNamespace(sqlite, storageNamespace(namespace), point.value.snapshot);
3492
4293
  captured.set(namespace, point.value.snapshot);
3493
4294
  rng.setState(point.value.rngState);
@@ -3500,10 +4301,10 @@ var createRuntime = (options) => {
3500
4301
  return namespace;
3501
4302
  }
3502
4303
  const storage = physicalBranch(namespace, branch2);
3503
- if (!history.hasBranch(branch2)) {
4304
+ if (!history2.hasBranch(branch2)) {
3504
4305
  if (at === void 0)
3505
- history.commit(capture(namespace));
3506
- const point = history.fork(branch2, at === void 0 ? {} : { from: at });
4306
+ history2.commit(capture(namespace));
4307
+ const point = history2.fork(branch2, at === void 0 ? {} : { from: at });
3507
4308
  const branchRng = createRng(options.seed ?? 0);
3508
4309
  if (point)
3509
4310
  branchRng.setState(point.value.rngState);
@@ -3512,8 +4313,8 @@ var createRuntime = (options) => {
3512
4313
  restoreNamespace(sqlite, storageNamespace(storage), point.value.snapshot);
3513
4314
  if (point)
3514
4315
  captured.set(storage, point.value.snapshot);
3515
- } else if (at !== void 0 && history.head(branch2)?.id !== at) {
3516
- const point = history.checkout(branch2, at);
4316
+ } else if (at !== void 0 && history2.head(branch2)?.id !== at) {
4317
+ const point = history2.checkout(branch2, at);
3517
4318
  if (!instances.has(storage)) {
3518
4319
  const branchRng = createRng(options.seed ?? 0);
3519
4320
  branchRng.setState(point.value.rngState);
@@ -3524,7 +4325,7 @@ var createRuntime = (options) => {
3524
4325
  captured.set(storage, point.value.snapshot);
3525
4326
  } else {
3526
4327
  if (!instances.has(storage)) {
3527
- const point = history.head(branch2);
4328
+ const point = history2.head(branch2);
3528
4329
  const branchRng = createRng(options.seed ?? 0);
3529
4330
  if (point)
3530
4331
  branchRng.setState(point.value.rngState);
@@ -3548,8 +4349,8 @@ var createRuntime = (options) => {
3548
4349
  const checkout = (checkpointId, checkoutOptions = {}) => {
3549
4350
  const namespace = checkoutOptions.namespace ?? DEFAULT_NAMESPACE;
3550
4351
  const branchName = checkoutOptions.branch ?? "main";
3551
- const history = timeline(namespace);
3552
- const point = history.checkout(branchName, checkpointId);
4352
+ const history2 = timeline(namespace);
4353
+ const point = history2.checkout(branchName, checkpointId);
3553
4354
  const storage = ensureBranch(namespace, branchName);
3554
4355
  restoreNamespace(sqlite, storageNamespace(storage), point.value.snapshot);
3555
4356
  captured.set(storage, point.value.snapshot);
@@ -3599,9 +4400,9 @@ var createRuntime = (options) => {
3599
4400
  instance(name);
3600
4401
  restoreNamespace(sqlite, storageNamespace(name), from);
3601
4402
  captured.set(name, from);
3602
- const history = timelines.get(name);
3603
- if (history)
3604
- history.commit(capture(name), { branch: "main" });
4403
+ const history2 = timelines.get(name);
4404
+ if (history2)
4405
+ history2.commit(capture(name), { branch: "main" });
3605
4406
  else
3606
4407
  timeline(name);
3607
4408
  };
@@ -3830,10 +4631,10 @@ var createRuntime = (options) => {
3830
4631
  },
3831
4632
  release: (name, checkpointId) => timeline(name).release(checkpointId),
3832
4633
  inspect: (name) => {
3833
- const history = timeline(name);
4634
+ const history2 = timeline(name);
3834
4635
  return {
3835
- branches: history.branches(),
3836
- checkpoints: history.checkpoints().map(({ id, branch: branchName, parent, at }) => ({
4636
+ branches: history2.branches(),
4637
+ checkpoints: history2.checkpoints().map(({ id, branch: branchName, parent, at }) => ({
3837
4638
  id,
3838
4639
  branch: branchName,
3839
4640
  parent,
@@ -3848,11 +4649,11 @@ var createRuntime = (options) => {
3848
4649
  } : {},
3849
4650
  routes: {
3850
4651
  ...credentialRoutes(credentials),
3851
- ...options.presets ? presetRoutes(options.presets, runtime) : {},
3852
4652
  ...options.webhooks ? webhookAdminRoutes(options.webhooks) : {},
3853
4653
  ...options.admin?.(runtime) ?? {},
3854
- // Standard state and UI routes win a colliding key. A service adds its own keys
3855
- // beside these; it does not replace `/state` or `/ui`.
4654
+ // Shell routes win a colliding key. Fault presets are one of them: the admin page
4655
+ // maps `presets`, and a service route must not replace that list with a record.
4656
+ ...options.presets ? presetRoutes(options.presets, runtime) : {},
3856
4657
  ...stateAdminRoutes({
3857
4658
  open: stateScope,
3858
4659
  afterWrite: (namespace) => {
@@ -3927,9 +4728,12 @@ var credentialRoutes = (registry) => ({
3927
4728
  }
3928
4729
  });
3929
4730
  var presetRoutes = (presets, runtime) => ({
3930
- "GET /faults/presets": () => adminJson(200, {
3931
- presets: Object.entries(presets).map(([name, preset]) => ({ name, ...preset }))
3932
- }),
4731
+ "GET /faults/presets": () => {
4732
+ const body = {
4733
+ presets: Object.entries(presets).map(([name, preset]) => ({ name, ...preset }))
4734
+ };
4735
+ return adminJson(200, body);
4736
+ },
3933
4737
  "POST /faults/presets/:name": ({ params, body, namespace }) => {
3934
4738
  const name = params.name;
3935
4739
  if (!presets[name])
@@ -4089,7 +4893,7 @@ var invalidField = (errors) => new PaddleError(400, "invalid_field", "Request do
4089
4893
  var badRequest = (detail) => new PaddleError(400, "bad_request", detail);
4090
4894
 
4091
4895
  // src/generated/openapi.ts
4092
- var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Paddle Billing API (Mockingbird subset)","description":"Stateful mock subset of the Paddle Billing API: customers with their addresses and\\nbusinesses, the catalog (products and prices), transactions with computed totals,\\nsubscriptions with their lifecycle (activate, pause, resume, cancel, one-time charges,\\nrenewals) and the events list. Subscriptions come from paid transactions, as in Paddle:\\nthe mock's admin routes stand in for the hosted checkout and the billing engine.\\n","version":"1","x-mockingbird-upstream":{"note":"Hand-authored from https://developer.paddle.com/api-reference/overview and the wire types of @paddle/paddle-node-sdk@3.10.0 (dist/types/**). Every entity carries the fields the SDK reads; enums are trimmed to representative values so generated requests stay meaningful."}},"servers":[{"url":"https://sandbox-api.paddle.com"}],"security":[{"bearerAuth":[]}],"paths":{"/customers":{"get":{"operationId":"ListCustomers","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","description":"Comma-separated customer ids.","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},{"name":"email","in":"query","description":"Comma-separated exact email addresses.","schema":{"type":"string","maxLength":120}},{"name":"search","in":"query","description":"Matches id, name or email (case-insensitive substring).","schema":{"type":"string","maxLength":60}},{"$ref":"#/components/parameters/StatusFilter"}],"responses":{"200":{"description":"Customers, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreateCustomer","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerCreate"}}}},"responses":{"201":{"description":"The created customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/customers/{customer_id}":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"GetCustomer","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateCustomer","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerUpdate"}}}},"responses":{"200":{"description":"The updated customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/customers/{customer_id}/credit-balances":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"GetCustomerCreditBalances","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"One balance per currency the customer holds credit in (none, in the mock)","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"type":"object","required":["customer_id","currency_code","balance"],"properties":{"customer_id":{"type":"string"},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"balance":{"type":"object","required":["available","reserved","used"],"properties":{"available":{"type":"string"},"reserved":{"type":"string"},"used":{"type":"string"}}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/auth-token":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"post":{"operationId":"CreateCustomerAuthToken","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A customer auth token for Paddle.js","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["customer_auth_token","expires_at"],"properties":{"customer_auth_token":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"expires_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/addresses":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"ListAddresses","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}}},{"name":"search","in":"query","schema":{"type":"string","maxLength":60}},{"$ref":"#/components/parameters/StatusFilter"}],"responses":{"200":{"description":"The customer's addresses, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Address"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"CreateAddress","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCreate"}}}},"responses":{"201":{"description":"The created address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/addresses/{address_id}":{"parameters":[{"$ref":"#/components/parameters/CustomerId"},{"$ref":"#/components/parameters/AddressId"}],"get":{"operationId":"GetAddress","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateAddress","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressUpdate"}}}},"responses":{"200":{"description":"The updated address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/businesses":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"ListBusinesses","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}}},{"name":"search","in":"query","schema":{"type":"string","maxLength":60}},{"$ref":"#/components/parameters/StatusFilter"}],"responses":{"200":{"description":"The customer's businesses, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Business"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"CreateBusiness","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessCreate"}}}},"responses":{"201":{"description":"The created business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/businesses/{business_id}":{"parameters":[{"$ref":"#/components/parameters/CustomerId"},{"$ref":"#/components/parameters/BusinessId"}],"get":{"operationId":"GetBusiness","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateBusiness","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessUpdate"}}}},"responses":{"200":{"description":"The updated business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/products":{"get":{"operationId":"ListProducts","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}},{"name":"include","in":"query","description":"\`prices\` embeds each product's prices.","schema":{"type":"string","enum":["prices"]}},{"$ref":"#/components/parameters/StatusFilter"},{"name":"tax_category","in":"query","schema":{"$ref":"#/components/schemas/TaxCategory"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/CatalogType"}}],"responses":{"200":{"description":"Products, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreateProduct","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"}}}},"responses":{"201":{"description":"The created product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/products/{product_id}":{"parameters":[{"$ref":"#/components/parameters/ProductId"}],"get":{"operationId":"GetProduct","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"include","in":"query","schema":{"type":"string","enum":["prices"]}}],"responses":{"200":{"description":"The product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateProduct","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"}}}},"responses":{"200":{"description":"The updated product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/prices":{"get":{"operationId":"ListPrices","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}}},{"name":"product_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}},{"name":"include","in":"query","description":"\`product\` embeds each price's product.","schema":{"type":"string","enum":["product"]}},{"$ref":"#/components/parameters/StatusFilter"},{"name":"recurring","in":"query","schema":{"type":"boolean"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/CatalogType"}}],"responses":{"200":{"description":"Prices, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Price"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreatePrice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceCreate"}}}},"responses":{"201":{"description":"The created price","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/prices/{price_id}":{"parameters":[{"$ref":"#/components/parameters/PriceId"}],"get":{"operationId":"GetPrice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"include","in":"query","schema":{"type":"string","enum":["product"]}}],"responses":{"200":{"description":"The price","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdatePrice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceUpdate"}}}},"responses":{"200":{"description":"The updated price","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transactions":{"get":{"operationId":"ListTransactions","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"name":"per_page","in":"query","schema":{"type":"integer","minimum":1,"maximum":30}},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"transaction","missing":"txn_00000000000000000000000000"}}},{"name":"customer_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},{"name":"subscription_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"subscription","missing":"sub_00000000000000000000000000"}}},{"name":"status","in":"query","description":"Comma-separated statuses.","schema":{"$ref":"#/components/schemas/TransactionStatus"}},{"name":"origin","in":"query","schema":{"$ref":"#/components/schemas/TransactionOrigin"}},{"name":"collection_mode","in":"query","schema":{"$ref":"#/components/schemas/CollectionMode"}},{"name":"invoice_number","in":"query","schema":{"type":"string","maxLength":40}},{"name":"include","in":"query","description":"Comma-separated relations to embed.","schema":{"type":"string","enum":["customer","address","business","customer,address","customer,address,business"]}},{"name":"created_at[GTE]","in":"query","description":"Transactions created at or after this RFC 3339 datetime (\`[LT]\`, \`[LTE]\`, \`[GT]\` and \`updated_at[\u2026]\` work the same way).","schema":{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"}},{"name":"billed_at[GTE]","in":"query","schema":{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"}}],"responses":{"200":{"description":"Transactions, newest first (30 per page)","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreateTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"$ref":"#/components/parameters/TransactionInclude"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionCreate"}}}},"responses":{"201":{"description":"The created transaction, with computed totals","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/transactions/preview":{"post":{"operationId":"PreviewTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionPreviewRequest"}}}},"responses":{"200":{"description":"Totals for the items, nothing stored","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/TransactionPreview"},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/transactions/{transaction_id}":{"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"get":{"operationId":"GetTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/TransactionInclude"}],"responses":{"200":{"description":"The transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"$ref":"#/components/parameters/TransactionInclude"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionUpdate"}}}},"responses":{"200":{"description":"The updated transaction (only \`draft\` and \`ready\` transactions can change)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transactions/{transaction_id}/invoice":{"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"get":{"operationId":"GetTransactionInvoice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"disposition","in":"query","schema":{"type":"string","enum":["attachment","inline"]}}],"responses":{"200":{"description":"A link to the invoice PDF (billed, paid and completed transactions only)","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["url"],"properties":{"url":{"type":"string","x-mockingbird-volatile":{"kind":"url"}}}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transactions/{transaction_id}/revise":{"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"post":{"operationId":"ReviseTransaction","x-mockingbird":{"supported":false,"reason":"Invoice revision (customer, business and address corrections on billed transactions) is not modelled."},"responses":{"200":{"description":"The revised transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}}}}},"/subscriptions":{"get":{"operationId":"ListSubscriptions","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"subscription","missing":"sub_00000000000000000000000000"}}},{"name":"customer_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},{"name":"address_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}}},{"name":"price_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/SubscriptionStatus"}},{"name":"collection_mode","in":"query","schema":{"$ref":"#/components/schemas/CollectionMode"}},{"name":"scheduled_change_action","in":"query","schema":{"type":"string","enum":["cancel","pause","resume"]}}],"responses":{"200":{"description":"Subscriptions, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Subscription"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/subscriptions/{subscription_id}":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"get":{"operationId":"GetSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"include","in":"query","description":"\`next_transaction\` and \`recurring_transaction_details\` embed previews.","schema":{"type":"string","enum":["next_transaction","recurring_transaction_details","next_transaction,recurring_transaction_details"]}}],"responses":{"200":{"description":"The subscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionUpdate"}}}},"responses":{"200":{"description":"The updated subscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/preview":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"patch":{"operationId":"PreviewSubscriptionUpdate","x-mockingbird":{"supported":false,"reason":"Update previews (proration credit/charge summaries) are not modelled; apply the update instead."},"responses":{"200":{"description":"A preview of the update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}}}}},"/subscriptions/{subscription_id}/activate":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"ActivateSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"200":{"description":"The subscription, now active (it must have been trialing)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/pause":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"PauseSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"effective_from":{"type":["string","null"],"enum":["next_billing_period","immediately",null]},"resume_at":{"type":["string","null"],"description":"RFC 3339 datetime to resume at.","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"},"on_resume":{"type":"string","enum":["continue_existing_billing_period","start_new_billing_period"]}}}}}},"responses":{"200":{"description":"The subscription, paused now or scheduled to pause","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/resume":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"ResumeSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["effective_from"],"properties":{"effective_from":{"type":"string","description":"\`immediately\`, or an RFC 3339 datetime to resume at.","oneOf":[{"type":"string","enum":["immediately"]},{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"}]},"on_resume":{"type":"string","enum":["continue_existing_billing_period","start_new_billing_period"]}}}}}},"responses":{"200":{"description":"The subscription, active again or scheduled to resume","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/cancel":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"CancelSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"effective_from":{"type":["string","null"],"enum":["next_billing_period","immediately",null]}}}}}},"responses":{"200":{"description":"The subscription, canceled now or scheduled to cancel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/charge":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"CreateSubscriptionCharge","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["effective_from","items"],"properties":{"effective_from":{"type":"string","enum":["next_billing_period","immediately"]},"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"on_payment_failure":{"type":"string","enum":["prevent_change","apply_change"]}}}}}},"responses":{"200":{"description":"The subscription; an immediate charge also creates a completed \`subscription_charge\` transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/charge/preview":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"PreviewSubscriptionCharge","x-mockingbird":{"supported":false,"reason":"One-time charge previews are not modelled; create the charge instead."},"responses":{"200":{"description":"A preview of the charge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}}}}},"/subscriptions/{subscription_id}/update-payment-method-transaction":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"get":{"operationId":"GetSubscriptionPaymentMethodChangeTransaction","x-mockingbird":{"supported":false,"reason":"Payment method changes go through the hosted checkout, which the mock does not serve."},"responses":{"200":{"description":"A zero-amount transaction for updating the payment method","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}}}}},"/events":{"get":{"operationId":"ListEvents","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"}],"responses":{"200":{"description":"Every event the account produced, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/notification-settings":{"get":{"operationId":"ListNotificationSettings","x-mockingbird":{"supported":false,"reason":"Notification destinations are configured on the mock (\`--webhook-url\`, \`PUT /__admin/webhook-endpoints\`), not through the API."},"responses":{"200":{"description":"Notification settings","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"CreateNotificationSetting","x-mockingbird":{"supported":false,"reason":"Notification destinations are configured on the mock (\`--webhook-url\`, \`PUT /__admin/webhook-endpoints\`), not through the API."},"responses":{"201":{"description":"The created notification setting","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/discounts":{"get":{"operationId":"ListDiscounts","x-mockingbird":{"supported":false,"reason":"Discounts are not modelled; totals carry a zero discount."},"responses":{"200":{"description":"Discounts","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"CreateDiscount","x-mockingbird":{"supported":false,"reason":"Discounts are not modelled; totals carry a zero discount."},"responses":{"201":{"description":"The created discount","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/adjustments":{"get":{"operationId":"ListAdjustments","x-mockingbird":{"supported":false,"reason":"Refunds and credits (adjustments) are not modelled."},"responses":{"200":{"description":"Adjustments","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"CreateAdjustment","x-mockingbird":{"supported":false,"reason":"Refunds and credits (adjustments) are not modelled."},"responses":{"201":{"description":"The created adjustment","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/customers/{customer_id}/portal-sessions":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"post":{"operationId":"CreateCustomerPortalSession","x-mockingbird":{"supported":false,"reason":"The hosted customer portal is not served; \`management_urls\` on a subscription point at placeholder links."},"responses":{"201":{"description":"The created portal session","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"\`Authorization: Bearer pdl_sdbx_apikey_\u2026\` (any key; none is 403 \`authentication_missing\`)"}},"parameters":{"After":{"name":"after","in":"query","description":"Return entities after this id (the cursor from \`meta.pagination.next\`).","schema":{"type":"string","maxLength":40}},"PerPage":{"name":"per_page","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},"OrderBy":{"name":"order_by","in":"query","schema":{"type":"string","enum":["id[ASC]","id[DESC]"]}},"StatusFilter":{"name":"status","in":"query","description":"Comma-separated statuses.","schema":{"type":"string","enum":["active","archived","active,archived"]}},"TransactionInclude":{"name":"include","in":"query","description":"Comma-separated relations to embed.","schema":{"type":"string","enum":["customer","address","business","customer,address","customer,address,business"]}},"CustomerId":{"name":"customer_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},"AddressId":{"name":"address_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}}},"BusinessId":{"name":"business_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}}},"ProductId":{"name":"product_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}},"PriceId":{"name":"price_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}}},"TransactionId":{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"transaction","missing":"txn_00000000000000000000000000"}}},"SubscriptionId":{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"subscription","missing":"sub_00000000000000000000000000"}}}},"responses":{"BadRequest":{"description":"Validation failed (\`invalid_field\`, with \`errors[]\`) or the request is malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Missing, malformed or rejected API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"No such entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"The change conflicts with existing state (a customer with that email exists)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"schemas":{"RequestId":{"type":"string","x-mockingbird-volatile":{"kind":"opaque"}},"Meta":{"type":"object","required":["request_id"],"properties":{"request_id":{"$ref":"#/components/schemas/RequestId"}}},"MetaPaginated":{"type":"object","required":["request_id","pagination"],"properties":{"request_id":{"$ref":"#/components/schemas/RequestId"},"pagination":{"type":"object","required":["per_page","next","has_more","estimated_total"],"properties":{"per_page":{"type":"integer"},"next":{"type":"string","x-mockingbird-volatile":{"kind":"url"}},"has_more":{"type":"boolean"},"estimated_total":{"type":"integer"}}}}},"ErrorResponse":{"type":"object","required":["error","meta"],"properties":{"error":{"type":"object","required":["type","code","detail","documentation_url"],"properties":{"type":{"type":"string","enum":["request_error","api_error"]},"code":{"type":"string"},"detail":{"type":"string"},"documentation_url":{"type":"string"},"errors":{"type":"array","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"Timestamp":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"NullableTimestamp":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"Status":{"type":"string","enum":["active","archived"]},"CatalogType":{"type":"string","enum":["standard","custom"]},"CurrencyCode":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY"]},"CountryCode":{"type":"string","enum":["US","GB","DE","FR","CA","AU","NL","ES","IE","JP"]},"TaxCategory":{"type":"string","enum":["standard","saas","digital-goods","ebooks","implementation-services","professional-services","software-programming-services","training-services","website-hosting"]},"TaxMode":{"type":"string","enum":["account_setting","external","internal","location"]},"Interval":{"type":"string","enum":["day","week","month","year"]},"CollectionMode":{"type":"string","enum":["automatic","manual"]},"TransactionStatus":{"type":"string","enum":["draft","ready","billed","paid","completed","canceled","past_due"]},"TransactionOrigin":{"type":"string","enum":["api","subscription_charge","subscription_payment_method_change","subscription_recurring","subscription_update","web"]},"SubscriptionStatus":{"type":"string","enum":["active","canceled","past_due","paused","trialing"]},"CustomData":{"type":["object","null"],"description":"Your own key-value data, echoed back unchanged.","maxProperties":10,"additionalProperties":{"type":["string","number","boolean","null"]}},"ImportMeta":{"type":["object","null"],"required":["imported_from"],"properties":{"external_id":{"type":["string","null"]},"imported_from":{"type":"string"}}},"Email":{"type":"string","description":"An email address.","pattern":"^[A-Za-z0-9._+-]+@[A-Za-z0-9-]+(\\\\.[A-Za-z0-9-]+)+$","maxLength":120},"Locale":{"type":"string","pattern":"^[a-z]{2}(-[A-Z]{2})?$"},"Money":{"type":"object","required":["amount","currency_code"],"properties":{"amount":{"type":"string","description":"In the currency's lowest unit, as a string of digits.","pattern":"^[0-9]{1,9}$"},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"}}},"TimePeriod":{"type":"object","required":["interval","frequency"],"properties":{"interval":{"$ref":"#/components/schemas/Interval"},"frequency":{"type":"integer","minimum":1,"maximum":365}}},"TrialPeriod":{"type":"object","required":["interval","frequency"],"properties":{"interval":{"$ref":"#/components/schemas/Interval"},"frequency":{"type":"integer","minimum":1,"maximum":365},"requires_payment_method":{"type":"boolean"}}},"PriceQuantity":{"type":"object","required":["minimum","maximum"],"properties":{"minimum":{"type":"integer","minimum":1,"maximum":999},"maximum":{"type":"integer","minimum":1,"maximum":999}}},"UnitPriceOverride":{"type":"object","required":["country_codes","unit_price"],"properties":{"country_codes":{"type":"array","minItems":1,"maxItems":3,"items":{"$ref":"#/components/schemas/CountryCode"}},"unit_price":{"$ref":"#/components/schemas/Money"}}},"Customer":{"type":"object","required":["id","name","email","marketing_consent","status","custom_data","locale","created_at","updated_at","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"customer","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":["string","null"]},"email":{"type":"string"},"marketing_consent":{"type":"boolean"},"status":{"$ref":"#/components/schemas/Status"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"locale":{"type":"string"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"}}},"CustomerResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Customer"},"meta":{"$ref":"#/components/schemas/Meta"}}},"CustomerCreate":{"type":"object","required":["email"],"properties":{"email":{"$ref":"#/components/schemas/Email"},"name":{"type":["string","null"],"maxLength":80},"custom_data":{"$ref":"#/components/schemas/CustomData"},"locale":{"$ref":"#/components/schemas/Locale"}}},"CustomerUpdate":{"type":"object","properties":{"email":{"$ref":"#/components/schemas/Email"},"name":{"type":["string","null"],"maxLength":80},"status":{"$ref":"#/components/schemas/Status"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"locale":{"$ref":"#/components/schemas/Locale"}}},"Address":{"type":"object","required":["id","customer_id","description","first_line","second_line","city","postal_code","region","country_code","custom_data","status","created_at","updated_at","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"address","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"customer_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"description":{"type":["string","null"]},"first_line":{"type":["string","null"]},"second_line":{"type":["string","null"]},"city":{"type":["string","null"]},"postal_code":{"type":["string","null"]},"region":{"type":["string","null"]},"country_code":{"type":"string"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"status":{"$ref":"#/components/schemas/Status"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"}}},"AddressResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Address"},"meta":{"$ref":"#/components/schemas/Meta"}}},"AddressFields":{"type":"object","properties":{"description":{"type":["string","null"],"maxLength":80},"first_line":{"type":["string","null"],"maxLength":120},"second_line":{"type":["string","null"],"maxLength":120},"city":{"type":["string","null"],"maxLength":60},"postal_code":{"type":["string","null"],"maxLength":20},"region":{"type":["string","null"],"maxLength":60},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"AddressCreate":{"allOf":[{"$ref":"#/components/schemas/AddressFields"},{"type":"object","required":["country_code"],"properties":{"country_code":{"$ref":"#/components/schemas/CountryCode"}}}]},"AddressUpdate":{"allOf":[{"$ref":"#/components/schemas/AddressFields"},{"type":"object","properties":{"country_code":{"$ref":"#/components/schemas/CountryCode"},"status":{"$ref":"#/components/schemas/Status"}}}]},"BusinessContact":{"type":"object","required":["email"],"properties":{"name":{"type":["string","null"],"maxLength":80},"email":{"$ref":"#/components/schemas/Email"}}},"Business":{"type":"object","required":["id","customer_id","name","company_number","tax_identifier","status","contacts","created_at","updated_at","custom_data","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"business","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"customer_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"company_number":{"type":["string","null"]},"tax_identifier":{"type":["string","null"]},"status":{"$ref":"#/components/schemas/Status"},"contacts":{"type":["array","null"],"items":{"type":"object","required":["name","email"],"properties":{"name":{"type":["string","null"]},"email":{"type":"string"}}}},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"}}},"BusinessResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Business"},"meta":{"$ref":"#/components/schemas/Meta"}}},"BusinessCreate":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"company_number":{"type":["string","null"],"maxLength":40},"tax_identifier":{"type":["string","null"],"maxLength":40},"contacts":{"type":["array","null"],"maxItems":3,"items":{"$ref":"#/components/schemas/BusinessContact"}},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"BusinessUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"company_number":{"type":["string","null"],"maxLength":40},"tax_identifier":{"type":["string","null"],"maxLength":40},"status":{"$ref":"#/components/schemas/Status"},"contacts":{"type":["array","null"],"maxItems":3,"items":{"$ref":"#/components/schemas/BusinessContact"}},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"Product":{"type":"object","required":["id","name","type","description","tax_category","image_url","custom_data","status","created_at","updated_at","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"product","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/CatalogType"},"description":{"type":["string","null"]},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"image_url":{"type":["string","null"]},"custom_data":{"$ref":"#/components/schemas/CustomData"},"status":{"$ref":"#/components/schemas/Status"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"},"prices":{"type":"array","description":"Present with \`include=prices\`.","items":{"$ref":"#/components/schemas/Price"}}}},"ProductResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Product"},"meta":{"$ref":"#/components/schemas/Meta"}}},"ProductCreate":{"type":"object","required":["name","tax_category"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"type":{"type":["string","null"],"enum":["standard","custom",null]},"description":{"type":["string","null"],"maxLength":500},"image_url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_-]+$","maxLength":200},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"ProductUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"type":{"type":["string","null"],"enum":["standard","custom",null]},"description":{"type":["string","null"],"maxLength":500},"image_url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_-]+$","maxLength":200},"custom_data":{"$ref":"#/components/schemas/CustomData"},"status":{"$ref":"#/components/schemas/Status"}}},"Price":{"type":"object","required":["id","product_id","description","type","name","billing_cycle","trial_period","tax_mode","unit_price","unit_price_overrides","quantity","status","created_at","updated_at","custom_data","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"price","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"product_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"description":{"type":"string"},"type":{"$ref":"#/components/schemas/CatalogType"},"name":{"type":["string","null"]},"billing_cycle":{"oneOf":[{"$ref":"#/components/schemas/TimePeriod"},{"type":"null"}]},"trial_period":{"oneOf":[{"$ref":"#/components/schemas/TrialPeriod"},{"type":"null"}]},"tax_mode":{"$ref":"#/components/schemas/TaxMode"},"unit_price":{"$ref":"#/components/schemas/Money"},"unit_price_overrides":{"type":"array","items":{"$ref":"#/components/schemas/UnitPriceOverride"}},"quantity":{"$ref":"#/components/schemas/PriceQuantity"},"status":{"$ref":"#/components/schemas/Status"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"},"product":{"description":"Present with \`include=product\`.","$ref":"#/components/schemas/Product"}}},"PriceResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Price"},"meta":{"$ref":"#/components/schemas/Meta"}}},"PriceFields":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":120},"name":{"type":["string","null"],"maxLength":80},"type":{"type":["string","null"],"enum":["standard","custom",null]},"billing_cycle":{"oneOf":[{"$ref":"#/components/schemas/TimePeriod"},{"type":"null"}]},"trial_period":{"oneOf":[{"$ref":"#/components/schemas/TrialPeriod"},{"type":"null"}]},"tax_mode":{"$ref":"#/components/schemas/TaxMode"},"unit_price":{"$ref":"#/components/schemas/Money"},"unit_price_overrides":{"type":"array","maxItems":3,"items":{"$ref":"#/components/schemas/UnitPriceOverride"}},"quantity":{"$ref":"#/components/schemas/PriceQuantity"},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"PriceCreate":{"allOf":[{"$ref":"#/components/schemas/PriceFields"},{"type":"object","required":["description","product_id","unit_price"],"properties":{"product_id":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}}}]},"PriceUpdate":{"allOf":[{"$ref":"#/components/schemas/PriceFields"},{"type":"object","properties":{"status":{"$ref":"#/components/schemas/Status"}}}]},"NonCatalogProduct":{"type":"object","required":["name","tax_category"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"description":{"type":["string","null"],"maxLength":500},"image_url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_-]+$","maxLength":200},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"NonCatalogPrice":{"type":"object","description":"A price created for this transaction only (type custom), for an existing product or a new custom product.","required":["description","unit_price"],"properties":{"description":{"type":"string","minLength":1,"maxLength":120},"name":{"type":["string","null"],"maxLength":80},"unit_price":{"$ref":"#/components/schemas/Money"},"billing_cycle":{"oneOf":[{"$ref":"#/components/schemas/TimePeriod"},{"type":"null"}]},"trial_period":{"oneOf":[{"$ref":"#/components/schemas/TrialPeriod"},{"type":"null"}]},"tax_mode":{"$ref":"#/components/schemas/TaxMode"},"quantity":{"$ref":"#/components/schemas/PriceQuantity"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"product_id":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}},"product":{"$ref":"#/components/schemas/NonCatalogProduct"}}},"TransactionItemRequest":{"type":"object","required":["quantity"],"properties":{"quantity":{"type":"integer","minimum":1,"maximum":100},"price_id":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}},"price":{"$ref":"#/components/schemas/NonCatalogPrice"}}},"BillingDetails":{"type":"object","required":["payment_terms"],"properties":{"enable_checkout":{"type":"boolean"},"purchase_order_number":{"type":["string","null"],"maxLength":40},"additional_information":{"type":["string","null"],"maxLength":200},"payment_terms":{"$ref":"#/components/schemas/TimePeriod"}}},"BillingDetailsResponse":{"type":["object","null"],"required":["enable_checkout","purchase_order_number","additional_information","payment_terms"],"properties":{"enable_checkout":{"type":"boolean"},"purchase_order_number":{"type":["string","null"]},"additional_information":{"type":["string","null"]},"payment_terms":{"$ref":"#/components/schemas/TimePeriod"}}},"BillingPeriod":{"type":"object","required":["starts_at","ends_at"],"properties":{"starts_at":{"$ref":"#/components/schemas/Timestamp"},"ends_at":{"$ref":"#/components/schemas/Timestamp"}}},"TransactionFields":{"type":"object","properties":{"customer_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}},"address_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}},"business_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"billing_details":{"oneOf":[{"$ref":"#/components/schemas/BillingDetails"},{"type":"null"}]},"billing_period":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"custom_data":{"$ref":"#/components/schemas/CustomData"},"checkout":{"type":["object","null"],"properties":{"url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_?=&-]+$","maxLength":200}}}}},"TransactionCreate":{"allOf":[{"$ref":"#/components/schemas/TransactionFields"},{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"status":{"type":"string","enum":["draft","ready","billed"]}}}]},"TransactionUpdate":{"allOf":[{"$ref":"#/components/schemas/TransactionFields"},{"type":"object","properties":{"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"status":{"type":"string","enum":["draft","ready","billed","canceled"]}}}]},"TransactionPreviewRequest":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":5,"items":{"allOf":[{"$ref":"#/components/schemas/TransactionItemRequest"},{"type":"object","properties":{"include_in_totals":{"type":"boolean"}}}]}},"customer_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}},"address_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}},"business_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}},"currency_code":{"type":["string","null"],"enum":["USD","EUR","GBP","CAD","AUD","JPY",null]},"address":{"type":["object","null"],"required":["country_code"],"properties":{"postal_code":{"type":["string","null"],"maxLength":20},"country_code":{"$ref":"#/components/schemas/CountryCode"}}},"ignore_trials":{"type":["boolean","null"]}}},"Totals":{"type":"object","required":["subtotal","discount","tax","total"],"properties":{"subtotal":{"type":"string"},"discount":{"type":"string"},"tax":{"type":"string"},"total":{"type":"string"}}},"TransactionTotals":{"type":"object","required":["subtotal","discount","tax","total","credit","credit_to_balance","balance","grand_total","grand_total_tax","fee","earnings","currency_code"],"properties":{"subtotal":{"type":"string"},"discount":{"type":"string"},"tax":{"type":"string"},"total":{"type":"string"},"credit":{"type":"string"},"credit_to_balance":{"type":"string"},"balance":{"type":"string"},"grand_total":{"type":"string"},"grand_total_tax":{"type":"string"},"fee":{"type":["string","null"]},"earnings":{"type":["string","null"]},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"}}},"TaxRateUsed":{"type":"object","required":["tax_rate","totals"],"properties":{"tax_rate":{"type":"string"},"totals":{"$ref":"#/components/schemas/Totals"}}},"LineItem":{"type":"object","required":["id","price_id","quantity","proration","tax_rate","unit_totals","totals","product"],"properties":{"id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"quantity":{"type":"integer"},"proration":{"type":"null"},"tax_rate":{"type":"string"},"unit_totals":{"$ref":"#/components/schemas/Totals"},"totals":{"$ref":"#/components/schemas/Totals"},"product":{"$ref":"#/components/schemas/Product"}}},"TransactionDetails":{"type":"object","required":["tax_rates_used","totals","adjusted_totals","payout_totals","adjusted_payout_totals","line_items"],"properties":{"tax_rates_used":{"type":"array","items":{"$ref":"#/components/schemas/TaxRateUsed"}},"totals":{"$ref":"#/components/schemas/TransactionTotals"},"adjusted_totals":{"type":"object","required":["subtotal","tax","total","grand_total","grand_total_tax","fee","earnings","currency_code","retained_fee"],"properties":{"subtotal":{"type":"string"},"tax":{"type":"string"},"total":{"type":"string"},"grand_total":{"type":"string"},"grand_total_tax":{"type":"string"},"fee":{"type":["string","null"]},"earnings":{"type":["string","null"]},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"retained_fee":{"type":"string"}}},"payout_totals":{"type":"null"},"adjusted_payout_totals":{"type":"null"},"line_items":{"type":"array","items":{"$ref":"#/components/schemas/LineItem"}}}},"PaymentAttempt":{"type":"object","required":["payment_attempt_id","stored_payment_method_id","payment_method_id","amount","status","error_code","method_details","created_at","captured_at"],"properties":{"payment_attempt_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"stored_payment_method_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"payment_method_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"amount":{"type":"string"},"status":{"type":"string","enum":["authorized","authorized_flagged","canceled","captured","error","action_required","pending_no_action_required","created","unknown","dropped"]},"error_code":{"type":["string","null"]},"method_details":{"type":["object","null"],"required":["type","card","paypal","south_korea_local_card","underlying_details"],"properties":{"type":{"type":"string"},"card":{"type":["object","null"],"required":["type","last4","expiry_month","expiry_year","cardholder_name"],"properties":{"type":{"type":"string"},"last4":{"type":"string"},"expiry_month":{"type":"integer"},"expiry_year":{"type":"integer"},"cardholder_name":{"type":"string"}}},"paypal":{"type":"null"},"south_korea_local_card":{"type":"null"},"underlying_details":{"type":"null"}}},"created_at":{"$ref":"#/components/schemas/Timestamp"},"captured_at":{"$ref":"#/components/schemas/NullableTimestamp"}}},"Transaction":{"type":"object","required":["id","status","customer_id","address_id","business_id","custom_data","currency_code","origin","subscription_id","invoice_id","invoice_number","collection_mode","discount_id","billing_details","billing_period","items","details","payments","checkout","created_at","updated_at","billed_at","revised_at"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"transaction","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"status":{"$ref":"#/components/schemas/TransactionStatus"},"customer_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"address_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"business_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"custom_data":{"$ref":"#/components/schemas/CustomData"},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"origin":{"$ref":"#/components/schemas/TransactionOrigin"},"subscription_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"invoice_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"invoice_number":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"opaque"}},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"discount_id":{"type":"null"},"billing_details":{"$ref":"#/components/schemas/BillingDetailsResponse"},"billing_period":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["price_id","price","quantity","proration"],"properties":{"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"price":{"$ref":"#/components/schemas/Price"},"quantity":{"type":"integer"},"proration":{"type":"null"}}}},"details":{"$ref":"#/components/schemas/TransactionDetails"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/PaymentAttempt"}},"checkout":{"type":["object","null"],"required":["url"],"properties":{"url":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"url"}}}},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"revised_at":{"type":"null"},"customer":{"description":"Present with \`include=customer\`.","oneOf":[{"$ref":"#/components/schemas/Customer"},{"type":"null"}]},"address":{"description":"Present with \`include=address\`.","oneOf":[{"$ref":"#/components/schemas/Address"},{"type":"null"}]},"business":{"description":"Present with \`include=business\`.","oneOf":[{"$ref":"#/components/schemas/Business"},{"type":"null"}]}}},"TransactionResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Transaction"},"meta":{"$ref":"#/components/schemas/Meta"}}},"TransactionPreview":{"type":"object","required":["customer_id","address_id","business_id","currency_code","discount_id","customer_ip_address","address","ignore_trials","items","details","available_payment_methods"],"properties":{"customer_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"address_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"business_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"discount_id":{"type":"null"},"customer_ip_address":{"type":"null"},"address":{"type":["object","null"],"required":["postal_code","country_code"],"properties":{"postal_code":{"type":["string","null"]},"country_code":{"type":"string"}}},"ignore_trials":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","required":["price","quantity","include_in_totals","proration"],"properties":{"price":{"$ref":"#/components/schemas/Price"},"quantity":{"type":"integer"},"include_in_totals":{"type":"boolean"},"proration":{"type":"null"}}}},"details":{"type":"object","required":["tax_rates_used","totals","line_items"],"properties":{"tax_rates_used":{"type":"array","items":{"$ref":"#/components/schemas/TaxRateUsed"}},"totals":{"$ref":"#/components/schemas/TransactionTotals"},"line_items":{"type":"array","items":{"type":"object","required":["price_id","quantity","tax_rate","unit_totals","totals","product","proration"],"properties":{"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"quantity":{"type":"integer"},"tax_rate":{"type":"string"},"unit_totals":{"$ref":"#/components/schemas/Totals"},"totals":{"$ref":"#/components/schemas/Totals"},"product":{"$ref":"#/components/schemas/Product"},"proration":{"type":"null"}}}}}},"available_payment_methods":{"type":"array","items":{"type":"string"}}}},"SubscriptionItem":{"type":"object","required":["status","quantity","recurring","created_at","updated_at","previously_billed_at","next_billed_at","trial_dates","price","product"],"properties":{"status":{"type":"string","enum":["active","inactive","trialing"]},"quantity":{"type":"integer"},"recurring":{"type":"boolean"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"previously_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"next_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"trial_dates":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"price":{"$ref":"#/components/schemas/Price"},"product":{"$ref":"#/components/schemas/Product"}}},"ScheduledChange":{"type":["object","null"],"required":["action","effective_at","resume_at"],"properties":{"action":{"type":"string","enum":["cancel","pause","resume"]},"effective_at":{"$ref":"#/components/schemas/Timestamp"},"resume_at":{"$ref":"#/components/schemas/NullableTimestamp"}}},"Subscription":{"type":"object","required":["id","status","customer_id","address_id","business_id","currency_code","created_at","updated_at","started_at","first_billed_at","next_billed_at","paused_at","canceled_at","discount","collection_mode","billing_details","current_billing_period","billing_cycle","scheduled_change","management_urls","items","custom_data","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"subscription","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"status":{"$ref":"#/components/schemas/SubscriptionStatus"},"customer_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"address_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"business_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"started_at":{"$ref":"#/components/schemas/NullableTimestamp"},"first_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"next_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"paused_at":{"$ref":"#/components/schemas/NullableTimestamp"},"canceled_at":{"$ref":"#/components/schemas/NullableTimestamp"},"discount":{"type":"null"},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"billing_details":{"$ref":"#/components/schemas/BillingDetailsResponse"},"current_billing_period":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"billing_cycle":{"$ref":"#/components/schemas/TimePeriod"},"scheduled_change":{"$ref":"#/components/schemas/ScheduledChange"},"management_urls":{"type":"object","required":["update_payment_method","cancel"],"properties":{"update_payment_method":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"url"}},"cancel":{"type":"string","x-mockingbird-volatile":{"kind":"url"}}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/SubscriptionItem"}},"custom_data":{"$ref":"#/components/schemas/CustomData"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"},"next_transaction":{"description":"Present with \`include=next_transaction\` (null once canceled).","type":["object","null"],"required":["billing_period","details","adjustments"],"properties":{"billing_period":{"$ref":"#/components/schemas/BillingPeriod"},"details":{"$ref":"#/components/schemas/PreviewDetails"},"adjustments":{"type":"array","items":{"type":"object"}}}},"recurring_transaction_details":{"description":"Present with \`include=recurring_transaction_details\`.","$ref":"#/components/schemas/PreviewDetails"}}},"PreviewDetails":{"type":"object","required":["tax_rates_used","totals","line_items"],"properties":{"tax_rates_used":{"type":"array","items":{"$ref":"#/components/schemas/TaxRateUsed"}},"totals":{"$ref":"#/components/schemas/TransactionTotals"},"line_items":{"type":"array","items":{"type":"object","required":["price_id","quantity","tax_rate","unit_totals","totals","product","proration"],"properties":{"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"quantity":{"type":"integer"},"tax_rate":{"type":"string"},"unit_totals":{"$ref":"#/components/schemas/Totals"},"totals":{"$ref":"#/components/schemas/Totals"},"product":{"$ref":"#/components/schemas/Product"},"proration":{"type":"null"}}}}}},"SubscriptionResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Subscription"},"meta":{"$ref":"#/components/schemas/Meta"}}},"SubscriptionUpdate":{"type":"object","properties":{"customer_id":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}},"address_id":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}},"business_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"next_billed_at":{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"billing_details":{"oneOf":[{"$ref":"#/components/schemas/BillingDetails"},{"type":"null"}]},"scheduled_change":{"type":"null","description":"Only \`null\` is accepted, to remove a scheduled change."},"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"custom_data":{"$ref":"#/components/schemas/CustomData"},"proration_billing_mode":{"type":"string","enum":["prorated_immediately","prorated_next_billing_period","full_immediately","full_next_billing_period","do_not_bill"]},"on_payment_failure":{"type":"string","enum":["prevent_change","apply_change"]}}},"Event":{"type":"object","required":["event_id","event_type","occurred_at","notification_id","data"],"properties":{"event_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"event_type":{"type":"string"},"occurred_at":{"$ref":"#/components/schemas/Timestamp"},"notification_id":{"type":"null"},"data":{"type":"object"}}}}}}`);
4896
+ var document2 = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Paddle Billing API (Mockingbird subset)","description":"Stateful mock subset of the Paddle Billing API: customers with their addresses and\\nbusinesses, the catalog (products and prices), transactions with computed totals,\\nsubscriptions with their lifecycle (activate, pause, resume, cancel, one-time charges,\\nrenewals) and the events list. Subscriptions come from paid transactions, as in Paddle:\\nthe mock's admin routes stand in for the hosted checkout and the billing engine.\\n","version":"1","x-mockingbird-upstream":{"note":"Hand-authored from https://developer.paddle.com/api-reference/overview and the wire types of @paddle/paddle-node-sdk@3.10.0 (dist/types/**). Every entity carries the fields the SDK reads; enums are trimmed to representative values so generated requests stay meaningful."}},"servers":[{"url":"https://sandbox-api.paddle.com"}],"security":[{"bearerAuth":[]}],"paths":{"/customers":{"get":{"operationId":"ListCustomers","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","description":"Comma-separated customer ids.","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},{"name":"email","in":"query","description":"Comma-separated exact email addresses.","schema":{"type":"string","maxLength":120}},{"name":"search","in":"query","description":"Matches id, name or email (case-insensitive substring).","schema":{"type":"string","maxLength":60}},{"$ref":"#/components/parameters/StatusFilter"}],"responses":{"200":{"description":"Customers, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreateCustomer","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerCreate"}}}},"responses":{"201":{"description":"The created customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/customers/{customer_id}":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"GetCustomer","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateCustomer","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerUpdate"}}}},"responses":{"200":{"description":"The updated customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/customers/{customer_id}/credit-balances":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"GetCustomerCreditBalances","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"One balance per currency the customer holds credit in (none, in the mock)","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"type":"object","required":["customer_id","currency_code","balance"],"properties":{"customer_id":{"type":"string"},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"balance":{"type":"object","required":["available","reserved","used"],"properties":{"available":{"type":"string"},"reserved":{"type":"string"},"used":{"type":"string"}}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/auth-token":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"post":{"operationId":"CreateCustomerAuthToken","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A customer auth token for Paddle.js","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["customer_auth_token","expires_at"],"properties":{"customer_auth_token":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"expires_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/addresses":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"ListAddresses","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}}},{"name":"search","in":"query","schema":{"type":"string","maxLength":60}},{"$ref":"#/components/parameters/StatusFilter"}],"responses":{"200":{"description":"The customer's addresses, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Address"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"CreateAddress","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCreate"}}}},"responses":{"201":{"description":"The created address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/addresses/{address_id}":{"parameters":[{"$ref":"#/components/parameters/CustomerId"},{"$ref":"#/components/parameters/AddressId"}],"get":{"operationId":"GetAddress","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateAddress","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressUpdate"}}}},"responses":{"200":{"description":"The updated address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/businesses":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"get":{"operationId":"ListBusinesses","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}}},{"name":"search","in":"query","schema":{"type":"string","maxLength":60}},{"$ref":"#/components/parameters/StatusFilter"}],"responses":{"200":{"description":"The customer's businesses, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Business"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"CreateBusiness","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessCreate"}}}},"responses":{"201":{"description":"The created business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/customers/{customer_id}/businesses/{business_id}":{"parameters":[{"$ref":"#/components/parameters/CustomerId"},{"$ref":"#/components/parameters/BusinessId"}],"get":{"operationId":"GetBusiness","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateBusiness","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessUpdate"}}}},"responses":{"200":{"description":"The updated business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/products":{"get":{"operationId":"ListProducts","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}},{"name":"include","in":"query","description":"\`prices\` embeds each product's prices.","schema":{"type":"string","enum":["prices"]}},{"$ref":"#/components/parameters/StatusFilter"},{"name":"tax_category","in":"query","schema":{"$ref":"#/components/schemas/TaxCategory"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/CatalogType"}}],"responses":{"200":{"description":"Products, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreateProduct","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"}}}},"responses":{"201":{"description":"The created product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/products/{product_id}":{"parameters":[{"$ref":"#/components/parameters/ProductId"}],"get":{"operationId":"GetProduct","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"include","in":"query","schema":{"type":"string","enum":["prices"]}}],"responses":{"200":{"description":"The product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateProduct","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"}}}},"responses":{"200":{"description":"The updated product","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/prices":{"get":{"operationId":"ListPrices","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}}},{"name":"product_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}},{"name":"include","in":"query","description":"\`product\` embeds each price's product.","schema":{"type":"string","enum":["product"]}},{"$ref":"#/components/parameters/StatusFilter"},{"name":"recurring","in":"query","schema":{"type":"boolean"}},{"name":"type","in":"query","schema":{"$ref":"#/components/schemas/CatalogType"}}],"responses":{"200":{"description":"Prices, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Price"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreatePrice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceCreate"}}}},"responses":{"201":{"description":"The created price","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/prices/{price_id}":{"parameters":[{"$ref":"#/components/parameters/PriceId"}],"get":{"operationId":"GetPrice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"include","in":"query","schema":{"type":"string","enum":["product"]}}],"responses":{"200":{"description":"The price","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdatePrice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceUpdate"}}}},"responses":{"200":{"description":"The updated price","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transactions":{"get":{"operationId":"ListTransactions","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"name":"per_page","in":"query","schema":{"type":"integer","minimum":1,"maximum":30}},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"transaction","missing":"txn_00000000000000000000000000"}}},{"name":"customer_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},{"name":"subscription_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"subscription","missing":"sub_00000000000000000000000000"}}},{"name":"status","in":"query","description":"Comma-separated statuses.","schema":{"$ref":"#/components/schemas/TransactionStatus"}},{"name":"origin","in":"query","schema":{"$ref":"#/components/schemas/TransactionOrigin"}},{"name":"collection_mode","in":"query","schema":{"$ref":"#/components/schemas/CollectionMode"}},{"name":"invoice_number","in":"query","schema":{"type":"string","maxLength":40}},{"name":"include","in":"query","description":"Comma-separated relations to embed.","schema":{"type":"string","enum":["customer","address","business","customer,address","customer,address,business"]}},{"name":"created_at[GTE]","in":"query","description":"Transactions created at or after this RFC 3339 datetime (\`[LT]\`, \`[LTE]\`, \`[GT]\` and \`updated_at[\u2026]\` work the same way).","schema":{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"}},{"name":"billed_at[GTE]","in":"query","schema":{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"}}],"responses":{"200":{"description":"Transactions, newest first (30 per page)","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"CreateTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"$ref":"#/components/parameters/TransactionInclude"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionCreate"}}}},"responses":{"201":{"description":"The created transaction, with computed totals","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/transactions/preview":{"post":{"operationId":"PreviewTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionPreviewRequest"}}}},"responses":{"200":{"description":"Totals for the items, nothing stored","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/TransactionPreview"},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/transactions/{transaction_id}":{"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"get":{"operationId":"GetTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/TransactionInclude"}],"responses":{"200":{"description":"The transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateTransaction","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"$ref":"#/components/parameters/TransactionInclude"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionUpdate"}}}},"responses":{"200":{"description":"The updated transaction (only \`draft\` and \`ready\` transactions can change)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transactions/{transaction_id}/invoice":{"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"get":{"operationId":"GetTransactionInvoice","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"disposition","in":"query","schema":{"type":"string","enum":["attachment","inline"]}}],"responses":{"200":{"description":"A link to the invoice PDF (billed, paid and completed transactions only)","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["url"],"properties":{"url":{"type":"string","x-mockingbird-volatile":{"kind":"url"}}}},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/transactions/{transaction_id}/revise":{"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"post":{"operationId":"ReviseTransaction","x-mockingbird":{"supported":false,"reason":"Invoice revision (customer, business and address corrections on billed transactions) is not modelled."},"responses":{"200":{"description":"The revised transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}}}}},"/subscriptions":{"get":{"operationId":"ListSubscriptions","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"},{"name":"id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"subscription","missing":"sub_00000000000000000000000000"}}},{"name":"customer_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},{"name":"address_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}}},{"name":"price_id","in":"query","schema":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/SubscriptionStatus"}},{"name":"collection_mode","in":"query","schema":{"$ref":"#/components/schemas/CollectionMode"}},{"name":"scheduled_change_action","in":"query","schema":{"type":"string","enum":["cancel","pause","resume"]}}],"responses":{"200":{"description":"Subscriptions, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Subscription"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/subscriptions/{subscription_id}":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"get":{"operationId":"GetSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"include","in":"query","description":"\`next_transaction\` and \`recurring_transaction_details\` embed previews.","schema":{"type":"string","enum":["next_transaction","recurring_transaction_details","next_transaction,recurring_transaction_details"]}}],"responses":{"200":{"description":"The subscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"UpdateSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionUpdate"}}}},"responses":{"200":{"description":"The updated subscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/preview":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"patch":{"operationId":"PreviewSubscriptionUpdate","x-mockingbird":{"supported":false,"reason":"Update previews (proration credit/charge summaries) are not modelled; apply the update instead."},"responses":{"200":{"description":"A preview of the update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}}}}},"/subscriptions/{subscription_id}/activate":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"ActivateSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"200":{"description":"The subscription, now active (it must have been trialing)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/pause":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"PauseSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"effective_from":{"type":["string","null"],"enum":["next_billing_period","immediately",null]},"resume_at":{"type":["string","null"],"description":"RFC 3339 datetime to resume at.","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"},"on_resume":{"type":"string","enum":["continue_existing_billing_period","start_new_billing_period"]}}}}}},"responses":{"200":{"description":"The subscription, paused now or scheduled to pause","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/resume":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"ResumeSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["effective_from"],"properties":{"effective_from":{"type":"string","description":"\`immediately\`, or an RFC 3339 datetime to resume at.","oneOf":[{"type":"string","enum":["immediately"]},{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"}]},"on_resume":{"type":"string","enum":["continue_existing_billing_period","start_new_billing_period"]}}}}}},"responses":{"200":{"description":"The subscription, active again or scheduled to resume","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/cancel":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"CancelSubscription","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"effective_from":{"type":["string","null"],"enum":["next_billing_period","immediately",null]}}}}}},"responses":{"200":{"description":"The subscription, canceled now or scheduled to cancel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/charge":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"CreateSubscriptionCharge","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["effective_from","items"],"properties":{"effective_from":{"type":"string","enum":["next_billing_period","immediately"]},"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"on_payment_failure":{"type":"string","enum":["prevent_change","apply_change"]}}}}}},"responses":{"200":{"description":"The subscription; an immediate charge also creates a completed \`subscription_charge\` transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/subscriptions/{subscription_id}/charge/preview":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"post":{"operationId":"PreviewSubscriptionCharge","x-mockingbird":{"supported":false,"reason":"One-time charge previews are not modelled; create the charge instead."},"responses":{"200":{"description":"A preview of the charge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}}}}},"/subscriptions/{subscription_id}/update-payment-method-transaction":{"parameters":[{"$ref":"#/components/parameters/SubscriptionId"}],"get":{"operationId":"GetSubscriptionPaymentMethodChangeTransaction","x-mockingbird":{"supported":false,"reason":"Payment method changes go through the hosted checkout, which the mock does not serve."},"responses":{"200":{"description":"A zero-amount transaction for updating the payment method","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}}}}},"/events":{"get":{"operationId":"ListEvents","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/After"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/OrderBy"}],"responses":{"200":{"description":"Every event the account produced, newest first","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"meta":{"$ref":"#/components/schemas/MetaPaginated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/notification-settings":{"get":{"operationId":"ListNotificationSettings","x-mockingbird":{"supported":false,"reason":"Notification destinations are configured on the mock (\`--webhook-url\`, \`PUT /__admin/webhook-endpoints\`), not through the API."},"responses":{"200":{"description":"Notification settings","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"CreateNotificationSetting","x-mockingbird":{"supported":false,"reason":"Notification destinations are configured on the mock (\`--webhook-url\`, \`PUT /__admin/webhook-endpoints\`), not through the API."},"responses":{"201":{"description":"The created notification setting","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/discounts":{"get":{"operationId":"ListDiscounts","x-mockingbird":{"supported":false,"reason":"Discounts are not modelled; totals carry a zero discount."},"responses":{"200":{"description":"Discounts","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"CreateDiscount","x-mockingbird":{"supported":false,"reason":"Discounts are not modelled; totals carry a zero discount."},"responses":{"201":{"description":"The created discount","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/adjustments":{"get":{"operationId":"ListAdjustments","x-mockingbird":{"supported":false,"reason":"Refunds and credits (adjustments) are not modelled."},"responses":{"200":{"description":"Adjustments","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"CreateAdjustment","x-mockingbird":{"supported":false,"reason":"Refunds and credits (adjustments) are not modelled."},"responses":{"201":{"description":"The created adjustment","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/customers/{customer_id}/portal-sessions":{"parameters":[{"$ref":"#/components/parameters/CustomerId"}],"post":{"operationId":"CreateCustomerPortalSession","x-mockingbird":{"supported":false,"reason":"The hosted customer portal is not served; \`management_urls\` on a subscription point at placeholder links."},"responses":{"201":{"description":"The created portal session","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"\`Authorization: Bearer pdl_sdbx_apikey_\u2026\` (any key; none is 403 \`authentication_missing\`)"}},"parameters":{"After":{"name":"after","in":"query","description":"Return entities after this id (the cursor from \`meta.pagination.next\`).","schema":{"type":"string","maxLength":40}},"PerPage":{"name":"per_page","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},"OrderBy":{"name":"order_by","in":"query","schema":{"type":"string","enum":["id[ASC]","id[DESC]"]}},"StatusFilter":{"name":"status","in":"query","description":"Comma-separated statuses.","schema":{"type":"string","enum":["active","archived","active,archived"]}},"TransactionInclude":{"name":"include","in":"query","description":"Comma-separated relations to embed.","schema":{"type":"string","enum":["customer","address","business","customer,address","customer,address,business"]}},"CustomerId":{"name":"customer_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}}},"AddressId":{"name":"address_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}}},"BusinessId":{"name":"business_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}}},"ProductId":{"name":"product_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}},"PriceId":{"name":"price_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}}},"TransactionId":{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"transaction","missing":"txn_00000000000000000000000000"}}},"SubscriptionId":{"name":"subscription_id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"subscription","missing":"sub_00000000000000000000000000"}}}},"responses":{"BadRequest":{"description":"Validation failed (\`invalid_field\`, with \`errors[]\`) or the request is malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Missing, malformed or rejected API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"No such entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"The change conflicts with existing state (a customer with that email exists)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"schemas":{"RequestId":{"type":"string","x-mockingbird-volatile":{"kind":"opaque"}},"Meta":{"type":"object","required":["request_id"],"properties":{"request_id":{"$ref":"#/components/schemas/RequestId"}}},"MetaPaginated":{"type":"object","required":["request_id","pagination"],"properties":{"request_id":{"$ref":"#/components/schemas/RequestId"},"pagination":{"type":"object","required":["per_page","next","has_more","estimated_total"],"properties":{"per_page":{"type":"integer"},"next":{"type":"string","x-mockingbird-volatile":{"kind":"url"}},"has_more":{"type":"boolean"},"estimated_total":{"type":"integer"}}}}},"ErrorResponse":{"type":"object","required":["error","meta"],"properties":{"error":{"type":"object","required":["type","code","detail","documentation_url"],"properties":{"type":{"type":"string","enum":["request_error","api_error"]},"code":{"type":"string"},"detail":{"type":"string"},"documentation_url":{"type":"string"},"errors":{"type":"array","items":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string"},"message":{"type":"string"}}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"Timestamp":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"NullableTimestamp":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"Status":{"type":"string","enum":["active","archived"]},"CatalogType":{"type":"string","enum":["standard","custom"]},"CurrencyCode":{"type":"string","enum":["USD","EUR","GBP","CAD","AUD","JPY"]},"CountryCode":{"type":"string","enum":["US","GB","DE","FR","CA","AU","NL","ES","IE","JP"]},"TaxCategory":{"type":"string","enum":["standard","saas","digital-goods","ebooks","implementation-services","professional-services","software-programming-services","training-services","website-hosting"]},"TaxMode":{"type":"string","enum":["account_setting","external","internal","location"]},"Interval":{"type":"string","enum":["day","week","month","year"]},"CollectionMode":{"type":"string","enum":["automatic","manual"]},"TransactionStatus":{"type":"string","enum":["draft","ready","billed","paid","completed","canceled","past_due"]},"TransactionOrigin":{"type":"string","enum":["api","subscription_charge","subscription_payment_method_change","subscription_recurring","subscription_update","web"]},"SubscriptionStatus":{"type":"string","enum":["active","canceled","past_due","paused","trialing"]},"CustomData":{"type":["object","null"],"description":"Your own key-value data, echoed back unchanged.","maxProperties":10,"additionalProperties":{"type":["string","number","boolean","null"]}},"ImportMeta":{"type":["object","null"],"required":["imported_from"],"properties":{"external_id":{"type":["string","null"]},"imported_from":{"type":"string"}}},"Email":{"type":"string","description":"An email address.","pattern":"^[A-Za-z0-9._+-]+@[A-Za-z0-9-]+(\\\\.[A-Za-z0-9-]+)+$","maxLength":120},"Locale":{"type":"string","pattern":"^[a-z]{2}(-[A-Z]{2})?$"},"Money":{"type":"object","required":["amount","currency_code"],"properties":{"amount":{"type":"string","description":"In the currency's lowest unit, as a string of digits.","pattern":"^[0-9]{1,9}$"},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"}}},"TimePeriod":{"type":"object","required":["interval","frequency"],"properties":{"interval":{"$ref":"#/components/schemas/Interval"},"frequency":{"type":"integer","minimum":1,"maximum":365}}},"TrialPeriod":{"type":"object","required":["interval","frequency"],"properties":{"interval":{"$ref":"#/components/schemas/Interval"},"frequency":{"type":"integer","minimum":1,"maximum":365},"requires_payment_method":{"type":"boolean"}}},"PriceQuantity":{"type":"object","required":["minimum","maximum"],"properties":{"minimum":{"type":"integer","minimum":1,"maximum":999},"maximum":{"type":"integer","minimum":1,"maximum":999}}},"UnitPriceOverride":{"type":"object","required":["country_codes","unit_price"],"properties":{"country_codes":{"type":"array","minItems":1,"maxItems":3,"items":{"$ref":"#/components/schemas/CountryCode"}},"unit_price":{"$ref":"#/components/schemas/Money"}}},"Customer":{"type":"object","required":["id","name","email","marketing_consent","status","custom_data","locale","created_at","updated_at","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"customer","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":["string","null"]},"email":{"type":"string"},"marketing_consent":{"type":"boolean"},"status":{"$ref":"#/components/schemas/Status"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"locale":{"type":"string"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"}}},"CustomerResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Customer"},"meta":{"$ref":"#/components/schemas/Meta"}}},"CustomerCreate":{"type":"object","required":["email"],"properties":{"email":{"$ref":"#/components/schemas/Email"},"name":{"type":["string","null"],"maxLength":80},"custom_data":{"$ref":"#/components/schemas/CustomData"},"locale":{"$ref":"#/components/schemas/Locale"}}},"CustomerUpdate":{"type":"object","properties":{"email":{"$ref":"#/components/schemas/Email"},"name":{"type":["string","null"],"maxLength":80},"status":{"$ref":"#/components/schemas/Status"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"locale":{"$ref":"#/components/schemas/Locale"}}},"Address":{"type":"object","required":["id","customer_id","description","first_line","second_line","city","postal_code","region","country_code","custom_data","status","created_at","updated_at","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"address","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"customer_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"description":{"type":["string","null"]},"first_line":{"type":["string","null"]},"second_line":{"type":["string","null"]},"city":{"type":["string","null"]},"postal_code":{"type":["string","null"]},"region":{"type":["string","null"]},"country_code":{"type":"string"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"status":{"$ref":"#/components/schemas/Status"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"}}},"AddressResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Address"},"meta":{"$ref":"#/components/schemas/Meta"}}},"AddressFields":{"type":"object","properties":{"description":{"type":["string","null"],"maxLength":80},"first_line":{"type":["string","null"],"maxLength":120},"second_line":{"type":["string","null"],"maxLength":120},"city":{"type":["string","null"],"maxLength":60},"postal_code":{"type":["string","null"],"maxLength":20},"region":{"type":["string","null"],"maxLength":60},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"AddressCreate":{"allOf":[{"$ref":"#/components/schemas/AddressFields"},{"type":"object","required":["country_code"],"properties":{"country_code":{"$ref":"#/components/schemas/CountryCode"}}}]},"AddressUpdate":{"allOf":[{"$ref":"#/components/schemas/AddressFields"},{"type":"object","properties":{"country_code":{"$ref":"#/components/schemas/CountryCode"},"status":{"$ref":"#/components/schemas/Status"}}}]},"BusinessContact":{"type":"object","required":["email"],"properties":{"name":{"type":["string","null"],"maxLength":80},"email":{"$ref":"#/components/schemas/Email"}}},"Business":{"type":"object","required":["id","customer_id","name","company_number","tax_identifier","status","contacts","created_at","updated_at","custom_data","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"business","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"customer_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"company_number":{"type":["string","null"]},"tax_identifier":{"type":["string","null"]},"status":{"$ref":"#/components/schemas/Status"},"contacts":{"type":["array","null"],"items":{"type":"object","required":["name","email"],"properties":{"name":{"type":["string","null"]},"email":{"type":"string"}}}},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"}}},"BusinessResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Business"},"meta":{"$ref":"#/components/schemas/Meta"}}},"BusinessCreate":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"company_number":{"type":["string","null"],"maxLength":40},"tax_identifier":{"type":["string","null"],"maxLength":40},"contacts":{"type":["array","null"],"maxItems":3,"items":{"$ref":"#/components/schemas/BusinessContact"}},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"BusinessUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"company_number":{"type":["string","null"],"maxLength":40},"tax_identifier":{"type":["string","null"],"maxLength":40},"status":{"$ref":"#/components/schemas/Status"},"contacts":{"type":["array","null"],"maxItems":3,"items":{"$ref":"#/components/schemas/BusinessContact"}},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"Product":{"type":"object","required":["id","name","type","description","tax_category","image_url","custom_data","status","created_at","updated_at","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"product","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/CatalogType"},"description":{"type":["string","null"]},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"image_url":{"type":["string","null"]},"custom_data":{"$ref":"#/components/schemas/CustomData"},"status":{"$ref":"#/components/schemas/Status"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"},"prices":{"type":"array","description":"Present with \`include=prices\`.","items":{"$ref":"#/components/schemas/Price"}}}},"ProductResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Product"},"meta":{"$ref":"#/components/schemas/Meta"}}},"ProductCreate":{"type":"object","required":["name","tax_category"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"type":{"type":["string","null"],"enum":["standard","custom",null]},"description":{"type":["string","null"],"maxLength":500},"image_url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_-]+$","maxLength":200},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"ProductUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"type":{"type":["string","null"],"enum":["standard","custom",null]},"description":{"type":["string","null"],"maxLength":500},"image_url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_-]+$","maxLength":200},"custom_data":{"$ref":"#/components/schemas/CustomData"},"status":{"$ref":"#/components/schemas/Status"}}},"Price":{"type":"object","required":["id","product_id","description","type","name","billing_cycle","trial_period","tax_mode","unit_price","unit_price_overrides","quantity","status","created_at","updated_at","custom_data","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"price","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"product_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"description":{"type":"string"},"type":{"$ref":"#/components/schemas/CatalogType"},"name":{"type":["string","null"]},"billing_cycle":{"oneOf":[{"$ref":"#/components/schemas/TimePeriod"},{"type":"null"}]},"trial_period":{"oneOf":[{"$ref":"#/components/schemas/TrialPeriod"},{"type":"null"}]},"tax_mode":{"$ref":"#/components/schemas/TaxMode"},"unit_price":{"$ref":"#/components/schemas/Money"},"unit_price_overrides":{"type":"array","items":{"$ref":"#/components/schemas/UnitPriceOverride"}},"quantity":{"$ref":"#/components/schemas/PriceQuantity"},"status":{"$ref":"#/components/schemas/Status"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"},"product":{"description":"Present with \`include=product\`.","$ref":"#/components/schemas/Product"}}},"PriceResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Price"},"meta":{"$ref":"#/components/schemas/Meta"}}},"PriceFields":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":120},"name":{"type":["string","null"],"maxLength":80},"type":{"type":["string","null"],"enum":["standard","custom",null]},"billing_cycle":{"oneOf":[{"$ref":"#/components/schemas/TimePeriod"},{"type":"null"}]},"trial_period":{"oneOf":[{"$ref":"#/components/schemas/TrialPeriod"},{"type":"null"}]},"tax_mode":{"$ref":"#/components/schemas/TaxMode"},"unit_price":{"$ref":"#/components/schemas/Money"},"unit_price_overrides":{"type":"array","maxItems":3,"items":{"$ref":"#/components/schemas/UnitPriceOverride"}},"quantity":{"$ref":"#/components/schemas/PriceQuantity"},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"PriceCreate":{"allOf":[{"$ref":"#/components/schemas/PriceFields"},{"type":"object","required":["description","product_id","unit_price"],"properties":{"product_id":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}}}}]},"PriceUpdate":{"allOf":[{"$ref":"#/components/schemas/PriceFields"},{"type":"object","properties":{"status":{"$ref":"#/components/schemas/Status"}}}]},"NonCatalogProduct":{"type":"object","required":["name","tax_category"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"tax_category":{"$ref":"#/components/schemas/TaxCategory"},"description":{"type":["string","null"],"maxLength":500},"image_url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_-]+$","maxLength":200},"custom_data":{"$ref":"#/components/schemas/CustomData"}}},"NonCatalogPrice":{"type":"object","description":"A price created for this transaction only (type custom), for an existing product or a new custom product.","required":["description","unit_price"],"properties":{"description":{"type":"string","minLength":1,"maxLength":120},"name":{"type":["string","null"],"maxLength":80},"unit_price":{"$ref":"#/components/schemas/Money"},"billing_cycle":{"oneOf":[{"$ref":"#/components/schemas/TimePeriod"},{"type":"null"}]},"trial_period":{"oneOf":[{"$ref":"#/components/schemas/TrialPeriod"},{"type":"null"}]},"tax_mode":{"$ref":"#/components/schemas/TaxMode"},"quantity":{"$ref":"#/components/schemas/PriceQuantity"},"custom_data":{"$ref":"#/components/schemas/CustomData"},"product_id":{"type":"string","x-mockingbird-resource-ref":{"type":"product","missing":"pro_00000000000000000000000000"}},"product":{"$ref":"#/components/schemas/NonCatalogProduct"}}},"TransactionItemRequest":{"type":"object","required":["quantity"],"properties":{"quantity":{"type":"integer","minimum":1,"maximum":100},"price_id":{"type":"string","x-mockingbird-resource-ref":{"type":"price","missing":"pri_00000000000000000000000000"}},"price":{"$ref":"#/components/schemas/NonCatalogPrice"}}},"BillingDetails":{"type":"object","required":["payment_terms"],"properties":{"enable_checkout":{"type":"boolean"},"purchase_order_number":{"type":["string","null"],"maxLength":40},"additional_information":{"type":["string","null"],"maxLength":200},"payment_terms":{"$ref":"#/components/schemas/TimePeriod"}}},"BillingDetailsResponse":{"type":["object","null"],"required":["enable_checkout","purchase_order_number","additional_information","payment_terms"],"properties":{"enable_checkout":{"type":"boolean"},"purchase_order_number":{"type":["string","null"]},"additional_information":{"type":["string","null"]},"payment_terms":{"$ref":"#/components/schemas/TimePeriod"}}},"BillingPeriod":{"type":"object","required":["starts_at","ends_at"],"properties":{"starts_at":{"$ref":"#/components/schemas/Timestamp"},"ends_at":{"$ref":"#/components/schemas/Timestamp"}}},"TransactionFields":{"type":"object","properties":{"customer_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}},"address_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}},"business_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"billing_details":{"oneOf":[{"$ref":"#/components/schemas/BillingDetails"},{"type":"null"}]},"billing_period":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"custom_data":{"$ref":"#/components/schemas/CustomData"},"checkout":{"type":["object","null"],"properties":{"url":{"type":["string","null"],"pattern":"^https://[A-Za-z0-9./_?=&-]+$","maxLength":200}}}}},"TransactionCreate":{"allOf":[{"$ref":"#/components/schemas/TransactionFields"},{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"status":{"type":"string","enum":["draft","ready","billed"]}}}]},"TransactionUpdate":{"allOf":[{"$ref":"#/components/schemas/TransactionFields"},{"type":"object","properties":{"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"status":{"type":"string","enum":["draft","ready","billed","canceled"]}}}]},"TransactionPreviewRequest":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":5,"items":{"allOf":[{"$ref":"#/components/schemas/TransactionItemRequest"},{"type":"object","properties":{"include_in_totals":{"type":"boolean"}}}]}},"customer_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}},"address_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}},"business_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}},"currency_code":{"type":["string","null"],"enum":["USD","EUR","GBP","CAD","AUD","JPY",null]},"address":{"type":["object","null"],"required":["country_code"],"properties":{"postal_code":{"type":["string","null"],"maxLength":20},"country_code":{"$ref":"#/components/schemas/CountryCode"}}},"ignore_trials":{"type":["boolean","null"]}}},"Totals":{"type":"object","required":["subtotal","discount","tax","total"],"properties":{"subtotal":{"type":"string"},"discount":{"type":"string"},"tax":{"type":"string"},"total":{"type":"string"}}},"TransactionTotals":{"type":"object","required":["subtotal","discount","tax","total","credit","credit_to_balance","balance","grand_total","grand_total_tax","fee","earnings","currency_code"],"properties":{"subtotal":{"type":"string"},"discount":{"type":"string"},"tax":{"type":"string"},"total":{"type":"string"},"credit":{"type":"string"},"credit_to_balance":{"type":"string"},"balance":{"type":"string"},"grand_total":{"type":"string"},"grand_total_tax":{"type":"string"},"fee":{"type":["string","null"]},"earnings":{"type":["string","null"]},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"}}},"TaxRateUsed":{"type":"object","required":["tax_rate","totals"],"properties":{"tax_rate":{"type":"string"},"totals":{"$ref":"#/components/schemas/Totals"}}},"LineItem":{"type":"object","required":["id","price_id","quantity","proration","tax_rate","unit_totals","totals","product"],"properties":{"id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"quantity":{"type":"integer"},"proration":{"type":"null"},"tax_rate":{"type":"string"},"unit_totals":{"$ref":"#/components/schemas/Totals"},"totals":{"$ref":"#/components/schemas/Totals"},"product":{"$ref":"#/components/schemas/Product"}}},"TransactionDetails":{"type":"object","required":["tax_rates_used","totals","adjusted_totals","payout_totals","adjusted_payout_totals","line_items"],"properties":{"tax_rates_used":{"type":"array","items":{"$ref":"#/components/schemas/TaxRateUsed"}},"totals":{"$ref":"#/components/schemas/TransactionTotals"},"adjusted_totals":{"type":"object","required":["subtotal","tax","total","grand_total","grand_total_tax","fee","earnings","currency_code","retained_fee"],"properties":{"subtotal":{"type":"string"},"tax":{"type":"string"},"total":{"type":"string"},"grand_total":{"type":"string"},"grand_total_tax":{"type":"string"},"fee":{"type":["string","null"]},"earnings":{"type":["string","null"]},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"retained_fee":{"type":"string"}}},"payout_totals":{"type":"null"},"adjusted_payout_totals":{"type":"null"},"line_items":{"type":"array","items":{"$ref":"#/components/schemas/LineItem"}}}},"PaymentAttempt":{"type":"object","required":["payment_attempt_id","stored_payment_method_id","payment_method_id","amount","status","error_code","method_details","created_at","captured_at"],"properties":{"payment_attempt_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"stored_payment_method_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"payment_method_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"amount":{"type":"string"},"status":{"type":"string","enum":["authorized","authorized_flagged","canceled","captured","error","action_required","pending_no_action_required","created","unknown","dropped"]},"error_code":{"type":["string","null"]},"method_details":{"type":["object","null"],"required":["type","card","paypal","south_korea_local_card","underlying_details"],"properties":{"type":{"type":"string"},"card":{"type":["object","null"],"required":["type","last4","expiry_month","expiry_year","cardholder_name"],"properties":{"type":{"type":"string"},"last4":{"type":"string"},"expiry_month":{"type":"integer"},"expiry_year":{"type":"integer"},"cardholder_name":{"type":"string"}}},"paypal":{"type":"null"},"south_korea_local_card":{"type":"null"},"underlying_details":{"type":"null"}}},"created_at":{"$ref":"#/components/schemas/Timestamp"},"captured_at":{"$ref":"#/components/schemas/NullableTimestamp"}}},"Transaction":{"type":"object","required":["id","status","customer_id","address_id","business_id","custom_data","currency_code","origin","subscription_id","invoice_id","invoice_number","collection_mode","discount_id","billing_details","billing_period","items","details","payments","checkout","created_at","updated_at","billed_at","revised_at"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"transaction","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"status":{"$ref":"#/components/schemas/TransactionStatus"},"customer_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"address_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"business_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"custom_data":{"$ref":"#/components/schemas/CustomData"},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"origin":{"$ref":"#/components/schemas/TransactionOrigin"},"subscription_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"invoice_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"invoice_number":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"opaque"}},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"discount_id":{"type":"null"},"billing_details":{"$ref":"#/components/schemas/BillingDetailsResponse"},"billing_period":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","required":["price_id","price","quantity","proration"],"properties":{"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"price":{"$ref":"#/components/schemas/Price"},"quantity":{"type":"integer"},"proration":{"type":"null"}}}},"details":{"$ref":"#/components/schemas/TransactionDetails"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/PaymentAttempt"}},"checkout":{"type":["object","null"],"required":["url"],"properties":{"url":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"url"}}}},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"revised_at":{"type":"null"},"customer":{"description":"Present with \`include=customer\`.","oneOf":[{"$ref":"#/components/schemas/Customer"},{"type":"null"}]},"address":{"description":"Present with \`include=address\`.","oneOf":[{"$ref":"#/components/schemas/Address"},{"type":"null"}]},"business":{"description":"Present with \`include=business\`.","oneOf":[{"$ref":"#/components/schemas/Business"},{"type":"null"}]}}},"TransactionResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Transaction"},"meta":{"$ref":"#/components/schemas/Meta"}}},"TransactionPreview":{"type":"object","required":["customer_id","address_id","business_id","currency_code","discount_id","customer_ip_address","address","ignore_trials","items","details","available_payment_methods"],"properties":{"customer_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"address_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"business_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"discount_id":{"type":"null"},"customer_ip_address":{"type":"null"},"address":{"type":["object","null"],"required":["postal_code","country_code"],"properties":{"postal_code":{"type":["string","null"]},"country_code":{"type":"string"}}},"ignore_trials":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","required":["price","quantity","include_in_totals","proration"],"properties":{"price":{"$ref":"#/components/schemas/Price"},"quantity":{"type":"integer"},"include_in_totals":{"type":"boolean"},"proration":{"type":"null"}}}},"details":{"type":"object","required":["tax_rates_used","totals","line_items"],"properties":{"tax_rates_used":{"type":"array","items":{"$ref":"#/components/schemas/TaxRateUsed"}},"totals":{"$ref":"#/components/schemas/TransactionTotals"},"line_items":{"type":"array","items":{"type":"object","required":["price_id","quantity","tax_rate","unit_totals","totals","product","proration"],"properties":{"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"quantity":{"type":"integer"},"tax_rate":{"type":"string"},"unit_totals":{"$ref":"#/components/schemas/Totals"},"totals":{"$ref":"#/components/schemas/Totals"},"product":{"$ref":"#/components/schemas/Product"},"proration":{"type":"null"}}}}}},"available_payment_methods":{"type":"array","items":{"type":"string"}}}},"SubscriptionItem":{"type":"object","required":["status","quantity","recurring","created_at","updated_at","previously_billed_at","next_billed_at","trial_dates","price","product"],"properties":{"status":{"type":"string","enum":["active","inactive","trialing"]},"quantity":{"type":"integer"},"recurring":{"type":"boolean"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"previously_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"next_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"trial_dates":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"price":{"$ref":"#/components/schemas/Price"},"product":{"$ref":"#/components/schemas/Product"}}},"ScheduledChange":{"type":["object","null"],"required":["action","effective_at","resume_at"],"properties":{"action":{"type":"string","enum":["cancel","pause","resume"]},"effective_at":{"$ref":"#/components/schemas/Timestamp"},"resume_at":{"$ref":"#/components/schemas/NullableTimestamp"}}},"Subscription":{"type":"object","required":["id","status","customer_id","address_id","business_id","currency_code","created_at","updated_at","started_at","first_billed_at","next_billed_at","paused_at","canceled_at","discount","collection_mode","billing_details","current_billing_period","billing_cycle","scheduled_change","management_urls","items","custom_data","import_meta"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"subscription","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"status":{"$ref":"#/components/schemas/SubscriptionStatus"},"customer_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"address_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"business_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"started_at":{"$ref":"#/components/schemas/NullableTimestamp"},"first_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"next_billed_at":{"$ref":"#/components/schemas/NullableTimestamp"},"paused_at":{"$ref":"#/components/schemas/NullableTimestamp"},"canceled_at":{"$ref":"#/components/schemas/NullableTimestamp"},"discount":{"type":"null"},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"billing_details":{"$ref":"#/components/schemas/BillingDetailsResponse"},"current_billing_period":{"oneOf":[{"$ref":"#/components/schemas/BillingPeriod"},{"type":"null"}]},"billing_cycle":{"$ref":"#/components/schemas/TimePeriod"},"scheduled_change":{"$ref":"#/components/schemas/ScheduledChange"},"management_urls":{"type":"object","required":["update_payment_method","cancel"],"properties":{"update_payment_method":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"url"}},"cancel":{"type":"string","x-mockingbird-volatile":{"kind":"url"}}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/SubscriptionItem"}},"custom_data":{"$ref":"#/components/schemas/CustomData"},"import_meta":{"$ref":"#/components/schemas/ImportMeta"},"next_transaction":{"description":"Present with \`include=next_transaction\` (null once canceled).","type":["object","null"],"required":["billing_period","details","adjustments"],"properties":{"billing_period":{"$ref":"#/components/schemas/BillingPeriod"},"details":{"$ref":"#/components/schemas/PreviewDetails"},"adjustments":{"type":"array","items":{"type":"object"}}}},"recurring_transaction_details":{"description":"Present with \`include=recurring_transaction_details\`.","$ref":"#/components/schemas/PreviewDetails"}}},"PreviewDetails":{"type":"object","required":["tax_rates_used","totals","line_items"],"properties":{"tax_rates_used":{"type":"array","items":{"$ref":"#/components/schemas/TaxRateUsed"}},"totals":{"$ref":"#/components/schemas/TransactionTotals"},"line_items":{"type":"array","items":{"type":"object","required":["price_id","quantity","tax_rate","unit_totals","totals","product","proration"],"properties":{"price_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"quantity":{"type":"integer"},"tax_rate":{"type":"string"},"unit_totals":{"$ref":"#/components/schemas/Totals"},"totals":{"$ref":"#/components/schemas/Totals"},"product":{"$ref":"#/components/schemas/Product"},"proration":{"type":"null"}}}}}},"SubscriptionResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Subscription"},"meta":{"$ref":"#/components/schemas/Meta"}}},"SubscriptionUpdate":{"type":"object","properties":{"customer_id":{"type":"string","x-mockingbird-resource-ref":{"type":"customer","missing":"ctm_00000000000000000000000000"}},"address_id":{"type":"string","x-mockingbird-resource-ref":{"type":"address","missing":"add_00000000000000000000000000"}},"business_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"business","missing":"biz_00000000000000000000000000"}},"currency_code":{"$ref":"#/components/schemas/CurrencyCode"},"next_billed_at":{"type":"string","pattern":"^20[2-3][0-9]-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9](\\\\.[0-9]+)?Z$"},"collection_mode":{"$ref":"#/components/schemas/CollectionMode"},"billing_details":{"oneOf":[{"$ref":"#/components/schemas/BillingDetails"},{"type":"null"}]},"scheduled_change":{"type":"null","description":"Only \`null\` is accepted, to remove a scheduled change."},"items":{"type":"array","minItems":1,"maxItems":5,"items":{"$ref":"#/components/schemas/TransactionItemRequest"}},"custom_data":{"$ref":"#/components/schemas/CustomData"},"proration_billing_mode":{"type":"string","enum":["prorated_immediately","prorated_next_billing_period","full_immediately","full_next_billing_period","do_not_bill"]},"on_payment_failure":{"type":"string","enum":["prevent_change","apply_change"]}}},"Event":{"type":"object","required":["event_id","event_type","occurred_at","notification_id","data"],"properties":{"event_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"event_type":{"type":"string"},"occurred_at":{"$ref":"#/components/schemas/Timestamp"},"notification_id":{"type":"null"},"data":{"type":"object"}}}}}}`);
4093
4897
  var operationIds = ["ListCustomers", "CreateCustomer", "GetCustomer", "UpdateCustomer", "GetCustomerCreditBalances", "CreateCustomerAuthToken", "ListAddresses", "CreateAddress", "GetAddress", "UpdateAddress", "ListBusinesses", "CreateBusiness", "GetBusiness", "UpdateBusiness", "ListProducts", "CreateProduct", "GetProduct", "UpdateProduct", "ListPrices", "CreatePrice", "GetPrice", "UpdatePrice", "ListTransactions", "CreateTransaction", "PreviewTransaction", "GetTransaction", "UpdateTransaction", "GetTransactionInvoice", "ReviseTransaction", "ListSubscriptions", "GetSubscription", "UpdateSubscription", "PreviewSubscriptionUpdate", "ActivateSubscription", "PauseSubscription", "ResumeSubscription", "CancelSubscription", "CreateSubscriptionCharge", "PreviewSubscriptionCharge", "GetSubscriptionPaymentMethodChangeTransaction", "ListEvents", "ListNotificationSettings", "CreateNotificationSetting", "ListDiscounts", "CreateDiscount", "ListAdjustments", "CreateAdjustment", "CreateCustomerPortalSession"];
4094
4898
  var supportedOperationIds = ["ListCustomers", "CreateCustomer", "GetCustomer", "UpdateCustomer", "GetCustomerCreditBalances", "CreateCustomerAuthToken", "ListAddresses", "CreateAddress", "GetAddress", "UpdateAddress", "ListBusinesses", "CreateBusiness", "GetBusiness", "UpdateBusiness", "ListProducts", "CreateProduct", "GetProduct", "UpdateProduct", "ListPrices", "CreatePrice", "GetPrice", "UpdatePrice", "ListTransactions", "CreateTransaction", "PreviewTransaction", "GetTransaction", "UpdateTransaction", "GetTransactionInvoice", "ListSubscriptions", "GetSubscription", "UpdateSubscription", "ActivateSubscription", "PauseSubscription", "ResumeSubscription", "CancelSubscription", "CreateSubscriptionCharge", "ListEvents"];
4095
4899
 
@@ -4268,7 +5072,7 @@ var paddleSigner = () => signers.custom(
4268
5072
  );
4269
5073
  var json5 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
4270
5074
  var adminError4 = (status, message, code = "mockingbird_admin") => json5(status, { error: { type: "mockingbird_admin", code, message } });
4271
- var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5075
+ var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4272
5076
  var attempt = (run) => {
4273
5077
  try {
4274
5078
  return run();
@@ -4279,12 +5083,12 @@ var attempt = (run) => {
4279
5083
  };
4280
5084
  var adminRoutes = () => (runtime) => ({
4281
5085
  "POST /transactions/:id/pay": ({ params, namespace, body }) => attempt(() => {
4282
- const card = isRecord5(body) && isRecord5(body.card) ? body.card : void 0;
5086
+ const card = isRecord6(body) && isRecord6(body.card) ? body.card : void 0;
4283
5087
  const result = runtime.instance(namespace).payTransaction(params.id, card);
4284
5088
  return json5(200, result);
4285
5089
  }),
4286
5090
  "POST /checkout": ({ namespace, body }) => attempt(() => {
4287
- if (!isRecord5(body) || !Array.isArray(body.items) || body.items.length === 0) {
5091
+ if (!isRecord6(body) || !Array.isArray(body.items) || body.items.length === 0) {
4288
5092
  return adminError4(400, "items: [{price_id, quantity?}] is required");
4289
5093
  }
4290
5094
  return json5(201, runtime.instance(namespace).checkout(body));
@@ -4308,7 +5112,7 @@ var createRuntime2 = (options = {}) => {
4308
5112
  });
4309
5113
  const runtime = createRuntime({
4310
5114
  name: PADDLE_NAMESPACE,
4311
- document,
5115
+ document: document2,
4312
5116
  ...options.sqlite ? { sqlite: options.sqlite } : {},
4313
5117
  ...options.clock ? { clock: options.clock } : {},
4314
5118
  ...options.seed !== void 0 ? { seed: options.seed } : {},
@@ -4356,10 +5160,10 @@ var TRANSACTIONS_PER_PAGE = 30;
4356
5160
  var CURRENCIES = ["USD", "EUR", "GBP", "CAD", "AUD", "JPY"];
4357
5161
  var TRANSACTION_INCLUDES = ["customer", "address", "business"];
4358
5162
  var SUBSCRIPTION_INCLUDES = ["next_transaction", "recurring_transaction_details"];
4359
- var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5163
+ var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4360
5164
  var str = (value) => typeof value === "string" ? value : void 0;
4361
5165
  var nullableStr = (value, fallback) => value === void 0 ? fallback : typeof value === "string" ? value : null;
4362
- var customData = (value, fallback) => value === void 0 ? fallback : isRecord6(value) ? value : null;
5166
+ var customData = (value, fallback) => value === void 0 ? fallback : isRecord7(value) ? value : null;
4363
5167
  var envelope = (status, data, requestId, pagination) => jsonRes(status, {
4364
5168
  data,
4365
5169
  meta: { request_id: requestId, ...pagination ? { pagination } : {} }
@@ -4431,7 +5235,7 @@ var PaddleAPI = class {
4431
5235
  ListEvents: (c) => this.listEvents(c)
4432
5236
  });
4433
5237
  this.service = createService({
4434
- document,
5238
+ document: document2,
4435
5239
  handlers,
4436
5240
  sqlite,
4437
5241
  namespace,
@@ -4535,7 +5339,7 @@ var PaddleAPI = class {
4535
5339
  })
4536
5340
  );
4537
5341
  }
4538
- if (context.body.kind !== "json" || !isRecord6(context.body.value)) {
5342
+ if (context.body.kind !== "json" || !isRecord7(context.body.value)) {
4539
5343
  throw invalidField([{ field: "body", message: "body: must be a JSON object" }]);
4540
5344
  }
4541
5345
  return context.body.value;
@@ -4796,7 +5600,7 @@ var PaddleAPI = class {
4796
5600
  contacts(value) {
4797
5601
  if (value === void 0) return void 0;
4798
5602
  if (!Array.isArray(value)) return null;
4799
- return value.filter(isRecord6).map((c) => ({ name: nullableStr(c.name, null), email: String(c.email) }));
5603
+ return value.filter(isRecord7).map((c) => ({ name: nullableStr(c.name, null), email: String(c.email) }));
4800
5604
  }
4801
5605
  createBusinessOp(context) {
4802
5606
  const customer = this.mustCustomer(context.params.customer_id ?? "");
@@ -4930,7 +5734,7 @@ var PaddleAPI = class {
4930
5734
  }
4931
5735
  timePeriod(value, field, errors) {
4932
5736
  if (value === null || value === void 0) return null;
4933
- if (!isRecord6(value) || typeof value.interval !== "string" || typeof value.frequency !== "number") {
5737
+ if (!isRecord7(value) || typeof value.interval !== "string" || typeof value.frequency !== "number") {
4934
5738
  errors.push({ field, message: `${field}: must have interval and frequency` });
4935
5739
  return null;
4936
5740
  }
@@ -5031,15 +5835,15 @@ var PaddleAPI = class {
5031
5835
  );
5032
5836
  }
5033
5837
  priceInput(body, errors) {
5034
- const unitPrice = isRecord6(body.unit_price) ? body.unit_price : {};
5035
- const overrides = Array.isArray(body.unit_price_overrides) ? body.unit_price_overrides.filter(isRecord6).map((o) => ({
5838
+ const unitPrice = isRecord7(body.unit_price) ? body.unit_price : {};
5839
+ const overrides = Array.isArray(body.unit_price_overrides) ? body.unit_price_overrides.filter(isRecord7).map((o) => ({
5036
5840
  country_codes: Array.isArray(o.country_codes) ? o.country_codes.map(String) : [],
5037
- unit_price: isRecord6(o.unit_price) ? {
5841
+ unit_price: isRecord7(o.unit_price) ? {
5038
5842
  amount: String(o.unit_price.amount),
5039
5843
  currency_code: String(o.unit_price.currency_code)
5040
5844
  } : { amount: "0", currency_code: "USD" }
5041
5845
  })) : void 0;
5042
- const quantity = isRecord6(body.quantity) ? { minimum: Number(body.quantity.minimum), maximum: Number(body.quantity.maximum) } : void 0;
5846
+ const quantity = isRecord7(body.quantity) ? { minimum: Number(body.quantity.minimum), maximum: Number(body.quantity.maximum) } : void 0;
5043
5847
  const trial = this.timePeriod(body.trial_period, "trial_period", errors);
5044
5848
  return {
5045
5849
  description: str(body.description),
@@ -5048,7 +5852,7 @@ var PaddleAPI = class {
5048
5852
  billing_cycle: this.timePeriod(body.billing_cycle, "billing_cycle", errors),
5049
5853
  trial_period: trial === null ? null : {
5050
5854
  ...trial,
5051
- ...isRecord6(body.trial_period) && typeof body.trial_period.requires_payment_method === "boolean" ? { requires_payment_method: body.trial_period.requires_payment_method } : {}
5855
+ ...isRecord7(body.trial_period) && typeof body.trial_period.requires_payment_method === "boolean" ? { requires_payment_method: body.trial_period.requires_payment_method } : {}
5052
5856
  },
5053
5857
  tax_mode: str(body.tax_mode),
5054
5858
  unit_price: body.unit_price === void 0 ? void 0 : { amount: String(unitPrice.amount), currency_code: String(unitPrice.currency_code) },
@@ -5133,7 +5937,7 @@ var PaddleAPI = class {
5133
5937
  const out = [];
5134
5938
  raw.forEach((item, index) => {
5135
5939
  const at = `${field}[${index}]`;
5136
- if (!isRecord6(item)) {
5940
+ if (!isRecord7(item)) {
5137
5941
  errors.push({ field: at, message: `${at}: must be an object` });
5138
5942
  return;
5139
5943
  }
@@ -5154,7 +5958,7 @@ var PaddleAPI = class {
5154
5958
  });
5155
5959
  }
5156
5960
  product = price ? this.state.products.get(price.product_id) : void 0;
5157
- } else if (isRecord6(item.price)) {
5961
+ } else if (isRecord7(item.price)) {
5158
5962
  const spec = item.price;
5159
5963
  const productId = str(spec.product_id);
5160
5964
  if (productId !== void 0) {
@@ -5166,7 +5970,7 @@ var PaddleAPI = class {
5166
5970
  });
5167
5971
  return;
5168
5972
  }
5169
- } else if (isRecord6(spec.product)) {
5973
+ } else if (isRecord7(spec.product)) {
5170
5974
  const built = this.buildProduct({
5171
5975
  name: String(spec.product.name),
5172
5976
  tax_category: String(spec.product.tax_category),
@@ -5266,7 +6070,7 @@ var PaddleAPI = class {
5266
6070
  }
5267
6071
  billingDetails(value, errors) {
5268
6072
  if (value === null || value === void 0) return null;
5269
- if (!isRecord6(value)) {
6073
+ if (!isRecord7(value)) {
5270
6074
  errors.push({ field: "billing_details", message: "billing_details: must be an object" });
5271
6075
  return null;
5272
6076
  }
@@ -5280,7 +6084,7 @@ var PaddleAPI = class {
5280
6084
  }
5281
6085
  period(value, field, errors) {
5282
6086
  if (value === null || value === void 0) return null;
5283
- if (!isRecord6(value) || typeof value.starts_at !== "string" || typeof value.ends_at !== "string") {
6087
+ if (!isRecord7(value) || typeof value.starts_at !== "string" || typeof value.ends_at !== "string") {
5284
6088
  errors.push({ field, message: `${field}: must have starts_at and ends_at` });
5285
6089
  return null;
5286
6090
  }
@@ -5369,7 +6173,7 @@ var PaddleAPI = class {
5369
6173
  const country = this.countryOf(parties.address_id);
5370
6174
  const lines = this.lineItems(items, country);
5371
6175
  const billed = status === "billed" && base?.status !== "billed";
5372
- const checkout = input.checkout === void 0 ? base?.checkout ?? this.checkoutFor(id, collectionMode, billingDetails) : isRecord6(input.checkout) ? { url: nullableStr(input.checkout.url, null) } : null;
6176
+ const checkout = input.checkout === void 0 ? base?.checkout ?? this.checkoutFor(id, collectionMode, billingDetails) : isRecord7(input.checkout) ? { url: nullableStr(input.checkout.url, null) } : null;
5373
6177
  return {
5374
6178
  id,
5375
6179
  status,
@@ -5443,7 +6247,7 @@ var PaddleAPI = class {
5443
6247
  const raw = context.query[field];
5444
6248
  if (raw === void 0) return () => true;
5445
6249
  const bounds = [];
5446
- const entries = isRecord6(raw) ? Object.entries(raw) : [["EQ", raw]];
6250
+ const entries = isRecord7(raw) ? Object.entries(raw) : [["EQ", raw]];
5447
6251
  for (const [op, value] of entries) {
5448
6252
  const at = typeof value === "string" ? Date.parse(value) : Number.NaN;
5449
6253
  if (Number.isNaN(at) || !["EQ", "LT", "LTE", "GT", "GTE"].includes(op)) {
@@ -5513,7 +6317,7 @@ var PaddleAPI = class {
5513
6317
  });
5514
6318
  }
5515
6319
  });
5516
- const address = isRecord6(body.address) ? {
6320
+ const address = isRecord7(body.address) ? {
5517
6321
  postal_code: nullableStr(body.address.postal_code, null),
5518
6322
  country_code: String(body.address.country_code)
5519
6323
  } : null;
@@ -6620,7 +7424,7 @@ var PaddleAPI = class {
6620
7424
 
6621
7425
  export {
6622
7426
  PaddleError,
6623
- document,
7427
+ document2 as document,
6624
7428
  operationIds,
6625
7429
  supportedOperationIds,
6626
7430
  ID_PREFIX,
@@ -6632,4 +7436,4 @@ export {
6632
7436
  AUTH_TOKEN_TTL_MS,
6633
7437
  PaddleAPI
6634
7438
  };
6635
- //# sourceMappingURL=chunk-GZYZKVKY.js.map
7439
+ //# sourceMappingURL=chunk-PIP2D5YO.js.map