@crvouga/mockingbird-service-odx 2.1.0 → 2.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog — @crvouga/mockingbird-service-odx
2
2
 
3
+ ## 2.2.0 (2026-10-05)
4
+
5
+ ### Features
6
+
7
+ - add scripted local API mock ([4a76a11](https://github.com/crvouga/mockingbird/commit/4a76a114e2efad45934e0a93cf29576fd418e15c))
8
+
9
+ ### Fixes and improvements
10
+
11
+ - support embedded route parameters ([127cad9](https://github.com/crvouga/mockingbird/commit/127cad997ef106950c1b866070eea191ba54403f))
12
+
3
13
  ## 2.1.0 (2026-10-04)
4
14
 
5
15
  ### Features
@@ -12,10 +22,6 @@
12
22
  - fill the embedded viewport ([c1a35a4](https://github.com/crvouga/mockingbird/commit/c1a35a4789389ee9cd06c286d09bd47c4d06c71e))
13
23
  - make dialog cleanup immediate ([0c1a3c5](https://github.com/crvouga/mockingbird/commit/0c1a3c5b12584d50c19dcae595b951b8e5417b9c))
14
24
 
15
- ### Dependencies
16
-
17
- - `@crvouga/mockingbird-service-sqlite`
18
-
19
25
  ## 2.0.0 (2026-10-04)
20
26
 
21
27
  ### ⚠️ Breaking changes
@@ -820,7 +820,40 @@ var decodeBody = (contentType, bytes) => {
820
820
  return { kind: "bytes", value: bytes };
821
821
  };
822
822
  var readBody = async (message2) => {
823
- const bytes = new Uint8Array(await message2.arrayBuffer());
823
+ if (!(message2 instanceof Request) || !message2.body) {
824
+ if (message2 instanceof Request)
825
+ message2.signal.throwIfAborted();
826
+ return decodeBody(message2.headers.get("content-type"), new Uint8Array(await message2.arrayBuffer()));
827
+ }
828
+ message2.signal.throwIfAborted();
829
+ const reader = message2.body.getReader();
830
+ const cancel = () => {
831
+ void reader.cancel(message2.signal.reason).catch(() => {
832
+ });
833
+ };
834
+ message2.signal.addEventListener("abort", cancel, { once: true });
835
+ const chunks = [];
836
+ let size = 0;
837
+ try {
838
+ for (; ; ) {
839
+ message2.signal.throwIfAborted();
840
+ const { done, value } = await reader.read();
841
+ message2.signal.throwIfAborted();
842
+ if (done)
843
+ break;
844
+ chunks.push(value);
845
+ size += value.byteLength;
846
+ }
847
+ } finally {
848
+ message2.signal.removeEventListener("abort", cancel);
849
+ reader.releaseLock();
850
+ }
851
+ const bytes = new Uint8Array(size);
852
+ let offset = 0;
853
+ for (const chunk of chunks) {
854
+ bytes.set(chunk, offset);
855
+ offset += chunk.byteLength;
856
+ }
824
857
  return decodeBody(message2.headers.get("content-type"), bytes);
825
858
  };
826
859
 
@@ -1443,7 +1476,42 @@ var verifyOperations = (document2, handlers) => {
1443
1476
  }
1444
1477
  return problems;
1445
1478
  };
1446
- var honoPath = (template) => template.replace(/\{([^}]+)\}/g, ":$1");
1479
+ var escapePattern = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1480
+ var serviceRoute = (template) => {
1481
+ const names = [];
1482
+ let pattern = "", end = 0;
1483
+ for (const match of template.matchAll(/\{([^}]+)\}/g)) {
1484
+ pattern += `${escapePattern(template.slice(end, match.index))}([^/]+?)`;
1485
+ const name = match[1];
1486
+ if (!name)
1487
+ throw new Error(`Invalid OpenAPI route template: ${template}`);
1488
+ names.push(name);
1489
+ end = match.index + match[0].length;
1490
+ }
1491
+ pattern += escapePattern(template.slice(end));
1492
+ const matcher = new RegExp(`^${pattern}$`);
1493
+ const path = template.split("/").map((segment, index) => {
1494
+ if (!segment.includes("{"))
1495
+ return segment;
1496
+ const literal = /^\{([^}]+)\}$/.exec(segment);
1497
+ if (literal)
1498
+ return `:${literal[1]}`;
1499
+ let expression = "", offset = 0;
1500
+ for (const match of segment.matchAll(/\{[^}]+\}/g)) {
1501
+ expression += `${escapePattern(segment.slice(offset, match.index))}[^/]+?`;
1502
+ offset = match.index + match[0].length;
1503
+ }
1504
+ expression += escapePattern(segment.slice(offset));
1505
+ return `:mockingbirdSegment${index}{${expression}}`;
1506
+ }).join("/");
1507
+ return {
1508
+ path,
1509
+ params: (pathname) => {
1510
+ const values = matcher.exec(pathname);
1511
+ return Object.fromEntries(names.map((name, index) => [name, decodeURIComponent(values?.[index + 1] ?? "")]));
1512
+ }
1513
+ };
1514
+ };
1447
1515
  var routeOrder = (a, b) => {
1448
1516
  const sa = a.path.split("/");
1449
1517
  const sb = b.path.split("/");
@@ -1478,6 +1546,7 @@ var createService = (options) => {
1478
1546
  for (const operation of operations) {
1479
1547
  const metadata = operationMetadata(operation.operation);
1480
1548
  const handler = options.handlers[operation.operationId];
1549
+ const registeredRoute = serviceRoute(operation.path);
1481
1550
  const route = async (c) => {
1482
1551
  const request = c.req.raw;
1483
1552
  if (!metadata.supported || !handler) {
@@ -1487,7 +1556,7 @@ var createService = (options) => {
1487
1556
  const context = {
1488
1557
  request,
1489
1558
  url,
1490
- params: c.req.param(),
1559
+ params: registeredRoute.params(url.pathname),
1491
1560
  query: queryOf(url),
1492
1561
  body: await readBody(request),
1493
1562
  sqlite: options.sqlite,
@@ -1499,7 +1568,7 @@ var createService = (options) => {
1499
1568
  const short = await options.before?.(context);
1500
1569
  return withIssues(request, short ?? await handler(context));
1501
1570
  };
1502
- app.on(operation.method.toUpperCase(), honoPath(operation.path), route);
1571
+ app.on(operation.method.toUpperCase(), registeredRoute.path, route);
1503
1572
  }
1504
1573
  return {
1505
1574
  app,
@@ -1968,7 +2037,7 @@ var stateAdminRoutes = (routes) => {
1968
2037
  };
1969
2038
 
1970
2039
  // ../core/dist/version.js
1971
- var PACKAGE_VERSION = true ? "2.1.0" : UNRELEASED_VERSION;
2040
+ var PACKAGE_VERSION = true ? "2.2.0" : UNRELEASED_VERSION;
1972
2041
 
1973
2042
  // ../core/dist/signing.js
1974
2043
  var encoder = new TextEncoder();
@@ -4165,4 +4234,4 @@ export {
4165
4234
  apiKeyCredential,
4166
4235
  OdxAPI
4167
4236
  };
4168
- //# sourceMappingURL=chunk-EVG7IH3F.js.map
4237
+ //# sourceMappingURL=chunk-BOTT3UIM.js.map