@crvouga/mockingbird-service-easypost 0.2.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/dist/{chunk-SPPBQVDT.js → chunk-7LWZJQN5.js} +97 -25
- package/dist/chunk-7LWZJQN5.js.map +7 -0
- package/dist/{chunk-HWAUA7CP.js → chunk-NPUUEP5A.js} +5 -3
- package/dist/chunk-NPUUEP5A.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +129 -101
- package/dist/index.js +1 -1
- package/dist/server.d.ts +233 -177
- package/dist/server.js +2 -2
- package/package.json +6 -2
- package/dist/chunk-HWAUA7CP.js.map +0 -7
- package/dist/chunk-SPPBQVDT.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-easypost
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 1.0.1 (2026-09-26)
|
|
4
|
+
|
|
5
|
+
### Fixes and improvements
|
|
6
|
+
|
|
7
|
+
- take the rejected-request byte count from content-length, never by reading the body ([a0e5fb2](https://github.com/crvouga/mockingbird/commit/a0e5fb2fc80ab725c3552b612f3f091fd6c857fb))
|
|
8
|
+
- reject a present body by media type, and log what a rejected request sent ([12e351a](https://github.com/crvouga/mockingbird/commit/12e351aba53cfb7b41e31a7809419455fc2902eb))
|
|
9
|
+
|
|
10
|
+
## 1.0.0 (2026-09-24)
|
|
11
|
+
|
|
12
|
+
### ⚠️ Breaking changes
|
|
13
|
+
|
|
14
|
+
- vendor branding for every service; purge internal mocks and consumer names ([f689534](https://github.com/crvouga/mockingbird/commit/f6895343543550dafcb7d76b426cae7635e03226))
|
|
15
|
+
|
|
16
|
+
## 0.2.0 (2026-09-23)
|
|
4
17
|
|
|
5
18
|
### Features
|
|
6
19
|
|
|
@@ -1418,6 +1418,90 @@ var operationMetadata = (operation) => {
|
|
|
1418
1418
|
|
|
1419
1419
|
// ../core/dist/service.js
|
|
1420
1420
|
import { Hono } from "hono";
|
|
1421
|
+
|
|
1422
|
+
// ../core/dist/validation.js
|
|
1423
|
+
var requestBodyOf = (context) => {
|
|
1424
|
+
const requestBody = context.operation.operation.requestBody;
|
|
1425
|
+
return requestBody ? deref(context.document, requestBody) : void 0;
|
|
1426
|
+
};
|
|
1427
|
+
var mediaTypeMatches = (accepted, actual) => {
|
|
1428
|
+
const pattern = mediaTypeOf(accepted) ?? accepted.toLowerCase();
|
|
1429
|
+
if (pattern === actual || pattern === "*/*")
|
|
1430
|
+
return true;
|
|
1431
|
+
const [type, subtype] = pattern.split("/");
|
|
1432
|
+
const [actualType, actualSubtype] = actual.split("/");
|
|
1433
|
+
if (type !== actualType && type !== "*")
|
|
1434
|
+
return false;
|
|
1435
|
+
if (subtype === void 0 || subtype === "*")
|
|
1436
|
+
return true;
|
|
1437
|
+
if (subtype.startsWith("*+"))
|
|
1438
|
+
return actualSubtype?.endsWith(subtype.slice(1)) === true;
|
|
1439
|
+
return false;
|
|
1440
|
+
};
|
|
1441
|
+
var acceptedKeyFor = (content, mediaType) => {
|
|
1442
|
+
if (!content || mediaType === void 0)
|
|
1443
|
+
return void 0;
|
|
1444
|
+
const keys = Object.keys(content);
|
|
1445
|
+
return keys.find((key) => mediaTypeOf(key) === mediaType) ?? keys.find((key) => mediaTypeMatches(key, mediaType));
|
|
1446
|
+
};
|
|
1447
|
+
var unsupportedMediaType = (context, options = {}) => {
|
|
1448
|
+
if (context.body.kind === "empty" && options.includeEmpty !== true)
|
|
1449
|
+
return void 0;
|
|
1450
|
+
const content = requestBodyOf(context)?.content;
|
|
1451
|
+
if (!content || Object.keys(content).length === 0)
|
|
1452
|
+
return void 0;
|
|
1453
|
+
const mediaType = mediaTypeOf(context.request.headers.get("content-type"));
|
|
1454
|
+
if (acceptedKeyFor(content, mediaType) !== void 0)
|
|
1455
|
+
return void 0;
|
|
1456
|
+
return { mediaType: mediaType ?? null, accepted: Object.keys(content) };
|
|
1457
|
+
};
|
|
1458
|
+
var recorded = /* @__PURE__ */ new WeakMap();
|
|
1459
|
+
var recordedIssues = (request) => recorded.get(request);
|
|
1460
|
+
var bodyIssues = (context, contentType = "application/json") => {
|
|
1461
|
+
const issues = findBodyIssues(context, contentType);
|
|
1462
|
+
if (issues.length > 0)
|
|
1463
|
+
recorded.set(context.request, issues);
|
|
1464
|
+
return issues;
|
|
1465
|
+
};
|
|
1466
|
+
var findBodyIssues = (context, contentType) => {
|
|
1467
|
+
const resolved = requestBodyOf(context);
|
|
1468
|
+
if (!resolved)
|
|
1469
|
+
return [];
|
|
1470
|
+
const unsupported = unsupportedMediaType(context);
|
|
1471
|
+
if (unsupported) {
|
|
1472
|
+
return [
|
|
1473
|
+
{
|
|
1474
|
+
path: "",
|
|
1475
|
+
kind: "media_type",
|
|
1476
|
+
message: unsupported.mediaType === null ? "request body has no content-type" : `request body media type ${unsupported.mediaType} is not supported`
|
|
1477
|
+
}
|
|
1478
|
+
];
|
|
1479
|
+
}
|
|
1480
|
+
const key = acceptedKeyFor(resolved.content, mediaTypeOf(context.request.headers.get("content-type"))) ?? contentType;
|
|
1481
|
+
const schema = resolved.content?.[key]?.schema;
|
|
1482
|
+
if (!schema)
|
|
1483
|
+
return [];
|
|
1484
|
+
if (context.body.kind === "invalid") {
|
|
1485
|
+
return [
|
|
1486
|
+
{
|
|
1487
|
+
path: "",
|
|
1488
|
+
kind: "syntax",
|
|
1489
|
+
message: `request body is not valid ${context.body.mediaType}`
|
|
1490
|
+
}
|
|
1491
|
+
];
|
|
1492
|
+
}
|
|
1493
|
+
const value = context.body.kind === "json" || context.body.kind === "form" || context.body.kind === "text" ? context.body.value : void 0;
|
|
1494
|
+
if (value === void 0) {
|
|
1495
|
+
return resolved.required && context.body.kind === "empty" ? [{ path: "", kind: "required", message: "request body is required" }] : [];
|
|
1496
|
+
}
|
|
1497
|
+
return validateValue(context.document, resolveSchema(context.document, schema), value).map((issue) => ({ path: issue.path.join("."), kind: "schema", message: issue.message }));
|
|
1498
|
+
};
|
|
1499
|
+
|
|
1500
|
+
// ../core/dist/service.js
|
|
1501
|
+
var withIssues = (request, response) => {
|
|
1502
|
+
const issues = response.status >= 400 ? recordedIssues(request) : void 0;
|
|
1503
|
+
return issues && issues.length > 0 ? annotateResponse(response, { issues }) : response;
|
|
1504
|
+
};
|
|
1421
1505
|
var defineOperations = (handlers) => handlers;
|
|
1422
1506
|
var OperationRegistryError = class extends Error {
|
|
1423
1507
|
problems;
|
|
@@ -1503,9 +1587,7 @@ var createService = (options) => {
|
|
|
1503
1587
|
now
|
|
1504
1588
|
};
|
|
1505
1589
|
const short = await options.before?.(context);
|
|
1506
|
-
|
|
1507
|
-
return short;
|
|
1508
|
-
return handler(context);
|
|
1590
|
+
return withIssues(request, short ?? await handler(context));
|
|
1509
1591
|
};
|
|
1510
1592
|
app.on(operation.method.toUpperCase(), honoPath(operation.path), route);
|
|
1511
1593
|
}
|
|
@@ -1542,7 +1624,7 @@ var restoreNamespace = (sqlite, namespace, snapshot) => {
|
|
|
1542
1624
|
};
|
|
1543
1625
|
|
|
1544
1626
|
// ../core/dist/version.js
|
|
1545
|
-
var PACKAGE_VERSION = true ? "0.
|
|
1627
|
+
var PACKAGE_VERSION = true ? "1.0.1" : UNRELEASED_VERSION;
|
|
1546
1628
|
|
|
1547
1629
|
// ../core/dist/webhooks.js
|
|
1548
1630
|
var json2 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
@@ -1980,8 +2062,15 @@ var createRuntime = (options) => {
|
|
|
1980
2062
|
const started = monotonicNow();
|
|
1981
2063
|
const url = new URL(request.url);
|
|
1982
2064
|
const operationId = operationIdFor(request, url.pathname);
|
|
2065
|
+
const contentLength = request.headers.get("content-length");
|
|
2066
|
+
const received = {
|
|
2067
|
+
contentType: request.headers.get("content-type"),
|
|
2068
|
+
bodyBytes: contentLength !== null && /^\d+$/.test(contentLength) ? Number(contentLength) : null,
|
|
2069
|
+
transferEncoding: request.headers.get("transfer-encoding")
|
|
2070
|
+
};
|
|
1983
2071
|
const log = (status, faultId, response2) => {
|
|
1984
2072
|
const noted = response2 ? responseNotes(response2) : void 0;
|
|
2073
|
+
const rejected = status >= 400 && faultId === void 0;
|
|
1985
2074
|
const entry = {
|
|
1986
2075
|
service: options.name,
|
|
1987
2076
|
namespace,
|
|
@@ -1993,7 +2082,9 @@ var createRuntime = (options) => {
|
|
|
1993
2082
|
unmatched: options.document !== void 0 && operationId === void 0,
|
|
1994
2083
|
...faultId !== void 0 ? { faultId } : {},
|
|
1995
2084
|
...noted?.ids && Object.keys(noted.ids).length > 0 ? { ids: noted.ids } : {},
|
|
1996
|
-
...noted?.adopted ? { adopted: true } : {}
|
|
2085
|
+
...noted?.adopted ? { adopted: true } : {},
|
|
2086
|
+
...rejected ? { request: { ...received } } : {},
|
|
2087
|
+
...rejected && noted?.issues && noted.issues.length > 0 ? { issues: noted.issues.map((issue) => ({ ...issue })) } : {}
|
|
1997
2088
|
};
|
|
1998
2089
|
metrics.record(entry);
|
|
1999
2090
|
journal.record({ ...entry, at: new Date(clock.now()).toISOString() });
|
|
@@ -2200,25 +2291,6 @@ var presetRoutes = (presets, runtime) => ({
|
|
|
2200
2291
|
}
|
|
2201
2292
|
});
|
|
2202
2293
|
|
|
2203
|
-
// ../core/dist/validation.js
|
|
2204
|
-
var bodyIssues = (context, contentType = "application/json") => {
|
|
2205
|
-
const requestBody = context.operation.operation.requestBody;
|
|
2206
|
-
if (!requestBody)
|
|
2207
|
-
return [];
|
|
2208
|
-
const resolved = deref(context.document, requestBody);
|
|
2209
|
-
const schema = resolved.content?.[contentType]?.schema;
|
|
2210
|
-
if (!schema)
|
|
2211
|
-
return [];
|
|
2212
|
-
const value = context.body.kind === "json" || context.body.kind === "form" ? context.body.value : void 0;
|
|
2213
|
-
if (context.body.kind === "invalid") {
|
|
2214
|
-
return [{ path: "", message: `request body is not valid ${context.body.mediaType}` }];
|
|
2215
|
-
}
|
|
2216
|
-
if (value === void 0) {
|
|
2217
|
-
return resolved.required ? [{ path: "", message: "request body is required" }] : [];
|
|
2218
|
-
}
|
|
2219
|
-
return validateValue(context.document, resolveSchema(context.document, schema), value).map((issue) => ({ path: issue.path.join("."), message: issue.message }));
|
|
2220
|
-
};
|
|
2221
|
-
|
|
2222
2294
|
// src/generated/openapi.ts
|
|
2223
2295
|
var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"EasyPost Trackers API (Mockingbird subset)","description":"Stateful mock subset of the EasyPost v2 API: create (or re-use) a tracker for a tracking\\ncode, retrieve it, and list trackers. Trimmed from EasyPost's published reference to what\\nour genomics tracking lookup calls, plus the two reads that make parity walks meaningful.\\n","version":"2","x-mockingbird-upstream":{"note":"Shapes from https://docs.easypost.com/docs/trackers; request/response fields our consumer reads come from packages/lib/src/shipment-tracking-status/easypost-client.ts."}},"servers":[{"url":"https://api.easypost.com"}],"security":[{"basicAuth":[]}],"paths":{"/v2/trackers":{"post":{"operationId":"CreateTracker","description":"Creates a tracker, or answers the existing one when the same tracking code (and carrier) was already tracked. EasyPost's test codes (EZ1000000001 \u2026 EZ7000000007) answer their documented fixed statuses.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/CreateTrackerBody"}},"application/json":{"schema":{"$ref":"#/components/schemas/CreateTrackerBody"}}}},"responses":{"201":{"description":"The tracker (new or re-used)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tracker"}}}},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Missing tracking code or invalid carrier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"ListTrackers","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"tracking_code","in":"query","required":false,"schema":{"type":"string","maxLength":40}},{"name":"carrier","in":"query","required":false,"schema":{"type":"string","enum":["USPS","UPS","FedEx","DHLExpress"]}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Newest trackers first","content":{"application/json":{"schema":{"type":"object","required":["trackers","has_more"],"properties":{"trackers":{"type":"array","items":{"$ref":"#/components/schemas/Tracker"}},"has_more":{"type":"boolean"}}}}}},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid query parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v2/trackers/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","x-mockingbird-resource-ref":{"type":"tracker","missing":"trk_00000000000000000000000000000000"}}}],"get":{"operationId":"RetrieveTracker","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The tracker","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tracker"}}}},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown tracker","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"basicAuth":{"type":"http","scheme":"basic","description":"The API key as the username, an empty password (\`Basic base64(key:)\`)."}},"schemas":{"CreateTrackerBody":{"type":"object","required":["tracker"],"properties":{"tracker":{"type":"object","required":["tracking_code"],"properties":{"tracking_code":{"type":"string","minLength":1,"maxLength":40,"examples":["EZ1000000001","EZ4000000004","1Z999AA10123456784"]},"carrier":{"type":"string","enum":["USPS","UPS","FedEx","DHL","DHLExpress"]}}}}},"Tracker":{"type":"object","required":["id","object","mode","tracking_code","status","status_detail","carrier","tracking_details","public_url","created_at","updated_at"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"tracker","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"object":{"type":"string","enum":["Tracker"]},"mode":{"type":"string","enum":["test","production"]},"tracking_code":{"type":"string"},"status":{"type":"string","enum":["unknown","pre_transit","in_transit","out_for_delivery","delivered","available_for_pickup","return_to_sender","failure","cancelled","error"]},"status_detail":{"type":"string"},"carrier":{"type":"string"},"signed_by":{"type":["string","null"]},"weight":{"type":["number","null"]},"est_delivery_date":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"shipment_id":{"type":["string","null"]},"tracking_details":{"type":"array","items":{"$ref":"#/components/schemas/TrackingDetail"}},"carrier_detail":{"type":["object","null"]},"public_url":{"type":"string","x-mockingbird-volatile":{"kind":"url"}},"fees":{"type":"array","items":{"type":"object"}},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"TrackingDetail":{"type":"object","required":["object","message","status","status_detail","datetime","source"],"properties":{"object":{"type":"string","enum":["TrackingDetail"]},"message":{"type":"string"},"status":{"type":"string"},"status_detail":{"type":"string"},"datetime":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"source":{"type":"string"},"tracking_location":{"type":"object"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"object"}}}}}}}}}`);
|
|
2224
2296
|
var operationIds = ["ListTrackers", "CreateTracker", "RetrieveTracker"];
|
|
@@ -2630,4 +2702,4 @@ export {
|
|
|
2630
2702
|
isTrackerStatus,
|
|
2631
2703
|
EasyPostAPI
|
|
2632
2704
|
};
|
|
2633
|
-
//# sourceMappingURL=chunk-
|
|
2705
|
+
//# sourceMappingURL=chunk-7LWZJQN5.js.map
|