@jaypie/fabric 0.1.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.
Files changed (166) hide show
  1. package/README.md +677 -0
  2. package/dist/cjs/commander/FabricCommander.d.ts +94 -0
  3. package/dist/cjs/commander/createCommanderOptions.d.ts +25 -0
  4. package/dist/cjs/commander/fabricCommand.d.ts +43 -0
  5. package/dist/cjs/commander/index.cjs +1487 -0
  6. package/dist/cjs/commander/index.cjs.map +1 -0
  7. package/dist/cjs/commander/index.d.ts +6 -0
  8. package/dist/cjs/commander/parseCommanderOptions.d.ts +32 -0
  9. package/dist/cjs/commander/registerServiceCommand.d.ts +43 -0
  10. package/dist/cjs/commander/types.d.ts +107 -0
  11. package/dist/cjs/constants.d.ts +12 -0
  12. package/dist/cjs/convert-date.d.ts +47 -0
  13. package/dist/cjs/convert.d.ts +69 -0
  14. package/dist/cjs/data/FabricData.d.ts +42 -0
  15. package/dist/cjs/data/index.cjs +1575 -0
  16. package/dist/cjs/data/index.cjs.map +1 -0
  17. package/dist/cjs/data/index.d.ts +5 -0
  18. package/dist/cjs/data/services/archive.d.ts +8 -0
  19. package/dist/cjs/data/services/create.d.ts +8 -0
  20. package/dist/cjs/data/services/delete.d.ts +8 -0
  21. package/dist/cjs/data/services/execute.d.ts +8 -0
  22. package/dist/cjs/data/services/index.d.ts +7 -0
  23. package/dist/cjs/data/services/list.d.ts +8 -0
  24. package/dist/cjs/data/services/read.d.ts +8 -0
  25. package/dist/cjs/data/services/update.d.ts +8 -0
  26. package/dist/cjs/data/transforms.d.ts +80 -0
  27. package/dist/cjs/data/types.d.ts +190 -0
  28. package/dist/cjs/express/FabricRouter.d.ts +29 -0
  29. package/dist/cjs/express/fabricExpress.d.ts +16 -0
  30. package/dist/cjs/express/index.cjs +505 -0
  31. package/dist/cjs/express/index.cjs.map +1 -0
  32. package/dist/cjs/express/index.d.ts +3 -0
  33. package/dist/cjs/express/types.d.ts +51 -0
  34. package/dist/cjs/helpers/fallback.d.ts +21 -0
  35. package/dist/cjs/helpers/index.d.ts +3 -0
  36. package/dist/cjs/helpers/resolvedName.d.ts +24 -0
  37. package/dist/cjs/http/FabricHttpServer.d.ts +31 -0
  38. package/dist/cjs/http/authorization.d.ts +30 -0
  39. package/dist/cjs/http/cors.d.ts +40 -0
  40. package/dist/cjs/http/fabricHttp.d.ts +28 -0
  41. package/dist/cjs/http/httpTransform.d.ts +36 -0
  42. package/dist/cjs/http/index.cjs +1820 -0
  43. package/dist/cjs/http/index.cjs.map +1 -0
  44. package/dist/cjs/http/index.d.ts +10 -0
  45. package/dist/cjs/http/stream.d.ts +185 -0
  46. package/dist/cjs/http/types.d.ts +343 -0
  47. package/dist/cjs/index/index.d.ts +8 -0
  48. package/dist/cjs/index/keyBuilder.d.ts +81 -0
  49. package/dist/cjs/index/registry.d.ts +56 -0
  50. package/dist/cjs/index/types.d.ts +54 -0
  51. package/dist/cjs/index.cjs +1674 -0
  52. package/dist/cjs/index.cjs.map +1 -0
  53. package/dist/cjs/index.d.ts +18 -0
  54. package/dist/cjs/lambda/createLambdaService.d.ts +33 -0
  55. package/dist/cjs/lambda/fabricLambda.d.ts +36 -0
  56. package/dist/cjs/lambda/index.cjs +967 -0
  57. package/dist/cjs/lambda/index.cjs.map +1 -0
  58. package/dist/cjs/lambda/index.d.ts +2 -0
  59. package/dist/cjs/lambda/types.d.ts +68 -0
  60. package/dist/cjs/llm/createLlmTool.d.ts +40 -0
  61. package/dist/cjs/llm/fabricTool.d.ts +40 -0
  62. package/dist/cjs/llm/index.cjs +1107 -0
  63. package/dist/cjs/llm/index.cjs.map +1 -0
  64. package/dist/cjs/llm/index.d.ts +3 -0
  65. package/dist/cjs/llm/inputToJsonSchema.d.ts +32 -0
  66. package/dist/cjs/llm/types.d.ts +61 -0
  67. package/dist/cjs/mcp/fabricMcp.d.ts +38 -0
  68. package/dist/cjs/mcp/index.cjs +938 -0
  69. package/dist/cjs/mcp/index.cjs.map +1 -0
  70. package/dist/cjs/mcp/index.d.ts +2 -0
  71. package/dist/cjs/mcp/registerMcpTool.d.ts +38 -0
  72. package/dist/cjs/mcp/types.d.ts +60 -0
  73. package/dist/cjs/models/base.d.ts +209 -0
  74. package/dist/cjs/resolve-date.d.ts +47 -0
  75. package/dist/cjs/resolve.d.ts +69 -0
  76. package/dist/cjs/resolveService.d.ts +49 -0
  77. package/dist/cjs/service.d.ts +13 -0
  78. package/dist/cjs/status.d.ts +30 -0
  79. package/dist/cjs/types/elementaryTypes.d.ts +84 -0
  80. package/dist/cjs/types/fieldCategory.d.ts +20 -0
  81. package/dist/cjs/types/fieldDefinition.d.ts +46 -0
  82. package/dist/cjs/types/index.d.ts +4 -0
  83. package/dist/cjs/types.d.ts +56 -0
  84. package/dist/esm/commander/FabricCommander.d.ts +94 -0
  85. package/dist/esm/commander/createCommanderOptions.d.ts +25 -0
  86. package/dist/esm/commander/fabricCommand.d.ts +43 -0
  87. package/dist/esm/commander/index.d.ts +6 -0
  88. package/dist/esm/commander/index.js +1482 -0
  89. package/dist/esm/commander/index.js.map +1 -0
  90. package/dist/esm/commander/parseCommanderOptions.d.ts +32 -0
  91. package/dist/esm/commander/registerServiceCommand.d.ts +43 -0
  92. package/dist/esm/commander/types.d.ts +107 -0
  93. package/dist/esm/constants.d.ts +12 -0
  94. package/dist/esm/convert-date.d.ts +47 -0
  95. package/dist/esm/convert.d.ts +69 -0
  96. package/dist/esm/data/FabricData.d.ts +42 -0
  97. package/dist/esm/data/index.d.ts +5 -0
  98. package/dist/esm/data/index.js +1548 -0
  99. package/dist/esm/data/index.js.map +1 -0
  100. package/dist/esm/data/services/archive.d.ts +8 -0
  101. package/dist/esm/data/services/create.d.ts +8 -0
  102. package/dist/esm/data/services/delete.d.ts +8 -0
  103. package/dist/esm/data/services/execute.d.ts +8 -0
  104. package/dist/esm/data/services/index.d.ts +7 -0
  105. package/dist/esm/data/services/list.d.ts +8 -0
  106. package/dist/esm/data/services/read.d.ts +8 -0
  107. package/dist/esm/data/services/update.d.ts +8 -0
  108. package/dist/esm/data/transforms.d.ts +80 -0
  109. package/dist/esm/data/types.d.ts +190 -0
  110. package/dist/esm/express/FabricRouter.d.ts +29 -0
  111. package/dist/esm/express/fabricExpress.d.ts +16 -0
  112. package/dist/esm/express/index.d.ts +3 -0
  113. package/dist/esm/express/index.js +500 -0
  114. package/dist/esm/express/index.js.map +1 -0
  115. package/dist/esm/express/types.d.ts +51 -0
  116. package/dist/esm/helpers/fallback.d.ts +21 -0
  117. package/dist/esm/helpers/index.d.ts +3 -0
  118. package/dist/esm/helpers/resolvedName.d.ts +24 -0
  119. package/dist/esm/http/FabricHttpServer.d.ts +31 -0
  120. package/dist/esm/http/authorization.d.ts +30 -0
  121. package/dist/esm/http/cors.d.ts +40 -0
  122. package/dist/esm/http/fabricHttp.d.ts +28 -0
  123. package/dist/esm/http/httpTransform.d.ts +36 -0
  124. package/dist/esm/http/index.d.ts +10 -0
  125. package/dist/esm/http/index.js +1775 -0
  126. package/dist/esm/http/index.js.map +1 -0
  127. package/dist/esm/http/stream.d.ts +185 -0
  128. package/dist/esm/http/types.d.ts +343 -0
  129. package/dist/esm/index/index.d.ts +8 -0
  130. package/dist/esm/index/keyBuilder.d.ts +81 -0
  131. package/dist/esm/index/registry.d.ts +56 -0
  132. package/dist/esm/index/types.d.ts +54 -0
  133. package/dist/esm/index.d.ts +18 -0
  134. package/dist/esm/index.js +1606 -0
  135. package/dist/esm/index.js.map +1 -0
  136. package/dist/esm/lambda/createLambdaService.d.ts +33 -0
  137. package/dist/esm/lambda/fabricLambda.d.ts +36 -0
  138. package/dist/esm/lambda/index.d.ts +2 -0
  139. package/dist/esm/lambda/index.js +965 -0
  140. package/dist/esm/lambda/index.js.map +1 -0
  141. package/dist/esm/lambda/types.d.ts +68 -0
  142. package/dist/esm/llm/createLlmTool.d.ts +40 -0
  143. package/dist/esm/llm/fabricTool.d.ts +40 -0
  144. package/dist/esm/llm/index.d.ts +3 -0
  145. package/dist/esm/llm/index.js +1104 -0
  146. package/dist/esm/llm/index.js.map +1 -0
  147. package/dist/esm/llm/inputToJsonSchema.d.ts +32 -0
  148. package/dist/esm/llm/types.d.ts +61 -0
  149. package/dist/esm/mcp/fabricMcp.d.ts +38 -0
  150. package/dist/esm/mcp/index.d.ts +2 -0
  151. package/dist/esm/mcp/index.js +936 -0
  152. package/dist/esm/mcp/index.js.map +1 -0
  153. package/dist/esm/mcp/registerMcpTool.d.ts +38 -0
  154. package/dist/esm/mcp/types.d.ts +60 -0
  155. package/dist/esm/models/base.d.ts +209 -0
  156. package/dist/esm/resolve-date.d.ts +47 -0
  157. package/dist/esm/resolve.d.ts +69 -0
  158. package/dist/esm/resolveService.d.ts +49 -0
  159. package/dist/esm/service.d.ts +13 -0
  160. package/dist/esm/status.d.ts +30 -0
  161. package/dist/esm/types/elementaryTypes.d.ts +84 -0
  162. package/dist/esm/types/fieldCategory.d.ts +20 -0
  163. package/dist/esm/types/fieldDefinition.d.ts +46 -0
  164. package/dist/esm/types/index.d.ts +4 -0
  165. package/dist/esm/types.d.ts +56 -0
  166. package/package.json +122 -0
