@fragno-dev/db 0.1.13 → 0.1.15

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.
Files changed (178) hide show
  1. package/.turbo/turbo-build.log +179 -132
  2. package/CHANGELOG.md +30 -0
  3. package/dist/adapters/adapters.d.ts +27 -1
  4. package/dist/adapters/adapters.d.ts.map +1 -1
  5. package/dist/adapters/adapters.js.map +1 -1
  6. package/dist/adapters/drizzle/drizzle-adapter.d.ts +5 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  8. package/dist/adapters/drizzle/drizzle-adapter.js +15 -3
  9. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  10. package/dist/adapters/drizzle/drizzle-query.js +7 -5
  11. package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
  12. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -1
  13. package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -1
  14. package/dist/adapters/drizzle/drizzle-uow-compiler.js +76 -44
  15. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
  16. package/dist/adapters/drizzle/drizzle-uow-decoder.js +23 -16
  17. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
  18. package/dist/adapters/drizzle/drizzle-uow-executor.js +18 -7
  19. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
  20. package/dist/adapters/drizzle/generate.d.ts +4 -1
  21. package/dist/adapters/drizzle/generate.d.ts.map +1 -1
  22. package/dist/adapters/drizzle/generate.js +11 -18
  23. package/dist/adapters/drizzle/generate.js.map +1 -1
  24. package/dist/adapters/drizzle/shared.d.ts +14 -1
  25. package/dist/adapters/drizzle/shared.d.ts.map +1 -0
  26. package/dist/adapters/kysely/kysely-adapter.d.ts +5 -1
  27. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  28. package/dist/adapters/kysely/kysely-adapter.js +14 -3
  29. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  30. package/dist/adapters/kysely/kysely-query-builder.js +1 -1
  31. package/dist/adapters/kysely/kysely-query-compiler.js +3 -2
  32. package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
  33. package/dist/adapters/kysely/kysely-query.d.ts +1 -0
  34. package/dist/adapters/kysely/kysely-query.d.ts.map +1 -1
  35. package/dist/adapters/kysely/kysely-query.js +28 -19
  36. package/dist/adapters/kysely/kysely-query.js.map +1 -1
  37. package/dist/adapters/kysely/kysely-shared.d.ts +14 -0
  38. package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -0
  39. package/dist/adapters/kysely/kysely-shared.js +16 -1
  40. package/dist/adapters/kysely/kysely-shared.js.map +1 -1
  41. package/dist/adapters/kysely/kysely-uow-compiler.js +68 -16
  42. package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
  43. package/dist/adapters/kysely/kysely-uow-executor.js +8 -4
  44. package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -1
  45. package/dist/adapters/kysely/migration/execute-base.js +1 -1
  46. package/dist/adapters/kysely/migration/execute-base.js.map +1 -1
  47. package/dist/db-fragment-definition-builder.d.ts +152 -0
  48. package/dist/db-fragment-definition-builder.d.ts.map +1 -0
  49. package/dist/db-fragment-definition-builder.js +137 -0
  50. package/dist/db-fragment-definition-builder.js.map +1 -0
  51. package/dist/fragments/internal-fragment.d.ts +19 -0
  52. package/dist/fragments/internal-fragment.d.ts.map +1 -0
  53. package/dist/fragments/internal-fragment.js +39 -0
  54. package/dist/fragments/internal-fragment.js.map +1 -0
  55. package/dist/migration-engine/generation-engine.d.ts.map +1 -1
  56. package/dist/migration-engine/generation-engine.js +35 -15
  57. package/dist/migration-engine/generation-engine.js.map +1 -1
  58. package/dist/mod.d.ts +8 -18
  59. package/dist/mod.d.ts.map +1 -1
  60. package/dist/mod.js +7 -34
  61. package/dist/mod.js.map +1 -1
  62. package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js +165 -0
  63. package/dist/node_modules/.pnpm/rou3@0.7.8/node_modules/rou3/dist/index.js.map +1 -0
  64. package/dist/packages/fragno/dist/api/bind-services.js +20 -0
  65. package/dist/packages/fragno/dist/api/bind-services.js.map +1 -0
  66. package/dist/packages/fragno/dist/api/error.js +48 -0
  67. package/dist/packages/fragno/dist/api/error.js.map +1 -0
  68. package/dist/packages/fragno/dist/api/fragment-definition-builder.js +320 -0
  69. package/dist/packages/fragno/dist/api/fragment-definition-builder.js.map +1 -0
  70. package/dist/packages/fragno/dist/api/fragment-instantiator.js +487 -0
  71. package/dist/packages/fragno/dist/api/fragment-instantiator.js.map +1 -0
  72. package/dist/packages/fragno/dist/api/fragno-response.js +73 -0
  73. package/dist/packages/fragno/dist/api/fragno-response.js.map +1 -0
  74. package/dist/packages/fragno/dist/api/internal/response-stream.js +81 -0
  75. package/dist/packages/fragno/dist/api/internal/response-stream.js.map +1 -0
  76. package/dist/packages/fragno/dist/api/internal/route.js +10 -0
  77. package/dist/packages/fragno/dist/api/internal/route.js.map +1 -0
  78. package/dist/packages/fragno/dist/api/mutable-request-state.js +97 -0
  79. package/dist/packages/fragno/dist/api/mutable-request-state.js.map +1 -0
  80. package/dist/packages/fragno/dist/api/request-context-storage.js +43 -0
  81. package/dist/packages/fragno/dist/api/request-context-storage.js.map +1 -0
  82. package/dist/packages/fragno/dist/api/request-input-context.js +118 -0
  83. package/dist/packages/fragno/dist/api/request-input-context.js.map +1 -0
  84. package/dist/packages/fragno/dist/api/request-middleware.js +83 -0
  85. package/dist/packages/fragno/dist/api/request-middleware.js.map +1 -0
  86. package/dist/packages/fragno/dist/api/request-output-context.js +119 -0
  87. package/dist/packages/fragno/dist/api/request-output-context.js.map +1 -0
  88. package/dist/packages/fragno/dist/api/route.js +17 -0
  89. package/dist/packages/fragno/dist/api/route.js.map +1 -0
  90. package/dist/packages/fragno/dist/internal/symbols.js +10 -0
  91. package/dist/packages/fragno/dist/internal/symbols.js.map +1 -0
  92. package/dist/query/cursor.d.ts +10 -2
  93. package/dist/query/cursor.d.ts.map +1 -1
  94. package/dist/query/cursor.js +11 -4
  95. package/dist/query/cursor.js.map +1 -1
  96. package/dist/query/execute-unit-of-work.d.ts +123 -0
  97. package/dist/query/execute-unit-of-work.d.ts.map +1 -0
  98. package/dist/query/execute-unit-of-work.js +184 -0
  99. package/dist/query/execute-unit-of-work.js.map +1 -0
  100. package/dist/query/query.d.ts +3 -3
  101. package/dist/query/query.d.ts.map +1 -1
  102. package/dist/query/result-transform.js +4 -2
  103. package/dist/query/result-transform.js.map +1 -1
  104. package/dist/query/retry-policy.d.ts +88 -0
  105. package/dist/query/retry-policy.d.ts.map +1 -0
  106. package/dist/query/retry-policy.js +61 -0
  107. package/dist/query/retry-policy.js.map +1 -0
  108. package/dist/query/unit-of-work.d.ts +171 -32
  109. package/dist/query/unit-of-work.d.ts.map +1 -1
  110. package/dist/query/unit-of-work.js +530 -133
  111. package/dist/query/unit-of-work.js.map +1 -1
  112. package/dist/schema/serialize.js +12 -7
  113. package/dist/schema/serialize.js.map +1 -1
  114. package/dist/with-database.d.ts +28 -0
  115. package/dist/with-database.d.ts.map +1 -0
  116. package/dist/with-database.js +34 -0
  117. package/dist/with-database.js.map +1 -0
  118. package/package.json +10 -3
  119. package/src/adapters/adapters.ts +30 -0
  120. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +86 -17
  121. package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +291 -7
  122. package/src/adapters/drizzle/drizzle-adapter.test.ts +3 -51
  123. package/src/adapters/drizzle/drizzle-adapter.ts +35 -7
  124. package/src/adapters/drizzle/drizzle-query.ts +25 -15
  125. package/src/adapters/drizzle/drizzle-uow-compiler-mysql.test.ts +1442 -0
  126. package/src/adapters/drizzle/drizzle-uow-compiler-sqlite.test.ts +1414 -0
  127. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +78 -61
  128. package/src/adapters/drizzle/drizzle-uow-compiler.ts +123 -42
  129. package/src/adapters/drizzle/drizzle-uow-decoder.ts +34 -27
  130. package/src/adapters/drizzle/drizzle-uow-executor.ts +41 -8
  131. package/src/adapters/drizzle/generate.test.ts +102 -269
  132. package/src/adapters/drizzle/generate.ts +12 -30
  133. package/src/adapters/drizzle/test-utils.ts +36 -5
  134. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +66 -22
  135. package/src/adapters/kysely/kysely-adapter-sqlite.test.ts +156 -0
  136. package/src/adapters/kysely/kysely-adapter.ts +25 -2
  137. package/src/adapters/kysely/kysely-query-compiler.ts +3 -8
  138. package/src/adapters/kysely/kysely-query.ts +57 -37
  139. package/src/adapters/kysely/kysely-shared.ts +34 -0
  140. package/src/adapters/kysely/kysely-uow-compiler.test.ts +62 -74
  141. package/src/adapters/kysely/kysely-uow-compiler.ts +92 -24
  142. package/src/adapters/kysely/kysely-uow-executor.ts +26 -7
  143. package/src/adapters/kysely/kysely-uow-joins.test.ts +33 -50
  144. package/src/adapters/kysely/migration/execute-base.ts +1 -1
  145. package/src/db-fragment-definition-builder.test.ts +887 -0
  146. package/src/db-fragment-definition-builder.ts +506 -0
  147. package/src/db-fragment-instantiator.test.ts +467 -0
  148. package/src/db-fragment-integration.test.ts +408 -0
  149. package/src/fragments/internal-fragment.test.ts +160 -0
  150. package/src/fragments/internal-fragment.ts +85 -0
  151. package/src/migration-engine/generation-engine.test.ts +58 -15
  152. package/src/migration-engine/generation-engine.ts +78 -25
  153. package/src/mod.ts +35 -43
  154. package/src/query/cursor.test.ts +119 -0
  155. package/src/query/cursor.ts +17 -4
  156. package/src/query/execute-unit-of-work.test.ts +1310 -0
  157. package/src/query/execute-unit-of-work.ts +463 -0
  158. package/src/query/query.ts +4 -4
  159. package/src/query/result-transform.test.ts +129 -0
  160. package/src/query/result-transform.ts +4 -1
  161. package/src/query/retry-policy.test.ts +217 -0
  162. package/src/query/retry-policy.ts +141 -0
  163. package/src/query/unit-of-work-coordinator.test.ts +833 -0
  164. package/src/query/unit-of-work-types.test.ts +15 -2
  165. package/src/query/unit-of-work.test.ts +878 -200
  166. package/src/query/unit-of-work.ts +963 -321
  167. package/src/schema/serialize.ts +22 -11
  168. package/src/with-database.ts +140 -0
  169. package/tsdown.config.ts +1 -0
  170. package/dist/fragment.d.ts +0 -54
  171. package/dist/fragment.d.ts.map +0 -1
  172. package/dist/fragment.js +0 -92
  173. package/dist/fragment.js.map +0 -1
  174. package/dist/shared/settings-schema.js +0 -36
  175. package/dist/shared/settings-schema.js.map +0 -1
  176. package/src/fragment.test.ts +0 -341
  177. package/src/fragment.ts +0 -198
  178. package/src/shared/settings-schema.ts +0 -61
