@crvouga/mockingbird-service-mailosaur 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-mailosaur
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
@@ -1029,7 +1029,40 @@ var decodeBody = (contentType, bytes) => {
1029
1029
  return { kind: "bytes", value: bytes };
1030
1030
  };
1031
1031
  var readBody = async (message) => {
1032
- const bytes = new Uint8Array(await message.arrayBuffer());
1032
+ if (!(message instanceof Request) || !message.body) {
1033
+ if (message instanceof Request)
1034
+ message.signal.throwIfAborted();
1035
+ return decodeBody(message.headers.get("content-type"), new Uint8Array(await message.arrayBuffer()));
1036
+ }
1037
+ message.signal.throwIfAborted();
1038
+ const reader = message.body.getReader();
1039
+ const cancel = () => {
1040
+ void reader.cancel(message.signal.reason).catch(() => {
1041
+ });
1042
+ };
1043
+ message.signal.addEventListener("abort", cancel, { once: true });
1044
+ const chunks = [];
1045
+ let size = 0;
1046
+ try {
1047
+ for (; ; ) {
1048
+ message.signal.throwIfAborted();
1049
+ const { done, value } = await reader.read();
1050
+ message.signal.throwIfAborted();
1051
+ if (done)
1052
+ break;
1053
+ chunks.push(value);
1054
+ size += value.byteLength;
1055
+ }
1056
+ } finally {
1057
+ message.signal.removeEventListener("abort", cancel);
1058
+ reader.releaseLock();
1059
+ }
1060
+ const bytes = new Uint8Array(size);
1061
+ let offset = 0;
1062
+ for (const chunk of chunks) {
1063
+ bytes.set(chunk, offset);
1064
+ offset += chunk.byteLength;
1065
+ }
1033
1066
  return decodeBody(message.headers.get("content-type"), bytes);
1034
1067
  };
1035
1068
 
@@ -1841,7 +1874,42 @@ var verifyOperations = (document2, handlers) => {
1841
1874
  }
1842
1875
  return problems;
1843
1876
  };
1844
- var honoPath = (template) => template.replace(/\{([^}]+)\}/g, ":$1");
1877
+ var escapePattern = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1878
+ var serviceRoute = (template) => {
1879
+ const names = [];
1880
+ let pattern = "", end = 0;
1881
+ for (const match of template.matchAll(/\{([^}]+)\}/g)) {
1882
+ pattern += `${escapePattern(template.slice(end, match.index))}([^/]+?)`;
1883
+ const name = match[1];
1884
+ if (!name)
1885
+ throw new Error(`Invalid OpenAPI route template: ${template}`);
1886
+ names.push(name);
1887
+ end = match.index + match[0].length;
1888
+ }
1889
+ pattern += escapePattern(template.slice(end));
1890
+ const matcher = new RegExp(`^${pattern}$`);
1891
+ const path = template.split("/").map((segment, index) => {
1892
+ if (!segment.includes("{"))
1893
+ return segment;
1894
+ const literal = /^\{([^}]+)\}$/.exec(segment);
1895
+ if (literal)
1896
+ return `:${literal[1]}`;
1897
+ let expression = "", offset = 0;
1898
+ for (const match of segment.matchAll(/\{[^}]+\}/g)) {
1899
+ expression += `${escapePattern(segment.slice(offset, match.index))}[^/]+?`;
1900
+ offset = match.index + match[0].length;
1901
+ }
1902
+ expression += escapePattern(segment.slice(offset));
1903
+ return `:mockingbirdSegment${index}{${expression}}`;
1904
+ }).join("/");
1905
+ return {
1906
+ path,
1907
+ params: (pathname) => {
1908
+ const values = matcher.exec(pathname);
1909
+ return Object.fromEntries(names.map((name, index) => [name, decodeURIComponent(values?.[index + 1] ?? "")]));
1910
+ }
1911
+ };
1912
+ };
1845
1913
  var routeOrder = (a, b) => {
1846
1914
  const sa = a.path.split("/");
1847
1915
  const sb = b.path.split("/");
@@ -1876,6 +1944,7 @@ var createService = (options) => {
1876
1944
  for (const operation of operations) {
1877
1945
  const metadata = operationMetadata(operation.operation);
1878
1946
  const handler = options.handlers[operation.operationId];
1947
+ const registeredRoute = serviceRoute(operation.path);
1879
1948
  const route = async (c) => {
1880
1949
  const request = c.req.raw;
1881
1950
  if (!metadata.supported || !handler) {
@@ -1885,7 +1954,7 @@ var createService = (options) => {
1885
1954
  const context = {
1886
1955
  request,
1887
1956
  url,
1888
- params: c.req.param(),
1957
+ params: registeredRoute.params(url.pathname),
1889
1958
  query: queryOf(url),
1890
1959
  body: await readBody(request),
1891
1960
  sqlite: options.sqlite,
@@ -1897,7 +1966,7 @@ var createService = (options) => {
1897
1966
  const short = await options.before?.(context);
1898
1967
  return withIssues(request, short ?? await handler(context));
1899
1968
  };
1900
- app.on(operation.method.toUpperCase(), honoPath(operation.path), route);
1969
+ app.on(operation.method.toUpperCase(), registeredRoute.path, route);
1901
1970
  }
1902
1971
  return {
1903
1972
  app,
@@ -2366,7 +2435,7 @@ var stateAdminRoutes = (routes) => {
2366
2435
  };
2367
2436
 
2368
2437
  // ../core/dist/version.js
2369
- var PACKAGE_VERSION = true ? "2.1.0" : UNRELEASED_VERSION;
2438
+ var PACKAGE_VERSION = true ? "2.2.0" : UNRELEASED_VERSION;
2370
2439
 
2371
2440
  // ../core/dist/signing.js
2372
2441
  var encoder = new TextEncoder();
@@ -3813,4 +3882,4 @@ export {
3813
3882
  matchesCriteria,
3814
3883
  MailosaurAPI
3815
3884
  };
3816
- //# sourceMappingURL=chunk-YA4LLBU3.js.map
3885
+ //# sourceMappingURL=chunk-IBC3CHG6.js.map