@@ -0,0 +1,29 @@
1
+ import type { FabricExpressRouter, FabricRouterConfig } from "./types.js";
2
+ /**
3
+ * Create an Express Router with multiple fabric services
4
+ *
5
+ * Provides a convenient way to mount multiple fabricHttp services:
6
+ * - Auto-registers each service at /${alias}
7
+ * - Supports custom path and method overrides per service
8
+ * - Optionally applies a prefix to all routes
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const router = FabricRouter({
13
+ * services: [
14
+ * userService,
15
+ * productService,
16
+ * { service: adminService, path: "/admin/:id", methods: ["POST"] },
17
+ * ],
18
+ * prefix: "/api",
19
+ * });
20
+ *
21
+ * app.use(router);
22
+ * // Routes: /api/users, /api/products, /api/admin/:id
23
+ * ```
24
+ */
25
+ export declare function FabricRouter(config: FabricRouterConfig): FabricExpressRouter;
26
+ /**
27
+ * Check if a value is a FabricExpressRouter
28
+ */
29
+ export declare function isFabricExpressRouter(value: unknown): value is FabricExpressRouter;
@@ -0,0 +1,16 @@
1
+ import type { FabricExpressConfig, FabricExpressMiddleware } from "./types.js";
2
+ /**
3
+ * Create Express middleware from a fabric HTTP service
4
+ *
5
+ * Wraps a FabricHttpService for use with Express:
6
+ * - Extracts HTTP context from Express request
7
+ * - Handles CORS preflight requests
8
+ * - Transforms input using the service's http function
9
+ * - Calls the service with transformed input
10
+ * - Sends response in JSON:API format
11
+ */
12
+ export declare function fabricExpress<TInput extends Record<string, unknown> = Record<string, unknown>, TOutput = unknown, TAuth = unknown>(config: FabricExpressConfig<TInput, TOutput, TAuth>): FabricExpressMiddleware;
13
+ /**
14
+ * Check if a value is a FabricExpressMiddleware
15
+ */
16
+ export declare function isFabricExpressMiddleware(value: unknown): value is FabricExpressMiddleware;
@@ -0,0 +1,3 @@
1
+ export { fabricExpress, isFabricExpressMiddleware } from "./fabricExpress.js";
2
+ export { FabricRouter, isFabricExpressRouter } from "./FabricRouter.js";
3
+ export type { FabricExpressConfig, FabricExpressMiddleware, FabricExpressRouter, FabricRouterConfig, FabricRouterServiceEntry, Request, Response, Router, } from "./types.js";
@@ -0,0 +1,500 @@
1
+ import '@jaypie/errors';
2
+ import { Router } from 'express';
3
+
4
+ /**
5
+ * Default HTTP transformation function
6
+ * Merges query parameters with body (body takes precedence)
7
+ */
8
+ const defaultHttpTransform = ({ body, query, }) => {
9
+ const queryObject = Object.fromEntries(query.entries());
10
+ const bodyObject = typeof body === "object" && body !== null ? body : {};
11
+ return {
12
+ ...queryObject,
13
+ ...bodyObject,
14
+ };
15
+ };
16
+ /**
17
+ * Parse query string into URLSearchParams
18
+ */
19
+ function parseQueryString(queryString) {
20
+ // Remove leading ? if present
21
+ const normalized = queryString.startsWith("?")
22
+ ? queryString.slice(1)
23
+ : queryString;
24
+ return new URLSearchParams(normalized);
25
+ }
26
+ /**
27
+ * Parse request body from string or return as-is if already parsed
28
+ */
29
+ function parseBody(body) {
30
+ if (typeof body === "string") {
31
+ try {
32
+ return JSON.parse(body);
33
+ }
34
+ catch {
35
+ // Return as-is if not valid JSON
36
+ return body;
37
+ }
38
+ }
39
+ return body;
40
+ }
41
+ /**
42
+ * Create HTTP context from raw request data
43
+ */
44
+ function createHttpContext(options) {
45
+ const { body = {}, headers = {}, method = "GET", path = "/", queryString = "", params = {}, } = options;
46
+ // Normalize headers to Headers object
47
+ const normalizedHeaders = headers instanceof Headers
48
+ ? headers
49
+ : new Headers(headers);
50
+ return {
51
+ body: parseBody(body),
52
+ headers: normalizedHeaders,
53
+ method: method.toUpperCase(),
54
+ path,
55
+ query: parseQueryString(queryString),
56
+ params,
57
+ };
58
+ }
59
+ /**
60
+ * Apply HTTP transformation to get service input
61
+ */
62
+ async function transformHttpToInput(context, transform = defaultHttpTransform) {
63
+ return transform(context);
64
+ }
65
+
66
+ /**
67
+ * Check if a value is a fabricService (has $fabric property)
68
+ */
69
+ function isFabricService(value) {
70
+ return (typeof value === "function" &&
71
+ "$fabric" in value &&
72
+ typeof value.$fabric === "string");
73
+ }
74
+ /**
75
+ * Check if a service is an HTTP service (has http, authorization, cors properties)
76
+ */
77
+ function isFabricHttpService(value) {
78
+ return (isFabricService(value) &&
79
+ "authorization" in value &&
80
+ "cors" in value &&
81
+ "http" in value &&
82
+ "stream" in value);
83
+ }
84
+
85
+ /**
86
+ * Default CORS configuration
87
+ */
88
+ const DEFAULT_CORS_CONFIG = {
89
+ origin: "*",
90
+ credentials: false,
91
+ headers: ["Content-Type", "Authorization"],
92
+ exposeHeaders: [],
93
+ maxAge: 86400, // 24 hours
94
+ };
95
+ /**
96
+ * Default allowed methods for CORS
97
+ */
98
+ const DEFAULT_CORS_METHODS = [
99
+ "GET",
100
+ "POST",
101
+ "DELETE",
102
+ "OPTIONS",
103
+ ];
104
+ /**
105
+ * Normalize CORS option to CorsConfig
106
+ * - true → default config
107
+ * - false → disabled (returns undefined)
108
+ * - CorsConfig → merged with defaults
109
+ */
110
+ function normalizeCorsConfig(option) {
111
+ // Undefined or true → use defaults
112
+ if (option === undefined || option === true) {
113
+ return { ...DEFAULT_CORS_CONFIG };
114
+ }
115
+ // False → disabled
116
+ if (option === false) {
117
+ return undefined;
118
+ }
119
+ // Merge with defaults
120
+ return {
121
+ ...DEFAULT_CORS_CONFIG,
122
+ ...option,
123
+ };
124
+ }
125
+ /**
126
+ * Get the allowed origin for a request
127
+ * @param config - CORS configuration
128
+ * @param requestOrigin - Origin header from request
129
+ * @returns The origin to allow, or undefined if not allowed
130
+ */
131
+ function getAllowedOrigin(config, requestOrigin) {
132
+ const { origin } = config;
133
+ // Wildcard allows all
134
+ if (origin === "*") {
135
+ return "*";
136
+ }
137
+ // No origin in request
138
+ if (!requestOrigin) {
139
+ return undefined;
140
+ }
141
+ // Array of allowed origins
142
+ if (Array.isArray(origin)) {
143
+ if (origin.includes(requestOrigin)) {
144
+ return requestOrigin;
145
+ }
146
+ return undefined;
147
+ }
148
+ // Single origin string
149
+ if (origin === requestOrigin) {
150
+ return requestOrigin;
151
+ }
152
+ return undefined;
153
+ }
154
+ /**
155
+ * Build CORS headers for a response
156
+ * @param config - CORS configuration
157
+ * @param requestOrigin - Origin header from request
158
+ * @param methods - Allowed HTTP methods
159
+ * @returns Object with CORS headers, or empty object if CORS is disabled
160
+ */
161
+ function buildCorsHeaders(config, requestOrigin, methods = DEFAULT_CORS_METHODS) {
162
+ if (!config) {
163
+ return {};
164
+ }
165
+ const headers = {};
166
+ // Access-Control-Allow-Origin
167
+ const allowedOrigin = getAllowedOrigin(config, requestOrigin);
168
+ if (allowedOrigin) {
169
+ headers["Access-Control-Allow-Origin"] = allowedOrigin;
170
+ }
171
+ // Access-Control-Allow-Methods
172
+ headers["Access-Control-Allow-Methods"] = methods.join(", ");
173
+ // Access-Control-Allow-Headers
174
+ if (config.headers && config.headers.length > 0) {
175
+ headers["Access-Control-Allow-Headers"] = config.headers.join(", ");
176
+ }
177
+ // Access-Control-Allow-Credentials
178
+ if (config.credentials) {
179
+ headers["Access-Control-Allow-Credentials"] = "true";
180
+ }
181
+ // Access-Control-Expose-Headers
182
+ if (config.exposeHeaders && config.exposeHeaders.length > 0) {
183
+ headers["Access-Control-Expose-Headers"] = config.exposeHeaders.join(", ");
184
+ }
185
+ // Access-Control-Max-Age
186
+ if (config.maxAge !== undefined) {
187
+ headers["Access-Control-Max-Age"] = String(config.maxAge);
188
+ }
189
+ return headers;
190
+ }
191
+ /**
192
+ * Check if request is a CORS preflight request
193
+ */
194
+ function isPreflightRequest(method, headers) {
195
+ return (method.toUpperCase() === "OPTIONS" &&
196
+ headers.has("access-control-request-method"));
197
+ }
198
+ /**
199
+ * Build preflight response headers
200
+ * Includes all CORS headers needed for preflight response
201
+ */
202
+ function buildPreflightHeaders(config, requestOrigin, requestMethod, requestHeaders, methods = DEFAULT_CORS_METHODS) {
203
+ if (!config) {
204
+ return {};
205
+ }
206
+ const headers = buildCorsHeaders(config, requestOrigin, methods);
207
+ // Include requested headers in response if not already covered
208
+ if (requestHeaders) {
209
+ const requestedHeaders = requestHeaders.split(",").map((h) => h.trim());
210
+ const allowedHeaders = config.headers || [];
211
+ const combinedHeaders = [
212
+ ...new Set([...allowedHeaders, ...requestedHeaders]),
213
+ ];
214
+ headers["Access-Control-Allow-Headers"] = combinedHeaders.join(", ");
215
+ }
216
+ return headers;
217
+ }
218
+
219
+ /**
220
+ * Default HTTP methods for fabric services
221
+ */
222
+ const DEFAULT_HTTP_METHODS = ["GET", "POST", "DELETE"];
223
+ // #endregion
224
+ // #region Streaming
225
+ /**
226
+ * HTTP stream event types for SSE/NDJSON streaming
227
+ */
228
+ var HttpStreamEventType;
229
+ (function (HttpStreamEventType) {
230
+ /** Stream complete */
231
+ HttpStreamEventType["Complete"] = "complete";
232
+ /** Final response data */
233
+ HttpStreamEventType["Data"] = "data";
234
+ /** Error event */
235
+ HttpStreamEventType["Error"] = "error";
236
+ /** Fabric progress message (from sendMessage) */
237
+ HttpStreamEventType["Message"] = "message";
238
+ /** Keep-alive signal (no content) */
239
+ HttpStreamEventType["Noop"] = "noop";
240
+ /** LLM text chunk */
241
+ HttpStreamEventType["Text"] = "text";
242
+ /** LLM tool call event */
243
+ HttpStreamEventType["ToolCall"] = "tool_call";
244
+ /** LLM tool result event */
245
+ HttpStreamEventType["ToolResult"] = "tool_result";
246
+ })(HttpStreamEventType || (HttpStreamEventType = {}));
247
+ // #endregion
248
+
249
+ /**
250
+ * Convert Express request headers to Headers object
251
+ */
252
+ function expressHeadersToHeaders(req) {
253
+ const headers = new Headers();
254
+ for (const [key, value] of Object.entries(req.headers)) {
255
+ if (value !== undefined) {
256
+ if (Array.isArray(value)) {
257
+ // Join array headers with comma
258
+ headers.set(key, value.join(", "));
259
+ }
260
+ else {
261
+ headers.set(key, value);
262
+ }
263
+ }
264
+ }
265
+ return headers;
266
+ }
267
+ /**
268
+ * Create HTTP context from Express request
269
+ */
270
+ function createHttpContextFromExpress(req, pathPattern) {
271
+ const headers = expressHeadersToHeaders(req);
272
+ // Build query string from Express query object
273
+ const queryString = new URLSearchParams(req.query).toString();
274
+ return createHttpContext({
275
+ body: req.body,
276
+ headers,
277
+ method: req.method,
278
+ path: req.path,
279
+ queryString,
280
+ params: req.params,
281
+ });
282
+ }
283
+ /**
284
+ * Send JSON:API success response
285
+ */
286
+ function sendDataResponse(res, data, statusCode = 200) {
287
+ if (data === null || data === undefined) {
288
+ res.status(204).send();
289
+ return;
290
+ }
291
+ res.status(statusCode).json({ data });
292
+ }
293
+ /**
294
+ * Send JSON:API error response
295
+ */
296
+ function sendErrorResponse(res, error) {
297
+ const status = error.status ?? 500;
298
+ const title = error.title ?? error.name ?? "Internal Server Error";
299
+ const detail = error.message;
300
+ res.status(status).json({
301
+ errors: [
302
+ {
303
+ detail,
304
+ status,
305
+ title,
306
+ },
307
+ ],
308
+ });
309
+ }
310
+ /**
311
+ * Apply CORS headers to response
312
+ */
313
+ function applyCorsHeaders(res, corsHeaders) {
314
+ for (const [key, value] of Object.entries(corsHeaders)) {
315
+ if (value !== undefined) {
316
+ res.set(key, value);
317
+ }
318
+ }
319
+ }
320
+ /**
321
+ * Create Express middleware from a fabric HTTP service
322
+ *
323
+ * Wraps a FabricHttpService for use with Express:
324
+ * - Extracts HTTP context from Express request
325
+ * - Handles CORS preflight requests
326
+ * - Transforms input using the service's http function
327
+ * - Calls the service with transformed input
328
+ * - Sends response in JSON:API format
329
+ */
330
+ function fabricExpress(config) {
331
+ const { service, methods = DEFAULT_HTTP_METHODS } = config;
332
+ // Validate service
333
+ if (!isFabricHttpService(service)) {
334
+ throw new Error("fabricExpress requires a FabricHttpService. Use fabricHttp() to create one.");
335
+ }
336
+ // Determine path from config or service alias
337
+ const path = config.path ?? `/${service.alias ?? ""}`;
338
+ // Normalize CORS configuration
339
+ const corsConfig = normalizeCorsConfig(service.cors);
340
+ // Create the middleware function
341
+ const middleware = async (req, res, next) => {
342
+ try {
343
+ // Create HTTP context from Express request
344
+ const httpContext = createHttpContextFromExpress(req, path);
345
+ // Get request origin for CORS
346
+ const requestOrigin = req.get("origin") ?? null;
347
+ // Handle CORS preflight
348
+ if (isPreflightRequest(req.method, httpContext.headers)) {
349
+ const preflightHeaders = buildPreflightHeaders(corsConfig, requestOrigin, req.get("access-control-request-method") ?? null, req.get("access-control-request-headers") ?? null, methods);
350
+ applyCorsHeaders(res, preflightHeaders);
351
+ res.status(204).send();
352
+ return;
353
+ }
354
+ // Apply CORS headers to response
355
+ const corsHeaders = buildCorsHeaders(corsConfig, requestOrigin, methods);
356
+ applyCorsHeaders(res, corsHeaders);
357
+ // Check if method is allowed
358
+ if (!methods.includes(req.method.toUpperCase())) {
359
+ res.status(405).json({
360
+ errors: [
361
+ {
362
+ detail: `Method ${req.method} not allowed`,
363
+ status: 405,
364
+ title: "Method Not Allowed",
365
+ },
366
+ ],
367
+ });
368
+ return;
369
+ }
370
+ // Transform HTTP context to service input
371
+ const input = await transformHttpToInput(httpContext, service.http);
372
+ // Create service context with HTTP info
373
+ const serviceContext = {
374
+ http: httpContext,
375
+ };
376
+ // Call the service
377
+ const result = await service(input, serviceContext);
378
+ // Send response
379
+ sendDataResponse(res, result);
380
+ }
381
+ catch (error) {
382
+ // Send error response
383
+ sendErrorResponse(res, error);
384
+ }
385
+ };
386
+ // Attach metadata to middleware
387
+ const expressMiddleware = middleware;
388
+ expressMiddleware.service = service;
389
+ expressMiddleware.path = path;
390
+ expressMiddleware.methods = methods;
391
+ return expressMiddleware;
392
+ }
393
+ /**
394
+ * Check if a value is a FabricExpressMiddleware
395
+ */
396
+ function isFabricExpressMiddleware(value) {
397
+ return (typeof value === "function" &&
398
+ "service" in value &&
399
+ "path" in value &&
400
+ "methods" in value);
401
+ }
402
+
403
+ /**
404
+ * Check if entry is a FabricExpressConfig (has service property)
405
+ */
406
+ function isServiceConfig(entry) {
407
+ return (typeof entry === "object" &&
408
+ entry !== null &&
409
+ "service" in entry &&
410
+ isFabricHttpService(entry.service));
411
+ }
412
+ /**
413
+ * Create an Express Router with multiple fabric services
414
+ *
415
+ * Provides a convenient way to mount multiple fabricHttp services:
416
+ * - Auto-registers each service at /${alias}
417
+ * - Supports custom path and method overrides per service
418
+ * - Optionally applies a prefix to all routes
419
+ *
420
+ * @example
421
+ * ```typescript
422
+ * const router = FabricRouter({
423
+ * services: [
424
+ * userService,
425
+ * productService,
426
+ * { service: adminService, path: "/admin/:id", methods: ["POST"] },
427
+ * ],
428
+ * prefix: "/api",
429
+ * });
430
+ *
431
+ * app.use(router);
432
+ * // Routes: /api/users, /api/products, /api/admin/:id
433
+ * ```
434
+ */
435
+ function FabricRouter(config) {
436
+ const { services, prefix } = config;
437
+ // Create base router
438
+ const router = Router();
439
+ // Track registered services
440
+ const registeredServices = [];
441
+ // Register each service
442
+ for (const entry of services) {
443
+ let service;
444
+ let path;
445
+ let methods;
446
+ if (isServiceConfig(entry)) {
447
+ // Config object with service + overrides
448
+ service = entry.service;
449
+ path = entry.path;
450
+ methods = entry.methods;
451
+ }
452
+ else if (isFabricHttpService(entry)) {
453
+ // Direct service
454
+ service = entry;
455
+ }
456
+ else {
457
+ throw new Error("FabricRouter: Each service entry must be a FabricHttpService or { service: FabricHttpService }");
458
+ }
459
+ // Create middleware
460
+ const middleware = fabricExpress({
461
+ methods: methods ?? DEFAULT_HTTP_METHODS,
462
+ path,
463
+ service,
464
+ });
465
+ // Determine mount path
466
+ const mountPath = middleware.path;
467
+ // Register all methods for this path
468
+ for (const method of middleware.methods) {
469
+ const lowerMethod = method.toLowerCase();
470
+ // Express router methods
471
+ if (lowerMethod === "options") {
472
+ // OPTIONS is handled by the middleware for preflight
473
+ router.options(mountPath, middleware);
474
+ }
475
+ else {
476
+ router[lowerMethod](mountPath, middleware);
477
+ }
478
+ }
479
+ // Also handle OPTIONS for CORS preflight if not already included
480
+ if (!middleware.methods.includes("OPTIONS")) {
481
+ router.options(mountPath, middleware);
482
+ }
483
+ registeredServices.push(service);
484
+ }
485
+ // Attach metadata
486
+ router.services = registeredServices;
487
+ router.prefix = prefix;
488
+ return router;
489
+ }
490
+ /**
491
+ * Check if a value is a FabricExpressRouter
492
+ */
493
+ function isFabricExpressRouter(value) {
494
+ return (typeof value === "function" &&
495
+ "services" in value &&
496
+ Array.isArray(value.services));
497
+ }
498
+
499
+ export { FabricRouter, fabricExpress, isFabricExpressMiddleware, isFabricExpressRouter };
500
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../../src/http/httpTransform.ts","../../../../../src/http/fabricHttp.ts","../../../../../src/http/cors.ts","../../../../../src/http/types.ts","../../../../../src/express/fabricExpress.ts","../../../../../src/express/FabricRouter.ts"],"sourcesContent":["import type { HttpContext, HttpTransformFunction } from \"./types.js\";\n\n/**\n * Default HTTP transformation function\n * Merges query parameters with body (body takes precedence)\n */\nexport const defaultHttpTransform: HttpTransformFunction = ({\n body,\n query,\n}) => {\n const queryObject = Object.fromEntries(query.entries());\n const bodyObject = typeof body === \"object\" && body !== null ? body : {};\n\n return {\n ...queryObject,\n ...bodyObject,\n } as Record<string, unknown>;\n};\n\n/**\n * Parse query string into URLSearchParams\n */\nexport function parseQueryString(queryString: string): URLSearchParams {\n // Remove leading ? if present\n const normalized = queryString.startsWith(\"?\")\n ? queryString.slice(1)\n : queryString;\n return new URLSearchParams(normalized);\n}\n\n/**\n * Parse path parameters from a URL path using a route pattern\n * @param path - The actual URL path (e.g., \"/users/123\")\n * @param pattern - The route pattern (e.g., \"/users/:id\")\n * @returns Object with extracted parameters\n */\nexport function parsePathParams(\n path: string,\n pattern: string,\n): Record<string, string> {\n const params: Record<string, string> = {};\n\n const pathParts = path.split(\"/\").filter(Boolean);\n const patternParts = pattern.split(\"/\").filter(Boolean);\n\n for (let i = 0; i < patternParts.length; i++) {\n const patternPart = patternParts[i];\n const pathPart = pathParts[i];\n\n if (patternPart.startsWith(\":\")) {\n // Extract parameter name (remove : prefix and ? suffix for optional params)\n const paramName = patternPart.slice(1).replace(\"?\", \"\");\n if (pathPart !== undefined) {\n params[paramName] = pathPart;\n }\n }\n }\n\n return params;\n}\n\n/**\n * Parse request body from string or return as-is if already parsed\n */\nexport function parseBody(body: unknown): unknown {\n if (typeof body === \"string\") {\n try {\n return JSON.parse(body);\n } catch {\n // Return as-is if not valid JSON\n return body;\n }\n }\n return body;\n}\n\n/**\n * Create HTTP context from raw request data\n */\nexport function createHttpContext(options: {\n body?: unknown;\n headers?: Headers | Record<string, string>;\n method?: string;\n path?: string;\n queryString?: string;\n params?: Record<string, string>;\n}): HttpContext {\n const {\n body = {},\n headers = {},\n method = \"GET\",\n path = \"/\",\n queryString = \"\",\n params = {},\n } = options;\n\n // Normalize headers to Headers object\n const normalizedHeaders =\n headers instanceof Headers\n ? headers\n : new Headers(headers as Record<string, string>);\n\n return {\n body: parseBody(body),\n headers: normalizedHeaders,\n method: method.toUpperCase(),\n path,\n query: parseQueryString(queryString),\n params,\n };\n}\n\n/**\n * Apply HTTP transformation to get service input\n */\nexport async function transformHttpToInput<TInput = Record<string, unknown>>(\n context: HttpContext,\n transform: HttpTransformFunction<TInput> = defaultHttpTransform as HttpTransformFunction<TInput>,\n): Promise<TInput> {\n return transform(context);\n}\n","import { fabricService } from \"../service.js\";\nimport type { Service, ServiceConfig, ServiceContext } from \"../types.js\";\n\nimport { validateAuthorization } from \"./authorization.js\";\nimport { defaultHttpTransform } from \"./httpTransform.js\";\nimport type {\n FabricHttpConfig,\n FabricHttpService,\n HttpContext,\n HttpTransformFunction,\n} from \"./types.js\";\n\n/**\n * Check if a value is a fabricService (has $fabric property)\n */\nfunction isFabricService<TInput extends Record<string, unknown>, TOutput>(\n value: unknown,\n): value is Service<TInput, TOutput> {\n return (\n typeof value === \"function\" &&\n \"$fabric\" in value &&\n typeof (value as Service<TInput, TOutput>).$fabric === \"string\"\n );\n}\n\n/**\n * Extended service context with auth information\n */\nexport interface HttpServiceContext<TAuth = unknown> extends ServiceContext {\n /** Authorization result (returned from authorization function) */\n auth?: TAuth;\n /** HTTP context for advanced use cases */\n http?: HttpContext;\n}\n\n/**\n * Create an HTTP-aware fabric service\n *\n * Extends fabricService with:\n * - HTTP context transformation (body, headers, method, path, query, params)\n * - Authorization handling (token extraction from Authorization header)\n * - CORS configuration (enabled by default)\n *\n * Accepts either:\n * - Inline service definition (with `service` function)\n * - Pre-built `fabricService` instance (via `service` property)\n */\nexport function fabricHttp<\n TInput extends Record<string, unknown> = Record<string, unknown>,\n TOutput = unknown,\n TAuth = unknown,\n>(\n config: FabricHttpConfig<TInput, TOutput, TAuth>,\n): FabricHttpService<TInput, TOutput, TAuth> {\n const {\n authorization = false,\n cors = true,\n http = defaultHttpTransform as HttpTransformFunction<TInput>,\n service: serviceConfig,\n stream = false,\n ...baseConfig\n } = config;\n\n // Resolve the underlying service\n let underlyingService: Service<TInput, TOutput>;\n\n if (isFabricService<TInput, TOutput>(serviceConfig)) {\n // Pre-built fabricService - merge configs\n underlyingService = serviceConfig;\n\n // Merge base config properties from the pre-built service\n if (\n baseConfig.alias === undefined &&\n underlyingService.alias !== undefined\n ) {\n baseConfig.alias = underlyingService.alias;\n }\n if (\n baseConfig.description === undefined &&\n underlyingService.description !== undefined\n ) {\n baseConfig.description = underlyingService.description;\n }\n if (\n baseConfig.input === undefined &&\n underlyingService.input !== undefined\n ) {\n baseConfig.input = underlyingService.input;\n }\n } else {\n // Inline service definition or plain function\n const serviceFunction = serviceConfig as ServiceConfig<\n TInput,\n TOutput\n >[\"service\"];\n underlyingService = fabricService<TInput, TOutput>({\n ...baseConfig,\n service: serviceFunction,\n } as ServiceConfig<TInput, TOutput>);\n }\n\n // Create the HTTP handler that processes HTTP context\n const httpHandler = async (\n input?: Partial<TInput> | string,\n context?: HttpServiceContext<TAuth>,\n ): Promise<TOutput> => {\n // If context has HTTP info, process authorization\n // (HTTP context is added by the adapter layer like fabricExpress)\n if (context?.http && authorization !== false) {\n const authResult = await validateAuthorization<TAuth>(\n context.http.headers,\n authorization,\n );\n // Add auth result to context\n (context as HttpServiceContext<TAuth>).auth = authResult;\n }\n\n // Call the underlying service\n return underlyingService(input, context);\n };\n\n // Create the HTTP service with all properties\n const httpService = httpHandler as FabricHttpService<TInput, TOutput, TAuth>;\n\n // Copy properties from config (which may have been merged with underlying service)\n httpService.$fabric = underlyingService.$fabric;\n\n // Use baseConfig values (which include overrides) or fall back to underlying service\n const resolvedAlias = baseConfig.alias ?? underlyingService.alias;\n const resolvedDescription =\n baseConfig.description ?? underlyingService.description;\n const resolvedInput = baseConfig.input ?? underlyingService.input;\n\n if (resolvedAlias !== undefined) {\n httpService.alias = resolvedAlias;\n }\n if (resolvedDescription !== undefined) {\n httpService.description = resolvedDescription;\n }\n if (resolvedInput !== undefined) {\n httpService.input = resolvedInput;\n }\n if (underlyingService.service !== undefined) {\n httpService.service = underlyingService.service;\n }\n\n // Add HTTP-specific properties\n httpService.authorization = authorization;\n httpService.cors = cors;\n httpService.http = http;\n httpService.stream = stream;\n\n return httpService;\n}\n\n/**\n * Check if a service is an HTTP service (has http, authorization, cors properties)\n */\nexport function isFabricHttpService<\n TInput extends Record<string, unknown>,\n TOutput,\n TAuth,\n>(value: unknown): value is FabricHttpService<TInput, TOutput, TAuth> {\n return (\n isFabricService<TInput, TOutput>(value) &&\n \"authorization\" in value &&\n \"cors\" in value &&\n \"http\" in value &&\n \"stream\" in value\n );\n}\n","import type {\n CorsConfig,\n CorsHeaders,\n CorsOption,\n HttpMethod,\n} from \"./types.js\";\n\n/**\n * Default CORS configuration\n */\nexport const DEFAULT_CORS_CONFIG: CorsConfig = {\n origin: \"*\",\n credentials: false,\n headers: [\"Content-Type\", \"Authorization\"],\n exposeHeaders: [],\n maxAge: 86400, // 24 hours\n};\n\n/**\n * Default allowed methods for CORS\n */\nexport const DEFAULT_CORS_METHODS: HttpMethod[] = [\n \"GET\",\n \"POST\",\n \"DELETE\",\n \"OPTIONS\",\n];\n\n/**\n * Normalize CORS option to CorsConfig\n * - true → default config\n * - false → disabled (returns undefined)\n * - CorsConfig → merged with defaults\n */\nexport function normalizeCorsConfig(\n option: CorsOption | undefined,\n): CorsConfig | undefined {\n // Undefined or true → use defaults\n if (option === undefined || option === true) {\n return { ...DEFAULT_CORS_CONFIG };\n }\n\n // False → disabled\n if (option === false) {\n return undefined;\n }\n\n // Merge with defaults\n return {\n ...DEFAULT_CORS_CONFIG,\n ...option,\n };\n}\n\n/**\n * Get the allowed origin for a request\n * @param config - CORS configuration\n * @param requestOrigin - Origin header from request\n * @returns The origin to allow, or undefined if not allowed\n */\nexport function getAllowedOrigin(\n config: CorsConfig,\n requestOrigin: string | null,\n): string | undefined {\n const { origin } = config;\n\n // Wildcard allows all\n if (origin === \"*\") {\n return \"*\";\n }\n\n // No origin in request\n if (!requestOrigin) {\n return undefined;\n }\n\n // Array of allowed origins\n if (Array.isArray(origin)) {\n if (origin.includes(requestOrigin)) {\n return requestOrigin;\n }\n return undefined;\n }\n\n // Single origin string\n if (origin === requestOrigin) {\n return requestOrigin;\n }\n\n return undefined;\n}\n\n/**\n * Build CORS headers for a response\n * @param config - CORS configuration\n * @param requestOrigin - Origin header from request\n * @param methods - Allowed HTTP methods\n * @returns Object with CORS headers, or empty object if CORS is disabled\n */\nexport function buildCorsHeaders(\n config: CorsConfig | undefined,\n requestOrigin: string | null,\n methods: HttpMethod[] = DEFAULT_CORS_METHODS,\n): CorsHeaders {\n if (!config) {\n return {};\n }\n\n const headers: CorsHeaders = {};\n\n // Access-Control-Allow-Origin\n const allowedOrigin = getAllowedOrigin(config, requestOrigin);\n if (allowedOrigin) {\n headers[\"Access-Control-Allow-Origin\"] = allowedOrigin;\n }\n\n // Access-Control-Allow-Methods\n headers[\"Access-Control-Allow-Methods\"] = methods.join(\", \");\n\n // Access-Control-Allow-Headers\n if (config.headers && config.headers.length > 0) {\n headers[\"Access-Control-Allow-Headers\"] = config.headers.join(\", \");\n }\n\n // Access-Control-Allow-Credentials\n if (config.credentials) {\n headers[\"Access-Control-Allow-Credentials\"] = \"true\";\n }\n\n // Access-Control-Expose-Headers\n if (config.exposeHeaders && config.exposeHeaders.length > 0) {\n headers[\"Access-Control-Expose-Headers\"] = config.exposeHeaders.join(\", \");\n }\n\n // Access-Control-Max-Age\n if (config.maxAge !== undefined) {\n headers[\"Access-Control-Max-Age\"] = String(config.maxAge);\n }\n\n return headers;\n}\n\n/**\n * Check if request is a CORS preflight request\n */\nexport function isPreflightRequest(method: string, headers: Headers): boolean {\n return (\n method.toUpperCase() === \"OPTIONS\" &&\n headers.has(\"access-control-request-method\")\n );\n}\n\n/**\n * Build preflight response headers\n * Includes all CORS headers needed for preflight response\n */\nexport function buildPreflightHeaders(\n config: CorsConfig | undefined,\n requestOrigin: string | null,\n requestMethod: string | null,\n requestHeaders: string | null,\n methods: HttpMethod[] = DEFAULT_CORS_METHODS,\n): CorsHeaders {\n if (!config) {\n return {};\n }\n\n const headers = buildCorsHeaders(config, requestOrigin, methods);\n\n // Include requested headers in response if not already covered\n if (requestHeaders) {\n const requestedHeaders = requestHeaders.split(\",\").map((h) => h.trim());\n const allowedHeaders = config.headers || [];\n const combinedHeaders = [\n ...new Set([...allowedHeaders, ...requestedHeaders]),\n ];\n headers[\"Access-Control-Allow-Headers\"] = combinedHeaders.join(\", \");\n }\n\n return headers;\n}\n","import type { Service, ServiceConfig } from \"../types.js\";\n\n// #region HTTP Context\n\n/**\n * HTTP request context passed to the `http` transformation function\n */\nexport interface HttpContext {\n /** Parsed request body */\n body: unknown;\n /** Request headers */\n headers: Headers;\n /** HTTP method (GET, POST, PUT, DELETE, PATCH) */\n method: string;\n /** URL path */\n path: string;\n /** Query string parameters */\n query: URLSearchParams;\n /** Path parameters extracted from route pattern (e.g., :id) */\n params: Record<string, string>;\n}\n\n/**\n * Function that transforms HTTP context to fabric service input\n */\nexport type HttpTransformFunction<TInput = Record<string, unknown>> = (\n context: HttpContext,\n) => TInput | Promise<TInput>;\n\n// #endregion\n\n// #region Authorization\n\n/**\n * Authorization function that validates a token and returns auth context\n * Token is extracted from Authorization header with Bearer prefix removed\n */\nexport type AuthorizationFunction<TAuth = unknown> = (\n token: string,\n) => TAuth | Promise<TAuth>;\n\n/**\n * Authorization configuration - either a function or false for public endpoints\n */\nexport type AuthorizationConfig<TAuth = unknown> =\n | AuthorizationFunction<TAuth>\n | false;\n\n// #endregion\n\n// #region CORS\n\n/**\n * CORS configuration options\n */\nexport interface CorsConfig {\n /** Allowed origins - \"*\" for all, or array of specific origins */\n origin?: string | string[];\n /** Allow credentials (Access-Control-Allow-Credentials) */\n credentials?: boolean;\n /** Additional allowed headers (Access-Control-Allow-Headers) */\n headers?: string[];\n /** Headers to expose to the client (Access-Control-Expose-Headers) */\n exposeHeaders?: string[];\n /** Preflight cache duration in seconds (Access-Control-Max-Age) */\n maxAge?: number;\n}\n\n/**\n * CORS configuration - object config, true for defaults, or false to disable\n */\nexport type CorsOption = CorsConfig | boolean;\n\n/**\n * Resolved CORS headers to send in response\n */\nexport interface CorsHeaders {\n \"Access-Control-Allow-Origin\"?: string;\n \"Access-Control-Allow-Methods\"?: string;\n \"Access-Control-Allow-Headers\"?: string;\n \"Access-Control-Allow-Credentials\"?: string;\n \"Access-Control-Expose-Headers\"?: string;\n \"Access-Control-Max-Age\"?: string;\n}\n\n// #endregion\n\n// #region Response Format\n\n/**\n * JSON:API-style success response envelope\n */\nexport interface DataResponse<T = unknown> {\n data: T;\n}\n\n/**\n * JSON:API-style error object\n */\nexport interface ErrorObject {\n status: number;\n title: string;\n detail?: string;\n}\n\n/**\n * JSON:API-style error response envelope\n */\nexport interface ErrorResponse {\n errors: ErrorObject[];\n}\n\n// #endregion\n\n// #region fabricHttp Config\n\n/**\n * HTTP service configuration - extends base ServiceConfig with HTTP-specific options\n */\nexport interface FabricHttpConfig<\n TInput extends Record<string, unknown> = Record<string, unknown>,\n TOutput = unknown,\n TAuth = unknown,\n> extends Omit<ServiceConfig<TInput, TOutput>, \"service\"> {\n /** Pre-built fabricService or inline service function */\n service?:\n | Service<TInput, TOutput>\n | ServiceConfig<TInput, TOutput>[\"service\"];\n\n /** Transform HTTP context to service input (defaults to body + query merge) */\n http?: HttpTransformFunction<TInput>;\n\n /** Authorization function or false for public endpoints */\n authorization?: AuthorizationConfig<TAuth>;\n\n /** CORS configuration (enabled by default) */\n cors?: CorsOption;\n\n /** Streaming configuration (disabled by default) */\n stream?: StreamOption;\n}\n\n/**\n * HTTP service - fabricService with HTTP-specific metadata\n */\nexport interface FabricHttpService<\n TInput extends Record<string, unknown> = Record<string, unknown>,\n TOutput = unknown,\n TAuth = unknown,\n> extends Service<TInput, TOutput> {\n /** HTTP transformation function */\n http: HttpTransformFunction<TInput>;\n /** Authorization configuration */\n authorization: AuthorizationConfig<TAuth>;\n /** CORS configuration */\n cors: CorsOption;\n /** Streaming configuration */\n stream: StreamOption;\n}\n\n// #endregion\n\n// #region HTTP Methods\n\n/**\n * Supported HTTP methods\n */\nexport type HttpMethod =\n | \"GET\"\n | \"POST\"\n | \"PUT\"\n | \"DELETE\"\n | \"PATCH\"\n | \"OPTIONS\";\n\n/**\n * Default HTTP methods for fabric services\n */\nexport const DEFAULT_HTTP_METHODS: HttpMethod[] = [\"GET\", \"POST\", \"DELETE\"];\n\n// #endregion\n\n// #region Streaming\n\n/**\n * HTTP stream event types for SSE/NDJSON streaming\n */\nexport enum HttpStreamEventType {\n /** Stream complete */\n Complete = \"complete\",\n /** Final response data */\n Data = \"data\",\n /** Error event */\n Error = \"error\",\n /** Fabric progress message (from sendMessage) */\n Message = \"message\",\n /** Keep-alive signal (no content) */\n Noop = \"noop\",\n /** LLM text chunk */\n Text = \"text\",\n /** LLM tool call event */\n ToolCall = \"tool_call\",\n /** LLM tool result event */\n ToolResult = \"tool_result\",\n}\n\n/**\n * Base stream event structure\n */\nexport interface HttpStreamEventBase {\n stream: HttpStreamEventType;\n}\n\n/**\n * Message event - progress updates from sendMessage\n */\nexport interface HttpStreamEventMessage extends HttpStreamEventBase {\n stream: HttpStreamEventType.Message;\n content: string;\n level?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\n/**\n * Text event - LLM text chunk\n */\nexport interface HttpStreamEventText extends HttpStreamEventBase {\n stream: HttpStreamEventType.Text;\n content: string;\n}\n\n/**\n * Tool call event - LLM requesting tool execution\n */\nexport interface HttpStreamEventToolCall extends HttpStreamEventBase {\n stream: HttpStreamEventType.ToolCall;\n toolCall: {\n id: string;\n name: string;\n arguments: string;\n };\n}\n\n/**\n * Tool result event - result from tool execution\n */\nexport interface HttpStreamEventToolResult extends HttpStreamEventBase {\n stream: HttpStreamEventType.ToolResult;\n toolResult: {\n id: string;\n name: string;\n result: unknown;\n };\n}\n\n/**\n * Data event - final response data\n */\nexport interface HttpStreamEventData<T = unknown> extends HttpStreamEventBase {\n stream: HttpStreamEventType.Data;\n data: T;\n}\n\n/**\n * Error event\n */\nexport interface HttpStreamEventError extends HttpStreamEventBase {\n stream: HttpStreamEventType.Error;\n error: {\n status: number | string;\n title: string;\n detail?: string;\n };\n}\n\n/**\n * Complete event - stream complete\n */\nexport interface HttpStreamEventComplete extends HttpStreamEventBase {\n stream: HttpStreamEventType.Complete;\n}\n\n/**\n * Noop event - keep-alive signal\n */\nexport interface HttpStreamEventNoop extends HttpStreamEventBase {\n stream: HttpStreamEventType.Noop;\n}\n\n/**\n * Union of all stream event types\n */\nexport type HttpStreamEvent =\n | HttpStreamEventComplete\n | HttpStreamEventData\n | HttpStreamEventError\n | HttpStreamEventMessage\n | HttpStreamEventNoop\n | HttpStreamEventText\n | HttpStreamEventToolCall\n | HttpStreamEventToolResult;\n\n/**\n * Stream configuration options (internal)\n */\nexport interface StreamConfig {\n /** Output format - NDJSON (default) or SSE */\n format?: \"ndjson\" | \"sse\";\n /** Keep-alive heartbeat interval in ms (default: 15000) */\n heartbeat?: number;\n /** Include tool calls/results in stream (default: true) */\n includeTools?: boolean;\n}\n\n/**\n * Stream option - true to enable streaming, false to disable\n */\nexport type StreamOption = boolean;\n\n/**\n * Streaming service function that yields events\n */\nexport type StreamingServiceFunction<\n TInput extends Record<string, unknown> = Record<string, unknown>,\n> = (\n input: TInput,\n context: unknown,\n) => AsyncIterable<HttpStreamEvent> | Promise<AsyncIterable<HttpStreamEvent>>;\n\n// #endregion\n\n// #region FabricHttpServer Config\n\n/**\n * Route entry for FabricHttpServer - service with path and method configuration\n */\nexport interface FabricHttpServerRoute<\n TInput extends Record<string, unknown> = Record<string, unknown>,\n TOutput = unknown,\n TAuth = unknown,\n> {\n /** The FabricHttpService to handle requests */\n service: FabricHttpService<TInput, TOutput, TAuth>;\n /** Route path pattern (defaults to /${alias}) */\n path?: string;\n /** Allowed HTTP methods (defaults to DEFAULT_HTTP_METHODS) */\n methods?: HttpMethod[];\n}\n\n/**\n * Service entry - either a FabricHttpService or a route config\n */\nexport type FabricHttpServerServiceEntry =\n | FabricHttpService\n | FabricHttpServerRoute;\n\n/**\n * Configuration for FabricHttpServer\n */\nexport interface FabricHttpServerConfig {\n /** Array of services or route configs to register */\n services: FabricHttpServerServiceEntry[];\n /** Server-level authorization (applied to all services unless overridden) */\n authorization?: AuthorizationConfig;\n /** Server-level CORS config (applied to all services unless overridden) */\n cors?: CorsOption;\n /** Path prefix for all routes (e.g., \"/api\") */\n prefix?: string;\n}\n\n/**\n * API Gateway v1 (REST API) event format\n */\nexport interface ApiGatewayV1Event {\n body: string | null;\n headers: Record<string, string>;\n httpMethod: string;\n path: string;\n pathParameters?: Record<string, string> | null;\n queryStringParameters?: Record<string, string> | null;\n requestContext?: {\n requestId?: string;\n };\n}\n\n/**\n * API Gateway v2 (HTTP API) event format\n */\nexport interface ApiGatewayV2Event {\n body?: string;\n headers: Record<string, string>;\n rawPath: string;\n rawQueryString?: string;\n requestContext: {\n http: {\n method: string;\n path: string;\n };\n requestId?: string;\n };\n pathParameters?: Record<string, string>;\n queryStringParameters?: Record<string, string>;\n}\n\n/**\n * Union of API Gateway event types\n */\nexport type ApiGatewayEvent = ApiGatewayV1Event | ApiGatewayV2Event;\n\n/**\n * API Gateway response format (compatible with v1 and v2)\n */\nexport interface ApiGatewayResponse {\n statusCode: number;\n headers: Record<string, string>;\n body: string;\n}\n\n/**\n * Registered route with resolved path and methods\n */\nexport interface RegisteredRoute {\n /** Compiled path pattern */\n path: string;\n /** Path segments for matching */\n segments: string[];\n /** Allowed methods */\n methods: HttpMethod[];\n /** The service to handle requests */\n service: FabricHttpService;\n}\n\n/**\n * Match result from route matching\n */\nexport interface RouteMatch {\n /** The matched route */\n route: RegisteredRoute;\n /** Extracted path parameters */\n params: Record<string, string>;\n}\n\n/**\n * FabricHttpServer handler function\n */\nexport type FabricHttpServerHandler = (\n event: ApiGatewayEvent,\n) => Promise<ApiGatewayResponse>;\n\n/**\n * FabricHttpServer with metadata\n */\nexport interface FabricHttpServer extends FabricHttpServerHandler {\n /** Registered services */\n services: FabricHttpService[];\n /** Route prefix */\n prefix?: string;\n /** Registered routes */\n routes: RegisteredRoute[];\n}\n\n// #endregion\n","import type { NextFunction, Request, Response } from \"express\";\n\nimport { isFabricHttpService } from \"../http/fabricHttp.js\";\nimport type { HttpServiceContext } from \"../http/fabricHttp.js\";\nimport {\n buildCorsHeaders,\n buildPreflightHeaders,\n isPreflightRequest,\n normalizeCorsConfig,\n} from \"../http/cors.js\";\nimport {\n createHttpContext,\n transformHttpToInput,\n} from \"../http/httpTransform.js\";\nimport type { CorsHeaders, HttpContext, HttpMethod } from \"../http/types.js\";\nimport { DEFAULT_HTTP_METHODS } from \"../http/types.js\";\n\nimport type { FabricExpressConfig, FabricExpressMiddleware } from \"./types.js\";\n\n/**\n * Convert Express request headers to Headers object\n */\nfunction expressHeadersToHeaders(req: Request): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value !== undefined) {\n if (Array.isArray(value)) {\n // Join array headers with comma\n headers.set(key, value.join(\", \"));\n } else {\n headers.set(key, value);\n }\n }\n }\n return headers;\n}\n\n/**\n * Create HTTP context from Express request\n */\nfunction createHttpContextFromExpress(\n req: Request,\n pathPattern?: string,\n): HttpContext {\n const headers = expressHeadersToHeaders(req);\n\n // Build query string from Express query object\n const queryString = new URLSearchParams(\n req.query as Record<string, string>,\n ).toString();\n\n return createHttpContext({\n body: req.body,\n headers,\n method: req.method,\n path: req.path,\n queryString,\n params: req.params as Record<string, string>,\n });\n}\n\n/**\n * Send JSON:API success response\n */\nfunction sendDataResponse<T>(res: Response, data: T, statusCode = 200): void {\n if (data === null || data === undefined) {\n res.status(204).send();\n return;\n }\n\n res.status(statusCode).json({ data });\n}\n\n/**\n * Send JSON:API error response\n */\nfunction sendErrorResponse(\n res: Response,\n error: Error & { status?: number; title?: string },\n): void {\n const status = error.status ?? 500;\n const title = error.title ?? error.name ?? \"Internal Server Error\";\n const detail = error.message;\n\n res.status(status).json({\n errors: [\n {\n detail,\n status,\n title,\n },\n ],\n });\n}\n\n/**\n * Apply CORS headers to response\n */\nfunction applyCorsHeaders(res: Response, corsHeaders: CorsHeaders): void {\n for (const [key, value] of Object.entries(corsHeaders)) {\n if (value !== undefined) {\n res.set(key, value);\n }\n }\n}\n\n/**\n * Create Express middleware from a fabric HTTP service\n *\n * Wraps a FabricHttpService for use with Express:\n * - Extracts HTTP context from Express request\n * - Handles CORS preflight requests\n * - Transforms input using the service's http function\n * - Calls the service with transformed input\n * - Sends response in JSON:API format\n */\nexport function fabricExpress<\n TInput extends Record<string, unknown> = Record<string, unknown>,\n TOutput = unknown,\n TAuth = unknown,\n>(\n config: FabricExpressConfig<TInput, TOutput, TAuth>,\n): FabricExpressMiddleware {\n const { service, methods = DEFAULT_HTTP_METHODS } = config;\n\n // Validate service\n if (!isFabricHttpService(service)) {\n throw new Error(\n \"fabricExpress requires a FabricHttpService. Use fabricHttp() to create one.\",\n );\n }\n\n // Determine path from config or service alias\n const path = config.path ?? `/${service.alias ?? \"\"}`;\n\n // Normalize CORS configuration\n const corsConfig = normalizeCorsConfig(service.cors);\n\n // Create the middleware function\n const middleware = async (\n req: Request,\n res: Response,\n next: NextFunction,\n ): Promise<void> => {\n try {\n // Create HTTP context from Express request\n const httpContext = createHttpContextFromExpress(req, path);\n\n // Get request origin for CORS\n const requestOrigin = req.get(\"origin\") ?? null;\n\n // Handle CORS preflight\n if (isPreflightRequest(req.method, httpContext.headers)) {\n const preflightHeaders = buildPreflightHeaders(\n corsConfig,\n requestOrigin,\n req.get(\"access-control-request-method\") ?? null,\n req.get(\"access-control-request-headers\") ?? null,\n methods,\n );\n applyCorsHeaders(res, preflightHeaders);\n res.status(204).send();\n return;\n }\n\n // Apply CORS headers to response\n const corsHeaders = buildCorsHeaders(corsConfig, requestOrigin, methods);\n applyCorsHeaders(res, corsHeaders);\n\n // Check if method is allowed\n if (!methods.includes(req.method.toUpperCase() as HttpMethod)) {\n res.status(405).json({\n errors: [\n {\n detail: `Method ${req.method} not allowed`,\n status: 405,\n title: \"Method Not Allowed\",\n },\n ],\n });\n return;\n }\n\n // Transform HTTP context to service input\n const input = await transformHttpToInput<TInput>(\n httpContext,\n service.http,\n );\n\n // Create service context with HTTP info\n const serviceContext: HttpServiceContext<TAuth> = {\n http: httpContext,\n };\n\n // Call the service\n const result = await service(input, serviceContext);\n\n // Send response\n sendDataResponse(res, result);\n } catch (error) {\n // Send error response\n sendErrorResponse(res, error as Error);\n }\n };\n\n // Attach metadata to middleware\n const expressMiddleware = middleware as FabricExpressMiddleware;\n expressMiddleware.service = service;\n expressMiddleware.path = path;\n expressMiddleware.methods = methods;\n\n return expressMiddleware;\n}\n\n/**\n * Check if a value is a FabricExpressMiddleware\n */\nexport function isFabricExpressMiddleware(\n value: unknown,\n): value is FabricExpressMiddleware {\n return (\n typeof value === \"function\" &&\n \"service\" in value &&\n \"path\" in value &&\n \"methods\" in value\n );\n}\n","import { Router } from \"express\";\n\nimport { isFabricHttpService } from \"../http/fabricHttp.js\";\nimport type { FabricHttpService, HttpMethod } from \"../http/types.js\";\nimport { DEFAULT_HTTP_METHODS } from \"../http/types.js\";\n\nimport { fabricExpress } from \"./fabricExpress.js\";\nimport type {\n FabricExpressConfig,\n FabricExpressRouter,\n FabricRouterConfig,\n FabricRouterServiceEntry,\n} from \"./types.js\";\n\n/**\n * Check if entry is a FabricExpressConfig (has service property)\n */\nfunction isServiceConfig(\n entry: FabricRouterServiceEntry,\n): entry is FabricExpressConfig {\n return (\n typeof entry === \"object\" &&\n entry !== null &&\n \"service\" in entry &&\n isFabricHttpService(entry.service)\n );\n}\n\n/**\n * Create an Express Router with multiple fabric services\n *\n * Provides a convenient way to mount multiple fabricHttp services:\n * - Auto-registers each service at /${alias}\n * - Supports custom path and method overrides per service\n * - Optionally applies a prefix to all routes\n *\n * @example\n * ```typescript\n * const router = FabricRouter({\n * services: [\n * userService,\n * productService,\n * { service: adminService, path: \"/admin/:id\", methods: [\"POST\"] },\n * ],\n * prefix: \"/api\",\n * });\n *\n * app.use(router);\n * // Routes: /api/users, /api/products, /api/admin/:id\n * ```\n */\nexport function FabricRouter(config: FabricRouterConfig): FabricExpressRouter {\n const { services, prefix } = config;\n\n // Create base router\n const router = Router() as FabricExpressRouter;\n\n // Track registered services\n const registeredServices: FabricHttpService[] = [];\n\n // Register each service\n for (const entry of services) {\n let service: FabricHttpService;\n let path: string | undefined;\n let methods: HttpMethod[] | undefined;\n\n if (isServiceConfig(entry)) {\n // Config object with service + overrides\n service = entry.service;\n path = entry.path;\n methods = entry.methods;\n } else if (isFabricHttpService(entry)) {\n // Direct service\n service = entry;\n } else {\n throw new Error(\n \"FabricRouter: Each service entry must be a FabricHttpService or { service: FabricHttpService }\",\n );\n }\n\n // Create middleware\n const middleware = fabricExpress({\n methods: methods ?? DEFAULT_HTTP_METHODS,\n path,\n service,\n });\n\n // Determine mount path\n const mountPath = middleware.path;\n\n // Register all methods for this path\n for (const method of middleware.methods) {\n const lowerMethod = method.toLowerCase() as\n | \"get\"\n | \"post\"\n | \"put\"\n | \"delete\"\n | \"patch\"\n | \"options\";\n\n // Express router methods\n if (lowerMethod === \"options\") {\n // OPTIONS is handled by the middleware for preflight\n router.options(mountPath, middleware);\n } else {\n router[lowerMethod](mountPath, middleware);\n }\n }\n\n // Also handle OPTIONS for CORS preflight if not already included\n if (!middleware.methods.includes(\"OPTIONS\")) {\n router.options(mountPath, middleware);\n }\n\n registeredServices.push(service);\n }\n\n // Attach metadata\n router.services = registeredServices;\n router.prefix = prefix;\n\n return router;\n}\n\n/**\n * Check if a value is a FabricExpressRouter\n */\nexport function isFabricExpressRouter(\n value: unknown,\n): value is FabricExpressRouter {\n return (\n typeof value === \"function\" &&\n \"services\" in value &&\n Array.isArray((value as FabricExpressRouter).services)\n );\n}\n"],"names":[],"mappings":"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"}