@@ -0,0 +1,81 @@
1
+ //#region ../fragno/dist/api/internal/response-stream.js
2
+ var ResponseStream = class {
3
+ #writer;
4
+ #encoder;
5
+ #abortSubscribers = [];
6
+ #responseReadable;
7
+ #aborted = false;
8
+ #closed = false;
9
+ /**
10
+ * Whether the stream has been aborted.
11
+ */
12
+ get aborted() {
13
+ return this.#aborted;
14
+ }
15
+ /**
16
+ * Whether the stream has been closed normally.
17
+ */
18
+ get closed() {
19
+ return this.#closed;
20
+ }
21
+ /**
22
+ * The readable stream that the response is piped to.
23
+ */
24
+ get responseReadable() {
25
+ return this.#responseReadable;
26
+ }
27
+ constructor(writable, readable) {
28
+ this.#writer = writable.getWriter();
29
+ this.#encoder = new TextEncoder();
30
+ const reader = readable.getReader();
31
+ this.#abortSubscribers.push(async () => {
32
+ await reader.cancel();
33
+ });
34
+ this.#responseReadable = new ReadableStream({
35
+ async pull(controller) {
36
+ const { done, value } = await reader.read();
37
+ if (done) controller.close();
38
+ else controller.enqueue(value);
39
+ },
40
+ cancel: () => {
41
+ this.abort();
42
+ }
43
+ });
44
+ }
45
+ async writeRaw(input) {
46
+ try {
47
+ if (typeof input === "string") input = this.#encoder.encode(input);
48
+ await this.#writer.write(input);
49
+ } catch {}
50
+ }
51
+ write(input) {
52
+ return this.writeRaw(JSON.stringify(input) + "\n");
53
+ }
54
+ sleep(ms) {
55
+ return new Promise((res) => setTimeout(res, ms));
56
+ }
57
+ async close() {
58
+ try {
59
+ await this.#writer.close();
60
+ } catch {} finally {
61
+ this.#closed = true;
62
+ }
63
+ }
64
+ onAbort(listener) {
65
+ this.#abortSubscribers.push(listener);
66
+ }
67
+ /**
68
+ * Abort the stream.
69
+ * You can call this method when stream is aborted by external event.
70
+ */
71
+ abort() {
72
+ if (!this.aborted) {
73
+ this.#aborted = true;
74
+ this.#abortSubscribers.forEach((subscriber) => subscriber());
75
+ }
76
+ }
77
+ };
78
+
79
+ //#endregion
80
+ export { ResponseStream };
81
+ //# sourceMappingURL=response-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-stream.js","names":["#aborted","#closed","#responseReadable","#writer","#encoder","#abortSubscribers"],"sources":["../../../../../../../fragno/dist/api/internal/response-stream.js"],"sourcesContent":["//#region src/api/internal/response-stream.ts\nvar ResponseStream = class {\n\t#writer;\n\t#encoder;\n\t#abortSubscribers = [];\n\t#responseReadable;\n\t#aborted = false;\n\t#closed = false;\n\t/**\n\t* Whether the stream has been aborted.\n\t*/\n\tget aborted() {\n\t\treturn this.#aborted;\n\t}\n\t/**\n\t* Whether the stream has been closed normally.\n\t*/\n\tget closed() {\n\t\treturn this.#closed;\n\t}\n\t/**\n\t* The readable stream that the response is piped to.\n\t*/\n\tget responseReadable() {\n\t\treturn this.#responseReadable;\n\t}\n\tconstructor(writable, readable) {\n\t\tthis.#writer = writable.getWriter();\n\t\tthis.#encoder = new TextEncoder();\n\t\tconst reader = readable.getReader();\n\t\tthis.#abortSubscribers.push(async () => {\n\t\t\tawait reader.cancel();\n\t\t});\n\t\tthis.#responseReadable = new ReadableStream({\n\t\t\tasync pull(controller) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) controller.close();\n\t\t\t\telse controller.enqueue(value);\n\t\t\t},\n\t\t\tcancel: () => {\n\t\t\t\tthis.abort();\n\t\t\t}\n\t\t});\n\t}\n\tasync writeRaw(input) {\n\t\ttry {\n\t\t\tif (typeof input === \"string\") input = this.#encoder.encode(input);\n\t\t\tawait this.#writer.write(input);\n\t\t} catch {}\n\t}\n\twrite(input) {\n\t\treturn this.writeRaw(JSON.stringify(input) + \"\\n\");\n\t}\n\tsleep(ms) {\n\t\treturn new Promise((res) => setTimeout(res, ms));\n\t}\n\tasync close() {\n\t\ttry {\n\t\t\tawait this.#writer.close();\n\t\t} catch {} finally {\n\t\t\tthis.#closed = true;\n\t\t}\n\t}\n\tonAbort(listener) {\n\t\tthis.#abortSubscribers.push(listener);\n\t}\n\t/**\n\t* Abort the stream.\n\t* You can call this method when stream is aborted by external event.\n\t*/\n\tabort() {\n\t\tif (!this.aborted) {\n\t\t\tthis.#aborted = true;\n\t\t\tthis.#abortSubscribers.forEach((subscriber) => subscriber());\n\t\t}\n\t}\n};\n\n//#endregion\nexport { ResponseStream };\n//# sourceMappingURL=response-stream.js.map"],"mappings":";AACA,IAAI,iBAAiB,MAAM;CAC1B;CACA;CACA,oBAAoB,EAAE;CACtB;CACA,WAAW;CACX,UAAU;;;;CAIV,IAAI,UAAU;AACb,SAAO,MAAKA;;;;;CAKb,IAAI,SAAS;AACZ,SAAO,MAAKC;;;;;CAKb,IAAI,mBAAmB;AACtB,SAAO,MAAKC;;CAEb,YAAY,UAAU,UAAU;AAC/B,QAAKC,SAAU,SAAS,WAAW;AACnC,QAAKC,UAAW,IAAI,aAAa;EACjC,MAAM,SAAS,SAAS,WAAW;AACnC,QAAKC,iBAAkB,KAAK,YAAY;AACvC,SAAM,OAAO,QAAQ;IACpB;AACF,QAAKH,mBAAoB,IAAI,eAAe;GAC3C,MAAM,KAAK,YAAY;IACtB,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,QAAI,KAAM,YAAW,OAAO;QACvB,YAAW,QAAQ,MAAM;;GAE/B,cAAc;AACb,SAAK,OAAO;;GAEb,CAAC;;CAEH,MAAM,SAAS,OAAO;AACrB,MAAI;AACH,OAAI,OAAO,UAAU,SAAU,SAAQ,MAAKE,QAAS,OAAO,MAAM;AAClE,SAAM,MAAKD,OAAQ,MAAM,MAAM;UACxB;;CAET,MAAM,OAAO;AACZ,SAAO,KAAK,SAAS,KAAK,UAAU,MAAM,GAAG,KAAK;;CAEnD,MAAM,IAAI;AACT,SAAO,IAAI,SAAS,QAAQ,WAAW,KAAK,GAAG,CAAC;;CAEjD,MAAM,QAAQ;AACb,MAAI;AACH,SAAM,MAAKA,OAAQ,OAAO;UACnB,WAAW;AAClB,SAAKF,SAAU;;;CAGjB,QAAQ,UAAU;AACjB,QAAKI,iBAAkB,KAAK,SAAS;;;;;;CAMtC,QAAQ;AACP,MAAI,CAAC,KAAK,SAAS;AAClB,SAAKL,UAAW;AAChB,SAAKK,iBAAkB,SAAS,eAAe,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ //#region ../fragno/dist/api/internal/route.js
2
+ function getMountRoute(opts) {
3
+ const mountRoute = opts.mountRoute ?? `/api/${opts.name}`;
4
+ if (mountRoute.endsWith("/")) return mountRoute.slice(0, -1);
5
+ return mountRoute;
6
+ }
7
+
8
+ //#endregion
9
+ export { getMountRoute };
10
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","names":[],"sources":["../../../../../../../fragno/dist/api/internal/route.js"],"sourcesContent":["//#region src/api/internal/route.ts\nfunction getMountRoute(opts) {\n\tconst mountRoute = opts.mountRoute ?? `/api/${opts.name}`;\n\tif (mountRoute.endsWith(\"/\")) return mountRoute.slice(0, -1);\n\treturn mountRoute;\n}\n\n//#endregion\nexport { getMountRoute };\n//# sourceMappingURL=route.js.map"],"mappings":";AACA,SAAS,cAAc,MAAM;CAC5B,MAAM,aAAa,KAAK,cAAc,QAAQ,KAAK;AACnD,KAAI,WAAW,SAAS,IAAI,CAAE,QAAO,WAAW,MAAM,GAAG,GAAG;AAC5D,QAAO"}
@@ -0,0 +1,97 @@
1
+ //#region ../fragno/dist/api/mutable-request-state.js
2
+ /**
3
+ * Holds mutable request state that can be modified by middleware and consumed by handlers.
4
+ *
5
+ * This class provides a structural way for middleware to modify request data:
6
+ * - Path parameters can be modified
7
+ * - Query/search parameters can be modified
8
+ * - Request body can be overridden
9
+ * - Request headers can be modified
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * // In middleware
14
+ * const state = new MutableRequestState({
15
+ * pathParams: { id: "123" },
16
+ * searchParams: new URLSearchParams("?role=user"),
17
+ * body: { name: "John" },
18
+ * headers: new Headers()
19
+ * });
20
+ *
21
+ * // Modify query parameters
22
+ * state.searchParams.set("role", "admin");
23
+ *
24
+ * // Override body
25
+ * state.setBody({ name: "Jane" });
26
+ *
27
+ * // Modify headers
28
+ * state.headers.set("X-Custom", "value");
29
+ * ```
30
+ */
31
+ var MutableRequestState = class {
32
+ #pathParams;
33
+ #searchParams;
34
+ #headers;
35
+ #initialBody;
36
+ #bodyOverride;
37
+ constructor(config) {
38
+ this.#pathParams = config.pathParams;
39
+ this.#searchParams = config.searchParams;
40
+ this.#headers = config.headers;
41
+ this.#initialBody = config.body;
42
+ this.#bodyOverride = void 0;
43
+ }
44
+ /**
45
+ * Path parameters extracted from the route.
46
+ * Can be modified directly (e.g., `state.pathParams.id = "456"`).
47
+ */
48
+ get pathParams() {
49
+ return this.#pathParams;
50
+ }
51
+ /**
52
+ * URLSearchParams for query parameters.
53
+ * Can be modified using URLSearchParams API (e.g., `state.searchParams.set("key", "value")`).
54
+ */
55
+ get searchParams() {
56
+ return this.#searchParams;
57
+ }
58
+ /**
59
+ * Request headers.
60
+ * Can be modified using Headers API (e.g., `state.headers.set("X-Custom", "value")`).
61
+ */
62
+ get headers() {
63
+ return this.#headers;
64
+ }
65
+ /**
66
+ * Get the current body value.
67
+ * Returns the override if set, otherwise the initial body.
68
+ */
69
+ get body() {
70
+ return this.#bodyOverride !== void 0 ? this.#bodyOverride : this.#initialBody;
71
+ }
72
+ /**
73
+ * Override the request body.
74
+ * This allows middleware to replace the body that will be seen by the handler.
75
+ *
76
+ * @param body - The new body value
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * // In middleware
81
+ * state.setBody({ modifiedField: "new value" });
82
+ * ```
83
+ */
84
+ setBody(body) {
85
+ this.#bodyOverride = body;
86
+ }
87
+ /**
88
+ * Check if the body has been overridden by middleware.
89
+ */
90
+ get hasBodyOverride() {
91
+ return this.#bodyOverride !== void 0;
92
+ }
93
+ };
94
+
95
+ //#endregion
96
+ export { MutableRequestState };
97
+ //# sourceMappingURL=mutable-request-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutable-request-state.js","names":["#pathParams","#searchParams","#headers","#initialBody","#bodyOverride"],"sources":["../../../../../../fragno/dist/api/mutable-request-state.js"],"sourcesContent":["//#region src/api/mutable-request-state.ts\n/**\n* Holds mutable request state that can be modified by middleware and consumed by handlers.\n*\n* This class provides a structural way for middleware to modify request data:\n* - Path parameters can be modified\n* - Query/search parameters can be modified\n* - Request body can be overridden\n* - Request headers can be modified\n*\n* @example\n* ```typescript\n* // In middleware\n* const state = new MutableRequestState({\n* pathParams: { id: \"123\" },\n* searchParams: new URLSearchParams(\"?role=user\"),\n* body: { name: \"John\" },\n* headers: new Headers()\n* });\n*\n* // Modify query parameters\n* state.searchParams.set(\"role\", \"admin\");\n*\n* // Override body\n* state.setBody({ name: \"Jane\" });\n*\n* // Modify headers\n* state.headers.set(\"X-Custom\", \"value\");\n* ```\n*/\nvar MutableRequestState = class {\n\t#pathParams;\n\t#searchParams;\n\t#headers;\n\t#initialBody;\n\t#bodyOverride;\n\tconstructor(config) {\n\t\tthis.#pathParams = config.pathParams;\n\t\tthis.#searchParams = config.searchParams;\n\t\tthis.#headers = config.headers;\n\t\tthis.#initialBody = config.body;\n\t\tthis.#bodyOverride = void 0;\n\t}\n\t/**\n\t* Path parameters extracted from the route.\n\t* Can be modified directly (e.g., `state.pathParams.id = \"456\"`).\n\t*/\n\tget pathParams() {\n\t\treturn this.#pathParams;\n\t}\n\t/**\n\t* URLSearchParams for query parameters.\n\t* Can be modified using URLSearchParams API (e.g., `state.searchParams.set(\"key\", \"value\")`).\n\t*/\n\tget searchParams() {\n\t\treturn this.#searchParams;\n\t}\n\t/**\n\t* Request headers.\n\t* Can be modified using Headers API (e.g., `state.headers.set(\"X-Custom\", \"value\")`).\n\t*/\n\tget headers() {\n\t\treturn this.#headers;\n\t}\n\t/**\n\t* Get the current body value.\n\t* Returns the override if set, otherwise the initial body.\n\t*/\n\tget body() {\n\t\treturn this.#bodyOverride !== void 0 ? this.#bodyOverride : this.#initialBody;\n\t}\n\t/**\n\t* Override the request body.\n\t* This allows middleware to replace the body that will be seen by the handler.\n\t*\n\t* @param body - The new body value\n\t*\n\t* @example\n\t* ```typescript\n\t* // In middleware\n\t* state.setBody({ modifiedField: \"new value\" });\n\t* ```\n\t*/\n\tsetBody(body) {\n\t\tthis.#bodyOverride = body;\n\t}\n\t/**\n\t* Check if the body has been overridden by middleware.\n\t*/\n\tget hasBodyOverride() {\n\t\treturn this.#bodyOverride !== void 0;\n\t}\n};\n\n//#endregion\nexport { MutableRequestState };\n//# sourceMappingURL=mutable-request-state.js.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,IAAI,sBAAsB,MAAM;CAC/B;CACA;CACA;CACA;CACA;CACA,YAAY,QAAQ;AACnB,QAAKA,aAAc,OAAO;AAC1B,QAAKC,eAAgB,OAAO;AAC5B,QAAKC,UAAW,OAAO;AACvB,QAAKC,cAAe,OAAO;AAC3B,QAAKC,eAAgB,KAAK;;;;;;CAM3B,IAAI,aAAa;AAChB,SAAO,MAAKJ;;;;;;CAMb,IAAI,eAAe;AAClB,SAAO,MAAKC;;;;;;CAMb,IAAI,UAAU;AACb,SAAO,MAAKC;;;;;;CAMb,IAAI,OAAO;AACV,SAAO,MAAKE,iBAAkB,KAAK,IAAI,MAAKA,eAAgB,MAAKD;;;;;;;;;;;;;;CAclE,QAAQ,MAAM;AACb,QAAKC,eAAgB;;;;;CAKtB,IAAI,kBAAkB;AACrB,SAAO,MAAKA,iBAAkB,KAAK"}
@@ -0,0 +1,43 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+
3
+ //#region ../fragno/dist/api/request-context-storage.js
4
+ /**
5
+ * Typed wrapper around AsyncLocalStorage for managing per-request data storage.
6
+ * Each fragment instance has its own storage to ensure proper isolation.
7
+ *
8
+ * TRequestStorage represents the type of data stored per-request (e.g., { userId: string, requestId: number })
9
+ *
10
+ * Note: The data stored should be an object that can be mutated during the request lifecycle.
11
+ * For example, you can store { uow: UnitOfWork } and modify properties on that object.
12
+ *
13
+ * @internal - Used by @fragno-dev/db, not part of public API
14
+ */
15
+ var RequestContextStorage = class {
16
+ #storage;
17
+ constructor() {
18
+ this.#storage = new AsyncLocalStorage();
19
+ }
20
+ run(data, callback) {
21
+ return this.#storage.run(data, callback);
22
+ }
23
+ /**
24
+ * Get the current stored data from AsyncLocalStorage.
25
+ * @throws an error if called outside of a run() callback.
26
+ *
27
+ * Note: The returned object can be mutated. Changes will be visible to all code
28
+ * running within the same async context.
29
+ */
30
+ getStore() {
31
+ const store = this.#storage.getStore();
32
+ if (!store) throw new Error("No storage found in RequestContextStorage. Service must be called within a route handler OR using `inContext`.");
33
+ return store;
34
+ }
35
+ runWithInitializer(initializer, callback) {
36
+ const data = initializer();
37
+ return this.#storage.run(data, callback);
38
+ }
39
+ };
40
+
41
+ //#endregion
42
+ export { RequestContextStorage };
43
+ //# sourceMappingURL=request-context-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context-storage.js","names":["#storage"],"sources":["../../../../../../fragno/dist/api/request-context-storage.js"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\n//#region src/api/request-context-storage.ts\n/**\n* Typed wrapper around AsyncLocalStorage for managing per-request data storage.\n* Each fragment instance has its own storage to ensure proper isolation.\n*\n* TRequestStorage represents the type of data stored per-request (e.g., { userId: string, requestId: number })\n*\n* Note: The data stored should be an object that can be mutated during the request lifecycle.\n* For example, you can store { uow: UnitOfWork } and modify properties on that object.\n*\n* @internal - Used by @fragno-dev/db, not part of public API\n*/\nvar RequestContextStorage = class {\n\t#storage;\n\tconstructor() {\n\t\tthis.#storage = new AsyncLocalStorage();\n\t}\n\trun(data, callback) {\n\t\treturn this.#storage.run(data, callback);\n\t}\n\t/**\n\t* Get the current stored data from AsyncLocalStorage.\n\t* @throws an error if called outside of a run() callback.\n\t*\n\t* Note: The returned object can be mutated. Changes will be visible to all code\n\t* running within the same async context.\n\t*/\n\tgetStore() {\n\t\tconst store = this.#storage.getStore();\n\t\tif (!store) throw new Error(\"No storage found in RequestContextStorage. Service must be called within a route handler OR using `inContext`.\");\n\t\treturn store;\n\t}\n\trunWithInitializer(initializer, callback) {\n\t\tconst data = initializer();\n\t\treturn this.#storage.run(data, callback);\n\t}\n};\n\n//#endregion\nexport { RequestContextStorage };\n//# sourceMappingURL=request-context-storage.js.map"],"mappings":";;;;;;;;;;;;;;AAcA,IAAI,wBAAwB,MAAM;CACjC;CACA,cAAc;AACb,QAAKA,UAAW,IAAI,mBAAmB;;CAExC,IAAI,MAAM,UAAU;AACnB,SAAO,MAAKA,QAAS,IAAI,MAAM,SAAS;;;;;;;;;CASzC,WAAW;EACV,MAAM,QAAQ,MAAKA,QAAS,UAAU;AACtC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,iHAAiH;AAC7I,SAAO;;CAER,mBAAmB,aAAa,UAAU;EACzC,MAAM,OAAO,aAAa;AAC1B,SAAO,MAAKA,QAAS,IAAI,MAAM,SAAS"}
@@ -0,0 +1,118 @@
1
+ import { FragnoApiValidationError } from "./error.js";
2
+
3
+ //#region ../fragno/dist/api/request-input-context.js
4
+ var RequestInputContext = class RequestInputContext$1 {
5
+ #path;
6
+ #method;
7
+ #pathParams;
8
+ #searchParams;
9
+ #headers;
10
+ #body;
11
+ #parsedBody;
12
+ #inputSchema;
13
+ #shouldValidateInput;
14
+ constructor(config) {
15
+ this.#path = config.path;
16
+ this.#method = config.method;
17
+ this.#pathParams = config.pathParams;
18
+ this.#searchParams = config.searchParams;
19
+ this.#headers = config.headers;
20
+ this.#body = config.rawBody;
21
+ this.#parsedBody = config.parsedBody;
22
+ this.#inputSchema = config.inputSchema;
23
+ this.#shouldValidateInput = config.shouldValidateInput ?? true;
24
+ }
25
+ /**
26
+ * Create a RequestContext from a Request object for server-side handling
27
+ */
28
+ static async fromRequest(config) {
29
+ return new RequestInputContext$1({
30
+ method: config.method,
31
+ path: config.path,
32
+ pathParams: config.state.pathParams,
33
+ searchParams: config.state.searchParams,
34
+ headers: config.state.headers,
35
+ parsedBody: config.state.body,
36
+ rawBody: config.rawBody,
37
+ inputSchema: config.inputSchema,
38
+ shouldValidateInput: config.shouldValidateInput
39
+ });
40
+ }
41
+ /**
42
+ * Create a RequestContext for server-side rendering contexts (no Request object)
43
+ */
44
+ static fromSSRContext(config) {
45
+ return new RequestInputContext$1({
46
+ method: config.method,
47
+ path: config.path,
48
+ pathParams: config.pathParams,
49
+ searchParams: config.searchParams ?? new URLSearchParams(),
50
+ headers: config.headers ?? new Headers(),
51
+ parsedBody: "body" in config ? config.body : void 0,
52
+ inputSchema: "inputSchema" in config ? config.inputSchema : void 0,
53
+ shouldValidateInput: false
54
+ });
55
+ }
56
+ /**
57
+ * The HTTP method as string (e.g., `GET`, `POST`)
58
+ */
59
+ get method() {
60
+ return this.#method;
61
+ }
62
+ /**
63
+ * The matched route path (e.g., `/users/:id`)
64
+ * @remarks `string`
65
+ */
66
+ get path() {
67
+ return this.#path;
68
+ }
69
+ /**
70
+ * Extracted path parameters as object (e.g., `{ id: '123' }`)
71
+ * @remarks `Record<string, string>`
72
+ */
73
+ get pathParams() {
74
+ return this.#pathParams;
75
+ }
76
+ /**
77
+ * [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object for query parameters
78
+ * @remarks `URLSearchParams`
79
+ */
80
+ get query() {
81
+ return this.#searchParams;
82
+ }
83
+ /**
84
+ * [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object for request headers
85
+ * @remarks `Headers`
86
+ */
87
+ get headers() {
88
+ return this.#headers;
89
+ }
90
+ get rawBody() {
91
+ return this.#body;
92
+ }
93
+ /**
94
+ * Input validation context (only if inputSchema is defined)
95
+ * @remarks `InputContext`
96
+ */
97
+ get input() {
98
+ if (!this.#inputSchema) return;
99
+ return {
100
+ schema: this.#inputSchema,
101
+ valid: async () => {
102
+ if (!this.#shouldValidateInput) return this.#parsedBody;
103
+ return this.#validateInput();
104
+ }
105
+ };
106
+ }
107
+ async #validateInput() {
108
+ if (!this.#inputSchema) throw new Error("No input schema defined for this route");
109
+ if (this.#parsedBody instanceof FormData || this.#parsedBody instanceof Blob) throw new Error("Schema validation is only supported for JSON data, not FormData or Blob");
110
+ const result = await this.#inputSchema["~standard"].validate(this.#parsedBody);
111
+ if (result.issues) throw new FragnoApiValidationError("Validation failed", result.issues);
112
+ return result.value;
113
+ }
114
+ };
115
+
116
+ //#endregion
117
+ export { RequestInputContext };
118
+ //# sourceMappingURL=request-input-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-input-context.js","names":["RequestInputContext","#path","#method","#pathParams","#searchParams","#headers","#body","#parsedBody","#inputSchema","#shouldValidateInput","#validateInput"],"sources":["../../../../../../fragno/dist/api/request-input-context.js"],"sourcesContent":["import { FragnoApiValidationError } from \"./error.js\";\n\n//#region src/api/request-input-context.ts\nvar RequestInputContext = class RequestInputContext {\n\t#path;\n\t#method;\n\t#pathParams;\n\t#searchParams;\n\t#headers;\n\t#body;\n\t#parsedBody;\n\t#inputSchema;\n\t#shouldValidateInput;\n\tconstructor(config) {\n\t\tthis.#path = config.path;\n\t\tthis.#method = config.method;\n\t\tthis.#pathParams = config.pathParams;\n\t\tthis.#searchParams = config.searchParams;\n\t\tthis.#headers = config.headers;\n\t\tthis.#body = config.rawBody;\n\t\tthis.#parsedBody = config.parsedBody;\n\t\tthis.#inputSchema = config.inputSchema;\n\t\tthis.#shouldValidateInput = config.shouldValidateInput ?? true;\n\t}\n\t/**\n\t* Create a RequestContext from a Request object for server-side handling\n\t*/\n\tstatic async fromRequest(config) {\n\t\treturn new RequestInputContext({\n\t\t\tmethod: config.method,\n\t\t\tpath: config.path,\n\t\t\tpathParams: config.state.pathParams,\n\t\t\tsearchParams: config.state.searchParams,\n\t\t\theaders: config.state.headers,\n\t\t\tparsedBody: config.state.body,\n\t\t\trawBody: config.rawBody,\n\t\t\tinputSchema: config.inputSchema,\n\t\t\tshouldValidateInput: config.shouldValidateInput\n\t\t});\n\t}\n\t/**\n\t* Create a RequestContext for server-side rendering contexts (no Request object)\n\t*/\n\tstatic fromSSRContext(config) {\n\t\treturn new RequestInputContext({\n\t\t\tmethod: config.method,\n\t\t\tpath: config.path,\n\t\t\tpathParams: config.pathParams,\n\t\t\tsearchParams: config.searchParams ?? new URLSearchParams(),\n\t\t\theaders: config.headers ?? new Headers(),\n\t\t\tparsedBody: \"body\" in config ? config.body : void 0,\n\t\t\tinputSchema: \"inputSchema\" in config ? config.inputSchema : void 0,\n\t\t\tshouldValidateInput: false\n\t\t});\n\t}\n\t/**\n\t* The HTTP method as string (e.g., `GET`, `POST`)\n\t*/\n\tget method() {\n\t\treturn this.#method;\n\t}\n\t/**\n\t* The matched route path (e.g., `/users/:id`)\n\t* @remarks `string`\n\t*/\n\tget path() {\n\t\treturn this.#path;\n\t}\n\t/**\n\t* Extracted path parameters as object (e.g., `{ id: '123' }`)\n\t* @remarks `Record<string, string>`\n\t*/\n\tget pathParams() {\n\t\treturn this.#pathParams;\n\t}\n\t/**\n\t* [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object for query parameters\n\t* @remarks `URLSearchParams`\n\t*/\n\tget query() {\n\t\treturn this.#searchParams;\n\t}\n\t/**\n\t* [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object for request headers\n\t* @remarks `Headers`\n\t*/\n\tget headers() {\n\t\treturn this.#headers;\n\t}\n\tget rawBody() {\n\t\treturn this.#body;\n\t}\n\t/**\n\t* Input validation context (only if inputSchema is defined)\n\t* @remarks `InputContext`\n\t*/\n\tget input() {\n\t\tif (!this.#inputSchema) return;\n\t\treturn {\n\t\t\tschema: this.#inputSchema,\n\t\t\tvalid: async () => {\n\t\t\t\tif (!this.#shouldValidateInput) return this.#parsedBody;\n\t\t\t\treturn this.#validateInput();\n\t\t\t}\n\t\t};\n\t}\n\tasync #validateInput() {\n\t\tif (!this.#inputSchema) throw new Error(\"No input schema defined for this route\");\n\t\tif (this.#parsedBody instanceof FormData || this.#parsedBody instanceof Blob) throw new Error(\"Schema validation is only supported for JSON data, not FormData or Blob\");\n\t\tconst result = await this.#inputSchema[\"~standard\"].validate(this.#parsedBody);\n\t\tif (result.issues) throw new FragnoApiValidationError(\"Validation failed\", result.issues);\n\t\treturn result.value;\n\t}\n};\n\n//#endregion\nexport { RequestInputContext };\n//# sourceMappingURL=request-input-context.js.map"],"mappings":";;;AAGA,IAAI,sBAAsB,MAAMA,sBAAoB;CACnD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,YAAY,QAAQ;AACnB,QAAKC,OAAQ,OAAO;AACpB,QAAKC,SAAU,OAAO;AACtB,QAAKC,aAAc,OAAO;AAC1B,QAAKC,eAAgB,OAAO;AAC5B,QAAKC,UAAW,OAAO;AACvB,QAAKC,OAAQ,OAAO;AACpB,QAAKC,aAAc,OAAO;AAC1B,QAAKC,cAAe,OAAO;AAC3B,QAAKC,sBAAuB,OAAO,uBAAuB;;;;;CAK3D,aAAa,YAAY,QAAQ;AAChC,SAAO,IAAIT,sBAAoB;GAC9B,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,YAAY,OAAO,MAAM;GACzB,cAAc,OAAO,MAAM;GAC3B,SAAS,OAAO,MAAM;GACtB,YAAY,OAAO,MAAM;GACzB,SAAS,OAAO;GAChB,aAAa,OAAO;GACpB,qBAAqB,OAAO;GAC5B,CAAC;;;;;CAKH,OAAO,eAAe,QAAQ;AAC7B,SAAO,IAAIA,sBAAoB;GAC9B,QAAQ,OAAO;GACf,MAAM,OAAO;GACb,YAAY,OAAO;GACnB,cAAc,OAAO,gBAAgB,IAAI,iBAAiB;GAC1D,SAAS,OAAO,WAAW,IAAI,SAAS;GACxC,YAAY,UAAU,SAAS,OAAO,OAAO,KAAK;GAClD,aAAa,iBAAiB,SAAS,OAAO,cAAc,KAAK;GACjE,qBAAqB;GACrB,CAAC;;;;;CAKH,IAAI,SAAS;AACZ,SAAO,MAAKE;;;;;;CAMb,IAAI,OAAO;AACV,SAAO,MAAKD;;;;;;CAMb,IAAI,aAAa;AAChB,SAAO,MAAKE;;;;;;CAMb,IAAI,QAAQ;AACX,SAAO,MAAKC;;;;;;CAMb,IAAI,UAAU;AACb,SAAO,MAAKC;;CAEb,IAAI,UAAU;AACb,SAAO,MAAKC;;;;;;CAMb,IAAI,QAAQ;AACX,MAAI,CAAC,MAAKE,YAAc;AACxB,SAAO;GACN,QAAQ,MAAKA;GACb,OAAO,YAAY;AAClB,QAAI,CAAC,MAAKC,oBAAsB,QAAO,MAAKF;AAC5C,WAAO,MAAKG,eAAgB;;GAE7B;;CAEF,OAAMA,gBAAiB;AACtB,MAAI,CAAC,MAAKF,YAAc,OAAM,IAAI,MAAM,yCAAyC;AACjF,MAAI,MAAKD,sBAAuB,YAAY,MAAKA,sBAAuB,KAAM,OAAM,IAAI,MAAM,0EAA0E;EACxK,MAAM,SAAS,MAAM,MAAKC,YAAa,aAAa,SAAS,MAAKD,WAAY;AAC9E,MAAI,OAAO,OAAQ,OAAM,IAAI,yBAAyB,qBAAqB,OAAO,OAAO;AACzF,SAAO,OAAO"}
@@ -0,0 +1,83 @@
1
+ import { RequestInputContext } from "./request-input-context.js";
2
+ import { OutputContext, RequestOutputContext } from "./request-output-context.js";
3
+
4
+ //#region ../fragno/dist/api/request-middleware.js
5
+ var RequestMiddlewareOutputContext = class extends OutputContext {
6
+ #deps;
7
+ #services;
8
+ constructor(deps, services) {
9
+ super();
10
+ this.#deps = deps;
11
+ this.#services = services;
12
+ }
13
+ get deps() {
14
+ return this.#deps;
15
+ }
16
+ get services() {
17
+ return this.#services;
18
+ }
19
+ };
20
+ var RequestMiddlewareInputContext = class {
21
+ #options;
22
+ #route;
23
+ #state;
24
+ constructor(routes, options) {
25
+ this.#options = options;
26
+ this.#state = options.state;
27
+ const route = routes.find((route$1) => route$1.path === options.path && route$1.method === options.method);
28
+ if (!route) throw new Error(`Route not found: ${options.path} ${options.method}`);
29
+ this.#route = route;
30
+ }
31
+ get path() {
32
+ return this.#options.path;
33
+ }
34
+ get method() {
35
+ return this.#options.method;
36
+ }
37
+ get pathParams() {
38
+ return this.#state.pathParams;
39
+ }
40
+ get queryParams() {
41
+ return this.#state.searchParams;
42
+ }
43
+ get headers() {
44
+ return this.#state.headers;
45
+ }
46
+ get inputSchema() {
47
+ return this.#route.inputSchema;
48
+ }
49
+ get outputSchema() {
50
+ return this.#route.outputSchema;
51
+ }
52
+ /**
53
+ * Access to the mutable request state.
54
+ * Use this to modify query parameters, path parameters, or request body.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * // Modify body
59
+ * requestState.setBody({ modified: true });
60
+ *
61
+ * // Query params are already accessible via queryParams getter
62
+ * // Path params are already accessible via pathParams getter
63
+ * ```
64
+ */
65
+ get requestState() {
66
+ return this.#state;
67
+ }
68
+ ifMatchesRoute = async (method, path, handler) => {
69
+ if (this.path !== path || this.method !== method) return;
70
+ return await handler(await RequestInputContext.fromRequest({
71
+ request: this.#options.request,
72
+ method: this.#options.method,
73
+ path,
74
+ pathParams: this.pathParams,
75
+ inputSchema: this.#route.inputSchema,
76
+ state: this.#state
77
+ }), new RequestOutputContext(this.#route.outputSchema));
78
+ };
79
+ };
80
+
81
+ //#endregion
82
+ export { RequestMiddlewareInputContext, RequestMiddlewareOutputContext };
83
+ //# sourceMappingURL=request-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-middleware.js","names":["#deps","#services","#options","#state","#route"],"sources":["../../../../../../fragno/dist/api/request-middleware.js"],"sourcesContent":["import { RequestInputContext } from \"./request-input-context.js\";\nimport { OutputContext, RequestOutputContext } from \"./request-output-context.js\";\n\n//#region src/api/request-middleware.ts\nvar RequestMiddlewareOutputContext = class extends OutputContext {\n\t#deps;\n\t#services;\n\tconstructor(deps, services) {\n\t\tsuper();\n\t\tthis.#deps = deps;\n\t\tthis.#services = services;\n\t}\n\tget deps() {\n\t\treturn this.#deps;\n\t}\n\tget services() {\n\t\treturn this.#services;\n\t}\n};\nvar RequestMiddlewareInputContext = class {\n\t#options;\n\t#route;\n\t#state;\n\tconstructor(routes, options) {\n\t\tthis.#options = options;\n\t\tthis.#state = options.state;\n\t\tconst route = routes.find((route$1) => route$1.path === options.path && route$1.method === options.method);\n\t\tif (!route) throw new Error(`Route not found: ${options.path} ${options.method}`);\n\t\tthis.#route = route;\n\t}\n\tget path() {\n\t\treturn this.#options.path;\n\t}\n\tget method() {\n\t\treturn this.#options.method;\n\t}\n\tget pathParams() {\n\t\treturn this.#state.pathParams;\n\t}\n\tget queryParams() {\n\t\treturn this.#state.searchParams;\n\t}\n\tget headers() {\n\t\treturn this.#state.headers;\n\t}\n\tget inputSchema() {\n\t\treturn this.#route.inputSchema;\n\t}\n\tget outputSchema() {\n\t\treturn this.#route.outputSchema;\n\t}\n\t/**\n\t* Access to the mutable request state.\n\t* Use this to modify query parameters, path parameters, or request body.\n\t*\n\t* @example\n\t* ```typescript\n\t* // Modify body\n\t* requestState.setBody({ modified: true });\n\t*\n\t* // Query params are already accessible via queryParams getter\n\t* // Path params are already accessible via pathParams getter\n\t* ```\n\t*/\n\tget requestState() {\n\t\treturn this.#state;\n\t}\n\tifMatchesRoute = async (method, path, handler) => {\n\t\tif (this.path !== path || this.method !== method) return;\n\t\treturn await handler(await RequestInputContext.fromRequest({\n\t\t\trequest: this.#options.request,\n\t\t\tmethod: this.#options.method,\n\t\t\tpath,\n\t\t\tpathParams: this.pathParams,\n\t\t\tinputSchema: this.#route.inputSchema,\n\t\t\tstate: this.#state\n\t\t}), new RequestOutputContext(this.#route.outputSchema));\n\t};\n};\n\n//#endregion\nexport { RequestMiddlewareInputContext, RequestMiddlewareOutputContext };\n//# sourceMappingURL=request-middleware.js.map"],"mappings":";;;;AAIA,IAAI,iCAAiC,cAAc,cAAc;CAChE;CACA;CACA,YAAY,MAAM,UAAU;AAC3B,SAAO;AACP,QAAKA,OAAQ;AACb,QAAKC,WAAY;;CAElB,IAAI,OAAO;AACV,SAAO,MAAKD;;CAEb,IAAI,WAAW;AACd,SAAO,MAAKC;;;AAGd,IAAI,gCAAgC,MAAM;CACzC;CACA;CACA;CACA,YAAY,QAAQ,SAAS;AAC5B,QAAKC,UAAW;AAChB,QAAKC,QAAS,QAAQ;EACtB,MAAM,QAAQ,OAAO,MAAM,YAAY,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,WAAW,QAAQ,OAAO;AAC1G,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,oBAAoB,QAAQ,KAAK,GAAG,QAAQ,SAAS;AACjF,QAAKC,QAAS;;CAEf,IAAI,OAAO;AACV,SAAO,MAAKF,QAAS;;CAEtB,IAAI,SAAS;AACZ,SAAO,MAAKA,QAAS;;CAEtB,IAAI,aAAa;AAChB,SAAO,MAAKC,MAAO;;CAEpB,IAAI,cAAc;AACjB,SAAO,MAAKA,MAAO;;CAEpB,IAAI,UAAU;AACb,SAAO,MAAKA,MAAO;;CAEpB,IAAI,cAAc;AACjB,SAAO,MAAKC,MAAO;;CAEpB,IAAI,eAAe;AAClB,SAAO,MAAKA,MAAO;;;;;;;;;;;;;;;CAepB,IAAI,eAAe;AAClB,SAAO,MAAKD;;CAEb,iBAAiB,OAAO,QAAQ,MAAM,YAAY;AACjD,MAAI,KAAK,SAAS,QAAQ,KAAK,WAAW,OAAQ;AAClD,SAAO,MAAM,QAAQ,MAAM,oBAAoB,YAAY;GAC1D,SAAS,MAAKD,QAAS;GACvB,QAAQ,MAAKA,QAAS;GACtB;GACA,YAAY,KAAK;GACjB,aAAa,MAAKE,MAAO;GACzB,OAAO,MAAKD;GACZ,CAAC,EAAE,IAAI,qBAAqB,MAAKC,MAAO,aAAa,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { ResponseStream } from "./internal/response-stream.js";
2
+
3
+ //#region ../fragno/dist/api/request-output-context.js
4
+ /**
5
+ * Utility function to merge headers from multiple sources.
6
+ * Later headers override earlier ones.
7
+ */
8
+ function mergeHeaders(...headerSources) {
9
+ const mergedHeaders = new Headers();
10
+ for (const headerSource of headerSources) {
11
+ if (!headerSource) continue;
12
+ if (headerSource instanceof Headers) for (const [key, value] of headerSource.entries()) mergedHeaders.set(key, value);
13
+ else if (Array.isArray(headerSource)) for (const [key, value] of headerSource) mergedHeaders.set(key, value);
14
+ else for (const [key, value] of Object.entries(headerSource)) mergedHeaders.set(key, value);
15
+ }
16
+ return mergedHeaders;
17
+ }
18
+ var OutputContext = class {
19
+ /**
20
+ * Creates an error response.
21
+ *
22
+ * Shortcut for `throw new FragnoApiError(...)`
23
+ */
24
+ error = ({ message, code }, initOrStatus, headers) => {
25
+ if (typeof initOrStatus === "undefined") return Response.json({
26
+ message,
27
+ code
28
+ }, {
29
+ status: 500,
30
+ headers
31
+ });
32
+ if (typeof initOrStatus === "number") return Response.json({
33
+ message,
34
+ code
35
+ }, {
36
+ status: initOrStatus,
37
+ headers
38
+ });
39
+ const mergedHeaders = mergeHeaders(initOrStatus.headers, headers);
40
+ return Response.json({
41
+ message,
42
+ code
43
+ }, {
44
+ status: initOrStatus.status,
45
+ headers: mergedHeaders
46
+ });
47
+ };
48
+ empty = (initOrStatus, headers) => {
49
+ const defaultHeaders = {};
50
+ if (typeof initOrStatus === "undefined") {
51
+ const mergedHeaders$1 = mergeHeaders(defaultHeaders, headers);
52
+ return new Response(null, {
53
+ status: 201,
54
+ headers: mergedHeaders$1
55
+ });
56
+ }
57
+ if (typeof initOrStatus === "number") {
58
+ const mergedHeaders$1 = mergeHeaders(defaultHeaders, headers);
59
+ return new Response(null, {
60
+ status: initOrStatus,
61
+ headers: mergedHeaders$1
62
+ });
63
+ }
64
+ const mergedHeaders = mergeHeaders(defaultHeaders, initOrStatus.headers, headers);
65
+ return new Response(null, {
66
+ status: initOrStatus.status,
67
+ headers: mergedHeaders
68
+ });
69
+ };
70
+ json = (object, initOrStatus, headers) => {
71
+ if (typeof initOrStatus === "undefined") return Response.json(object, {
72
+ status: 200,
73
+ headers
74
+ });
75
+ if (typeof initOrStatus === "number") return Response.json(object, {
76
+ status: initOrStatus,
77
+ headers
78
+ });
79
+ const mergedHeaders = mergeHeaders(initOrStatus.headers, headers);
80
+ return Response.json(object, {
81
+ status: initOrStatus.status,
82
+ headers: mergedHeaders
83
+ });
84
+ };
85
+ jsonStream = (cb, { onError, headers } = {}) => {
86
+ const defaultHeaders = {
87
+ "content-type": "application/x-ndjson; charset=utf-8",
88
+ "transfer-encoding": "chunked",
89
+ "cache-control": "no-cache"
90
+ };
91
+ const { readable, writable } = new TransformStream();
92
+ const stream = new ResponseStream(writable, readable);
93
+ (async () => {
94
+ try {
95
+ await cb(stream);
96
+ } catch (e) {
97
+ if (e === void 0) {} else if (e instanceof Error && onError) await onError(e, stream);
98
+ else console.error(e);
99
+ } finally {
100
+ stream.close();
101
+ }
102
+ })();
103
+ return new Response(stream.responseReadable, {
104
+ status: 200,
105
+ headers: mergeHeaders(defaultHeaders, headers)
106
+ });
107
+ };
108
+ };
109
+ var RequestOutputContext = class extends OutputContext {
110
+ #outputSchema;
111
+ constructor(outputSchema) {
112
+ super();
113
+ this.#outputSchema = outputSchema;
114
+ }
115
+ };
116
+
117
+ //#endregion
118
+ export { OutputContext, RequestOutputContext };
119
+ //# sourceMappingURL=request-output-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-output-context.js","names":["#outputSchema"],"sources":["../../../../../../fragno/dist/api/request-output-context.js"],"sourcesContent":["import { ResponseStream } from \"./internal/response-stream.js\";\n\n//#region src/api/request-output-context.ts\n/**\n* Utility function to merge headers from multiple sources.\n* Later headers override earlier ones.\n*/\nfunction mergeHeaders(...headerSources) {\n\tconst mergedHeaders = new Headers();\n\tfor (const headerSource of headerSources) {\n\t\tif (!headerSource) continue;\n\t\tif (headerSource instanceof Headers) for (const [key, value] of headerSource.entries()) mergedHeaders.set(key, value);\n\t\telse if (Array.isArray(headerSource)) for (const [key, value] of headerSource) mergedHeaders.set(key, value);\n\t\telse for (const [key, value] of Object.entries(headerSource)) mergedHeaders.set(key, value);\n\t}\n\treturn mergedHeaders;\n}\nvar OutputContext = class {\n\t/**\n\t* Creates an error response.\n\t*\n\t* Shortcut for `throw new FragnoApiError(...)`\n\t*/\n\terror = ({ message, code }, initOrStatus, headers) => {\n\t\tif (typeof initOrStatus === \"undefined\") return Response.json({\n\t\t\tmessage,\n\t\t\tcode\n\t\t}, {\n\t\t\tstatus: 500,\n\t\t\theaders\n\t\t});\n\t\tif (typeof initOrStatus === \"number\") return Response.json({\n\t\t\tmessage,\n\t\t\tcode\n\t\t}, {\n\t\t\tstatus: initOrStatus,\n\t\t\theaders\n\t\t});\n\t\tconst mergedHeaders = mergeHeaders(initOrStatus.headers, headers);\n\t\treturn Response.json({\n\t\t\tmessage,\n\t\t\tcode\n\t\t}, {\n\t\t\tstatus: initOrStatus.status,\n\t\t\theaders: mergedHeaders\n\t\t});\n\t};\n\tempty = (initOrStatus, headers) => {\n\t\tconst defaultHeaders = {};\n\t\tif (typeof initOrStatus === \"undefined\") {\n\t\t\tconst mergedHeaders$1 = mergeHeaders(defaultHeaders, headers);\n\t\t\treturn new Response(null, {\n\t\t\t\tstatus: 201,\n\t\t\t\theaders: mergedHeaders$1\n\t\t\t});\n\t\t}\n\t\tif (typeof initOrStatus === \"number\") {\n\t\t\tconst mergedHeaders$1 = mergeHeaders(defaultHeaders, headers);\n\t\t\treturn new Response(null, {\n\t\t\t\tstatus: initOrStatus,\n\t\t\t\theaders: mergedHeaders$1\n\t\t\t});\n\t\t}\n\t\tconst mergedHeaders = mergeHeaders(defaultHeaders, initOrStatus.headers, headers);\n\t\treturn new Response(null, {\n\t\t\tstatus: initOrStatus.status,\n\t\t\theaders: mergedHeaders\n\t\t});\n\t};\n\tjson = (object, initOrStatus, headers) => {\n\t\tif (typeof initOrStatus === \"undefined\") return Response.json(object, {\n\t\t\tstatus: 200,\n\t\t\theaders\n\t\t});\n\t\tif (typeof initOrStatus === \"number\") return Response.json(object, {\n\t\t\tstatus: initOrStatus,\n\t\t\theaders\n\t\t});\n\t\tconst mergedHeaders = mergeHeaders(initOrStatus.headers, headers);\n\t\treturn Response.json(object, {\n\t\t\tstatus: initOrStatus.status,\n\t\t\theaders: mergedHeaders\n\t\t});\n\t};\n\tjsonStream = (cb, { onError, headers } = {}) => {\n\t\tconst defaultHeaders = {\n\t\t\t\"content-type\": \"application/x-ndjson; charset=utf-8\",\n\t\t\t\"transfer-encoding\": \"chunked\",\n\t\t\t\"cache-control\": \"no-cache\"\n\t\t};\n\t\tconst { readable, writable } = new TransformStream();\n\t\tconst stream = new ResponseStream(writable, readable);\n\t\t(async () => {\n\t\t\ttry {\n\t\t\t\tawait cb(stream);\n\t\t\t} catch (e) {\n\t\t\t\tif (e === void 0) {} else if (e instanceof Error && onError) await onError(e, stream);\n\t\t\t\telse console.error(e);\n\t\t\t} finally {\n\t\t\t\tstream.close();\n\t\t\t}\n\t\t})();\n\t\treturn new Response(stream.responseReadable, {\n\t\t\tstatus: 200,\n\t\t\theaders: mergeHeaders(defaultHeaders, headers)\n\t\t});\n\t};\n};\nvar RequestOutputContext = class extends OutputContext {\n\t#outputSchema;\n\tconstructor(outputSchema) {\n\t\tsuper();\n\t\tthis.#outputSchema = outputSchema;\n\t}\n};\n\n//#endregion\nexport { OutputContext, RequestOutputContext };\n//# sourceMappingURL=request-output-context.js.map"],"mappings":";;;;;;;AAOA,SAAS,aAAa,GAAG,eAAe;CACvC,MAAM,gBAAgB,IAAI,SAAS;AACnC,MAAK,MAAM,gBAAgB,eAAe;AACzC,MAAI,CAAC,aAAc;AACnB,MAAI,wBAAwB,QAAS,MAAK,MAAM,CAAC,KAAK,UAAU,aAAa,SAAS,CAAE,eAAc,IAAI,KAAK,MAAM;WAC5G,MAAM,QAAQ,aAAa,CAAE,MAAK,MAAM,CAAC,KAAK,UAAU,aAAc,eAAc,IAAI,KAAK,MAAM;MACvG,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,aAAa,CAAE,eAAc,IAAI,KAAK,MAAM;;AAE5F,QAAO;;AAER,IAAI,gBAAgB,MAAM;;;;;;CAMzB,SAAS,EAAE,SAAS,QAAQ,cAAc,YAAY;AACrD,MAAI,OAAO,iBAAiB,YAAa,QAAO,SAAS,KAAK;GAC7D;GACA;GACA,EAAE;GACF,QAAQ;GACR;GACA,CAAC;AACF,MAAI,OAAO,iBAAiB,SAAU,QAAO,SAAS,KAAK;GAC1D;GACA;GACA,EAAE;GACF,QAAQ;GACR;GACA,CAAC;EACF,MAAM,gBAAgB,aAAa,aAAa,SAAS,QAAQ;AACjE,SAAO,SAAS,KAAK;GACpB;GACA;GACA,EAAE;GACF,QAAQ,aAAa;GACrB,SAAS;GACT,CAAC;;CAEH,SAAS,cAAc,YAAY;EAClC,MAAM,iBAAiB,EAAE;AACzB,MAAI,OAAO,iBAAiB,aAAa;GACxC,MAAM,kBAAkB,aAAa,gBAAgB,QAAQ;AAC7D,UAAO,IAAI,SAAS,MAAM;IACzB,QAAQ;IACR,SAAS;IACT,CAAC;;AAEH,MAAI,OAAO,iBAAiB,UAAU;GACrC,MAAM,kBAAkB,aAAa,gBAAgB,QAAQ;AAC7D,UAAO,IAAI,SAAS,MAAM;IACzB,QAAQ;IACR,SAAS;IACT,CAAC;;EAEH,MAAM,gBAAgB,aAAa,gBAAgB,aAAa,SAAS,QAAQ;AACjF,SAAO,IAAI,SAAS,MAAM;GACzB,QAAQ,aAAa;GACrB,SAAS;GACT,CAAC;;CAEH,QAAQ,QAAQ,cAAc,YAAY;AACzC,MAAI,OAAO,iBAAiB,YAAa,QAAO,SAAS,KAAK,QAAQ;GACrE,QAAQ;GACR;GACA,CAAC;AACF,MAAI,OAAO,iBAAiB,SAAU,QAAO,SAAS,KAAK,QAAQ;GAClE,QAAQ;GACR;GACA,CAAC;EACF,MAAM,gBAAgB,aAAa,aAAa,SAAS,QAAQ;AACjE,SAAO,SAAS,KAAK,QAAQ;GAC5B,QAAQ,aAAa;GACrB,SAAS;GACT,CAAC;;CAEH,cAAc,IAAI,EAAE,SAAS,YAAY,EAAE,KAAK;EAC/C,MAAM,iBAAiB;GACtB,gBAAgB;GAChB,qBAAqB;GACrB,iBAAiB;GACjB;EACD,MAAM,EAAE,UAAU,aAAa,IAAI,iBAAiB;EACpD,MAAM,SAAS,IAAI,eAAe,UAAU,SAAS;AACrD,GAAC,YAAY;AACZ,OAAI;AACH,UAAM,GAAG,OAAO;YACR,GAAG;AACX,QAAI,MAAM,KAAK,GAAG,YAAY,aAAa,SAAS,QAAS,OAAM,QAAQ,GAAG,OAAO;QAChF,SAAQ,MAAM,EAAE;aACZ;AACT,WAAO,OAAO;;MAEZ;AACJ,SAAO,IAAI,SAAS,OAAO,kBAAkB;GAC5C,QAAQ;GACR,SAAS,aAAa,gBAAgB,QAAQ;GAC9C,CAAC;;;AAGJ,IAAI,uBAAuB,cAAc,cAAc;CACtD;CACA,YAAY,cAAc;AACzB,SAAO;AACP,QAAKA,eAAgB"}
@@ -0,0 +1,17 @@
1
+ //#region ../fragno/dist/api/route.js
2
+ /**
3
+ * Helper to resolve route factories into routes
4
+ * @internal
5
+ */
6
+ function resolveRouteFactories(context, routesOrFactories) {
7
+ const routes = [];
8
+ for (const item of routesOrFactories) if (typeof item === "function") {
9
+ const factoryRoutes = item(context);
10
+ routes.push(...factoryRoutes);
11
+ } else routes.push(item);
12
+ return routes;
13
+ }
14
+
15
+ //#endregion
16
+ export { resolveRouteFactories };
17
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","names":[],"sources":["../../../../../../fragno/dist/api/route.js"],"sourcesContent":["//#region src/api/route.ts\n/**\n* Helper to resolve route factories into routes\n* @internal\n*/\nfunction resolveRouteFactories(context, routesOrFactories) {\n\tconst routes = [];\n\tfor (const item of routesOrFactories) if (typeof item === \"function\") {\n\t\tconst factoryRoutes = item(context);\n\t\troutes.push(...factoryRoutes);\n\t} else routes.push(item);\n\treturn routes;\n}\nfunction defineRoute(config) {\n\treturn config;\n}\nfunction defineRoutes(_definition) {\n\treturn { create: (fn) => {\n\t\treturn (ctx) => {\n\t\t\treturn fn({\n\t\t\t\t...ctx,\n\t\t\t\tdefineRoute\n\t\t\t});\n\t\t};\n\t} };\n}\n\n//#endregion\nexport { defineRoute, defineRoutes, resolveRouteFactories };\n//# sourceMappingURL=route.js.map"],"mappings":";;;;;AAKA,SAAS,sBAAsB,SAAS,mBAAmB;CAC1D,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,QAAQ,kBAAmB,KAAI,OAAO,SAAS,YAAY;EACrE,MAAM,gBAAgB,KAAK,QAAQ;AACnC,SAAO,KAAK,GAAG,cAAc;OACvB,QAAO,KAAK,KAAK;AACxB,QAAO"}
@@ -0,0 +1,10 @@
1
+ //#region ../fragno/dist/internal/symbols.js
2
+ /**
3
+ * Not actually a symbol, since we might be dealing with multiple instances of this code.
4
+ * @internal
5
+ */
6
+ const instantiatedFragmentFakeSymbol = "$fragno-instantiated-fragment";
7
+
8
+ //#endregion
9
+ export { instantiatedFragmentFakeSymbol };
10
+ //# sourceMappingURL=symbols.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbols.js","names":[],"sources":["../../../../../../fragno/dist/internal/symbols.js"],"sourcesContent":["//#region src/internal/symbols.ts\n/**\n* Not actually a symbol, since we might be dealing with multiple instances of this code.\n* @internal\n*/\nconst instantiatedFragmentFakeSymbol = \"$fragno-instantiated-fragment\";\n\n//#endregion\nexport { instantiatedFragmentFakeSymbol };\n//# sourceMappingURL=symbols.js.map"],"mappings":";;;;;AAKA,MAAM,iCAAiC"}