@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.
- package/CHANGELOG.md +10 -0
- package/dist/{chunk-XBICSMA7.js → chunk-CMUNJ23P.js} +2 -2
- package/dist/{chunk-GZYZKVKY.js → chunk-PIP2D5YO.js} +1437 -633
- package/dist/chunk-PIP2D5YO.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.js +1 -1
- package/dist/server.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-GZYZKVKY.js.map +0 -7
- /package/dist/{chunk-XBICSMA7.js.map → chunk-CMUNJ23P.js.map} +0 -0
|
@@ -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 = (
|
|
543
|
+
var resolveRef = (document3, ref) => {
|
|
544
544
|
if (!ref.startsWith("#/"))
|
|
545
545
|
throw new OpenAPIReferenceError(ref);
|
|
546
|
-
let cursor =
|
|
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 = (
|
|
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(
|
|
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 = (
|
|
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(
|
|
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(
|
|
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 = (
|
|
595
|
+
var listOperations = (document3) => {
|
|
596
596
|
const operations = [];
|
|
597
|
-
for (const [path, item] of Object.entries(
|
|
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(
|
|
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(
|
|
612
|
-
requestBody: operation.requestBody === void 0 ? void 0 : deref(
|
|
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 = (
|
|
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(
|
|
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 = (
|
|
701
|
+
var validateValue = (document3, schema, value, path = []) => {
|
|
702
702
|
const errors = [];
|
|
703
|
-
const s = resolveSchema(
|
|
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(
|
|
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(
|
|
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(
|
|
787
|
+
errors.push(...validateValue(document3, s.additionalProperties, record[key], [...path, key]));
|
|
788
788
|
}
|
|
789
789
|
if (s.propertyNames) {
|
|
790
|
-
const nameErrors = validateValue(
|
|
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(
|
|
799
|
-
if (s.anyOf && !s.anyOf.some((branch) => validateValue(
|
|
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(
|
|
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(
|
|
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 "&";
|
|
1859
|
+
case "<":
|
|
1860
|
+
return "<";
|
|
1861
|
+
case ">":
|
|
1862
|
+
return ">";
|
|
1863
|
+
case '"':
|
|
1864
|
+
return """;
|
|
1865
|
+
default:
|
|
1866
|
+
return "'";
|
|
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 "'";
|
|
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
|
|
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='
|
|
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: #
|
|
2633
|
+
--bg: #fafafa;
|
|
1400
2634
|
--bg-elev: #ffffff;
|
|
1401
|
-
--bg-muted: #
|
|
1402
|
-
--bg-inset: #
|
|
1403
|
-
--line: #
|
|
1404
|
-
--line-strong: #
|
|
1405
|
-
--ink: #
|
|
1406
|
-
--muted: #
|
|
1407
|
-
--faint: #
|
|
1408
|
-
--accent: #
|
|
1409
|
-
--accent-ink: #
|
|
1410
|
-
--accent-soft: #
|
|
1411
|
-
--ok: #
|
|
1412
|
-
--ok-soft: #
|
|
1413
|
-
--warn: #
|
|
1414
|
-
--warn-soft: #
|
|
1415
|
-
--err: #
|
|
1416
|
-
--err-soft: #
|
|
1417
|
-
--shadow:
|
|
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:
|
|
1421
|
-
--header:
|
|
1422
|
-
--nav:
|
|
2654
|
+
--radius: 10px;
|
|
2655
|
+
--header: 56px;
|
|
2656
|
+
--nav: 200px;
|
|
1423
2657
|
}
|
|
1424
2658
|
:root[data-theme="dark"] {
|
|
1425
2659
|
color-scheme: dark;
|
|
1426
|
-
--bg: #
|
|
1427
|
-
--bg-elev: #
|
|
1428
|
-
--bg-muted: #
|
|
1429
|
-
--bg-inset: #
|
|
1430
|
-
--line: #
|
|
1431
|
-
--line-strong: #
|
|
1432
|
-
--ink: #
|
|
1433
|
-
--muted: #
|
|
1434
|
-
--faint: #
|
|
1435
|
-
--accent: #
|
|
1436
|
-
--accent-ink: #
|
|
1437
|
-
--accent-soft: #
|
|
1438
|
-
--ok: #
|
|
1439
|
-
--ok-soft: #
|
|
1440
|
-
--warn: #
|
|
1441
|
-
--warn-soft: #
|
|
1442
|
-
--err: #
|
|
1443
|
-
--err-soft: #
|
|
1444
|
-
--shadow:
|
|
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: #
|
|
1450
|
-
--bg-elev: #
|
|
1451
|
-
--bg-muted: #
|
|
1452
|
-
--bg-inset: #
|
|
1453
|
-
--line: #
|
|
1454
|
-
--line-strong: #
|
|
1455
|
-
--ink: #
|
|
1456
|
-
--muted: #
|
|
1457
|
-
--faint: #
|
|
1458
|
-
--accent: #
|
|
1459
|
-
--accent-ink: #
|
|
1460
|
-
--accent-soft: #
|
|
1461
|
-
--ok: #
|
|
1462
|
-
--ok-soft: #
|
|
1463
|
-
--warn: #
|
|
1464
|
-
--warn-soft: #
|
|
1465
|
-
--err: #
|
|
1466
|
-
--err-soft: #
|
|
1467
|
-
--shadow:
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
html
|
|
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
|
-
|
|
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:
|
|
2725
|
+
background: var(--bg-elev);
|
|
1493
2726
|
border-bottom: 1px solid var(--line);
|
|
1494
|
-
|
|
1495
|
-
}
|
|
1496
|
-
.brand {
|
|
1497
|
-
|
|
1498
|
-
|
|
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
|
|
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:
|
|
1571
|
-
color: var(--ink); width: min(640px, calc(100vw - 24px)); box-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
|
-
<
|
|
1630
|
-
|
|
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
|
-
|
|
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
|
-
"&": "&", "<": "<", ">": ">", '"': """, "'": "'"
|
|
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
|
|
3031
|
+
const document3 = () => ui?.render ? ui.render({ service, defaultHtml: shell }) : shell();
|
|
2231
3032
|
return {
|
|
2232
|
-
"GET /ui": () => htmlResponse(
|
|
2233
|
-
"GET /ui/": () => htmlResponse(
|
|
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
|
|
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 =
|
|
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 = (
|
|
3174
|
+
var verifyOperations = (document3, handlers) => {
|
|
2374
3175
|
const problems = [];
|
|
2375
|
-
const operations = listOperations(
|
|
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
|
|
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 (!
|
|
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) =>
|
|
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 =
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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.
|
|
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
|
|
4057
|
+
var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3257
4058
|
var parseEndpoint = (value) => {
|
|
3258
|
-
if (!
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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 :
|
|
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 = (
|
|
3392
|
-
const matchers = listOperations(
|
|
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
|
|
4288
|
+
const history2 = timeline(namespace);
|
|
3488
4289
|
if (branch2 === "main") {
|
|
3489
4290
|
if (at !== void 0) {
|
|
3490
|
-
const point =
|
|
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 (!
|
|
4304
|
+
if (!history2.hasBranch(branch2)) {
|
|
3504
4305
|
if (at === void 0)
|
|
3505
|
-
|
|
3506
|
-
const point =
|
|
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 &&
|
|
3516
|
-
const point =
|
|
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 =
|
|
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
|
|
3552
|
-
const point =
|
|
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
|
|
3603
|
-
if (
|
|
3604
|
-
|
|
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
|
|
4634
|
+
const history2 = timeline(name);
|
|
3834
4635
|
return {
|
|
3835
|
-
branches:
|
|
3836
|
-
checkpoints:
|
|
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
|
-
//
|
|
3855
|
-
//
|
|
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": () =>
|
|
3931
|
-
|
|
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
|
|
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 =
|
|
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 (!
|
|
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
|
|
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 :
|
|
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" || !
|
|
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(
|
|
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 (!
|
|
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 =
|
|
5035
|
-
const overrides = Array.isArray(body.unit_price_overrides) ? body.unit_price_overrides.filter(
|
|
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:
|
|
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 =
|
|
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
|
-
...
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
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) :
|
|
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 =
|
|
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 =
|
|
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-
|
|
7439
|
+
//# sourceMappingURL=chunk-PIP2D5YO.js.map
|