@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.
- package/README.md +677 -0
- package/dist/cjs/commander/FabricCommander.d.ts +94 -0
- package/dist/cjs/commander/createCommanderOptions.d.ts +25 -0
- package/dist/cjs/commander/fabricCommand.d.ts +43 -0
- package/dist/cjs/commander/index.cjs +1487 -0
- package/dist/cjs/commander/index.cjs.map +1 -0
- package/dist/cjs/commander/index.d.ts +6 -0
- package/dist/cjs/commander/parseCommanderOptions.d.ts +32 -0
- package/dist/cjs/commander/registerServiceCommand.d.ts +43 -0
- package/dist/cjs/commander/types.d.ts +107 -0
- package/dist/cjs/constants.d.ts +12 -0
- package/dist/cjs/convert-date.d.ts +47 -0
- package/dist/cjs/convert.d.ts +69 -0
- package/dist/cjs/data/FabricData.d.ts +42 -0
- package/dist/cjs/data/index.cjs +1575 -0
- package/dist/cjs/data/index.cjs.map +1 -0
- package/dist/cjs/data/index.d.ts +5 -0
- package/dist/cjs/data/services/archive.d.ts +8 -0
- package/dist/cjs/data/services/create.d.ts +8 -0
- package/dist/cjs/data/services/delete.d.ts +8 -0
- package/dist/cjs/data/services/execute.d.ts +8 -0
- package/dist/cjs/data/services/index.d.ts +7 -0
- package/dist/cjs/data/services/list.d.ts +8 -0
- package/dist/cjs/data/services/read.d.ts +8 -0
- package/dist/cjs/data/services/update.d.ts +8 -0
- package/dist/cjs/data/transforms.d.ts +80 -0
- package/dist/cjs/data/types.d.ts +190 -0
- package/dist/cjs/express/FabricRouter.d.ts +29 -0
- package/dist/cjs/express/fabricExpress.d.ts +16 -0
- package/dist/cjs/express/index.cjs +505 -0
- package/dist/cjs/express/index.cjs.map +1 -0
- package/dist/cjs/express/index.d.ts +3 -0
- package/dist/cjs/express/types.d.ts +51 -0
- package/dist/cjs/helpers/fallback.d.ts +21 -0
- package/dist/cjs/helpers/index.d.ts +3 -0
- package/dist/cjs/helpers/resolvedName.d.ts +24 -0
- package/dist/cjs/http/FabricHttpServer.d.ts +31 -0
- package/dist/cjs/http/authorization.d.ts +30 -0
- package/dist/cjs/http/cors.d.ts +40 -0
- package/dist/cjs/http/fabricHttp.d.ts +28 -0
- package/dist/cjs/http/httpTransform.d.ts +36 -0
- package/dist/cjs/http/index.cjs +1820 -0
- package/dist/cjs/http/index.cjs.map +1 -0
- package/dist/cjs/http/index.d.ts +10 -0
- package/dist/cjs/http/stream.d.ts +185 -0
- package/dist/cjs/http/types.d.ts +343 -0
- package/dist/cjs/index/index.d.ts +8 -0
- package/dist/cjs/index/keyBuilder.d.ts +81 -0
- package/dist/cjs/index/registry.d.ts +56 -0
- package/dist/cjs/index/types.d.ts +54 -0
- package/dist/cjs/index.cjs +1674 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.ts +18 -0
- package/dist/cjs/lambda/createLambdaService.d.ts +33 -0
- package/dist/cjs/lambda/fabricLambda.d.ts +36 -0
- package/dist/cjs/lambda/index.cjs +967 -0
- package/dist/cjs/lambda/index.cjs.map +1 -0
- package/dist/cjs/lambda/index.d.ts +2 -0
- package/dist/cjs/lambda/types.d.ts +68 -0
- package/dist/cjs/llm/createLlmTool.d.ts +40 -0
- package/dist/cjs/llm/fabricTool.d.ts +40 -0
- package/dist/cjs/llm/index.cjs +1107 -0
- package/dist/cjs/llm/index.cjs.map +1 -0
- package/dist/cjs/llm/index.d.ts +3 -0
- package/dist/cjs/llm/inputToJsonSchema.d.ts +32 -0
- package/dist/cjs/llm/types.d.ts +61 -0
- package/dist/cjs/mcp/fabricMcp.d.ts +38 -0
- package/dist/cjs/mcp/index.cjs +938 -0
- package/dist/cjs/mcp/index.cjs.map +1 -0
- package/dist/cjs/mcp/index.d.ts +2 -0
- package/dist/cjs/mcp/registerMcpTool.d.ts +38 -0
- package/dist/cjs/mcp/types.d.ts +60 -0
- package/dist/cjs/models/base.d.ts +209 -0
- package/dist/cjs/resolve-date.d.ts +47 -0
- package/dist/cjs/resolve.d.ts +69 -0
- package/dist/cjs/resolveService.d.ts +49 -0
- package/dist/cjs/service.d.ts +13 -0
- package/dist/cjs/status.d.ts +30 -0
- package/dist/cjs/types/elementaryTypes.d.ts +84 -0
- package/dist/cjs/types/fieldCategory.d.ts +20 -0
- package/dist/cjs/types/fieldDefinition.d.ts +46 -0
- package/dist/cjs/types/index.d.ts +4 -0
- package/dist/cjs/types.d.ts +56 -0
- package/dist/esm/commander/FabricCommander.d.ts +94 -0
- package/dist/esm/commander/createCommanderOptions.d.ts +25 -0
- package/dist/esm/commander/fabricCommand.d.ts +43 -0
- package/dist/esm/commander/index.d.ts +6 -0
- package/dist/esm/commander/index.js +1482 -0
- package/dist/esm/commander/index.js.map +1 -0
- package/dist/esm/commander/parseCommanderOptions.d.ts +32 -0
- package/dist/esm/commander/registerServiceCommand.d.ts +43 -0
- package/dist/esm/commander/types.d.ts +107 -0
- package/dist/esm/constants.d.ts +12 -0
- package/dist/esm/convert-date.d.ts +47 -0
- package/dist/esm/convert.d.ts +69 -0
- package/dist/esm/data/FabricData.d.ts +42 -0
- package/dist/esm/data/index.d.ts +5 -0
- package/dist/esm/data/index.js +1548 -0
- package/dist/esm/data/index.js.map +1 -0
- package/dist/esm/data/services/archive.d.ts +8 -0
- package/dist/esm/data/services/create.d.ts +8 -0
- package/dist/esm/data/services/delete.d.ts +8 -0
- package/dist/esm/data/services/execute.d.ts +8 -0
- package/dist/esm/data/services/index.d.ts +7 -0
- package/dist/esm/data/services/list.d.ts +8 -0
- package/dist/esm/data/services/read.d.ts +8 -0
- package/dist/esm/data/services/update.d.ts +8 -0
- package/dist/esm/data/transforms.d.ts +80 -0
- package/dist/esm/data/types.d.ts +190 -0
- package/dist/esm/express/FabricRouter.d.ts +29 -0
- package/dist/esm/express/fabricExpress.d.ts +16 -0
- package/dist/esm/express/index.d.ts +3 -0
- package/dist/esm/express/index.js +500 -0
- package/dist/esm/express/index.js.map +1 -0
- package/dist/esm/express/types.d.ts +51 -0
- package/dist/esm/helpers/fallback.d.ts +21 -0
- package/dist/esm/helpers/index.d.ts +3 -0
- package/dist/esm/helpers/resolvedName.d.ts +24 -0
- package/dist/esm/http/FabricHttpServer.d.ts +31 -0
- package/dist/esm/http/authorization.d.ts +30 -0
- package/dist/esm/http/cors.d.ts +40 -0
- package/dist/esm/http/fabricHttp.d.ts +28 -0
- package/dist/esm/http/httpTransform.d.ts +36 -0
- package/dist/esm/http/index.d.ts +10 -0
- package/dist/esm/http/index.js +1775 -0
- package/dist/esm/http/index.js.map +1 -0
- package/dist/esm/http/stream.d.ts +185 -0
- package/dist/esm/http/types.d.ts +343 -0
- package/dist/esm/index/index.d.ts +8 -0
- package/dist/esm/index/keyBuilder.d.ts +81 -0
- package/dist/esm/index/registry.d.ts +56 -0
- package/dist/esm/index/types.d.ts +54 -0
- package/dist/esm/index.d.ts +18 -0
- package/dist/esm/index.js +1606 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lambda/createLambdaService.d.ts +33 -0
- package/dist/esm/lambda/fabricLambda.d.ts +36 -0
- package/dist/esm/lambda/index.d.ts +2 -0
- package/dist/esm/lambda/index.js +965 -0
- package/dist/esm/lambda/index.js.map +1 -0
- package/dist/esm/lambda/types.d.ts +68 -0
- package/dist/esm/llm/createLlmTool.d.ts +40 -0
- package/dist/esm/llm/fabricTool.d.ts +40 -0
- package/dist/esm/llm/index.d.ts +3 -0
- package/dist/esm/llm/index.js +1104 -0
- package/dist/esm/llm/index.js.map +1 -0
- package/dist/esm/llm/inputToJsonSchema.d.ts +32 -0
- package/dist/esm/llm/types.d.ts +61 -0
- package/dist/esm/mcp/fabricMcp.d.ts +38 -0
- package/dist/esm/mcp/index.d.ts +2 -0
- package/dist/esm/mcp/index.js +936 -0
- package/dist/esm/mcp/index.js.map +1 -0
- package/dist/esm/mcp/registerMcpTool.d.ts +38 -0
- package/dist/esm/mcp/types.d.ts +60 -0
- package/dist/esm/models/base.d.ts +209 -0
- package/dist/esm/resolve-date.d.ts +47 -0
- package/dist/esm/resolve.d.ts +69 -0
- package/dist/esm/resolveService.d.ts +49 -0
- package/dist/esm/service.d.ts +13 -0
- package/dist/esm/status.d.ts +30 -0
- package/dist/esm/types/elementaryTypes.d.ts +84 -0
- package/dist/esm/types/fieldCategory.d.ts +20 -0
- package/dist/esm/types/fieldDefinition.d.ts +46 -0
- package/dist/esm/types/index.d.ts +4 -0
- package/dist/esm/types.d.ts +56 -0
- 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,505 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('@jaypie/errors');
|
|
4
|
+
var express = require('express');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default HTTP transformation function
|
|
8
|
+
* Merges query parameters with body (body takes precedence)
|
|
9
|
+
*/
|
|
10
|
+
const defaultHttpTransform = ({ body, query, }) => {
|
|
11
|
+
const queryObject = Object.fromEntries(query.entries());
|
|
12
|
+
const bodyObject = typeof body === "object" && body !== null ? body : {};
|
|
13
|
+
return {
|
|
14
|
+
...queryObject,
|
|
15
|
+
...bodyObject,
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Parse query string into URLSearchParams
|
|
20
|
+
*/
|
|
21
|
+
function parseQueryString(queryString) {
|
|
22
|
+
// Remove leading ? if present
|
|
23
|
+
const normalized = queryString.startsWith("?")
|
|
24
|
+
? queryString.slice(1)
|
|
25
|
+
: queryString;
|
|
26
|
+
return new URLSearchParams(normalized);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse request body from string or return as-is if already parsed
|
|
30
|
+
*/
|
|
31
|
+
function parseBody(body) {
|
|
32
|
+
if (typeof body === "string") {
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(body);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Return as-is if not valid JSON
|
|
38
|
+
return body;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return body;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create HTTP context from raw request data
|
|
45
|
+
*/
|
|
46
|
+
function createHttpContext(options) {
|
|
47
|
+
const { body = {}, headers = {}, method = "GET", path = "/", queryString = "", params = {}, } = options;
|
|
48
|
+
// Normalize headers to Headers object
|
|
49
|
+
const normalizedHeaders = headers instanceof Headers
|
|
50
|
+
? headers
|
|
51
|
+
: new Headers(headers);
|
|
52
|
+
return {
|
|
53
|
+
body: parseBody(body),
|
|
54
|
+
headers: normalizedHeaders,
|
|
55
|
+
method: method.toUpperCase(),
|
|
56
|
+
path,
|
|
57
|
+
query: parseQueryString(queryString),
|
|
58
|
+
params,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Apply HTTP transformation to get service input
|
|
63
|
+
*/
|
|
64
|
+
async function transformHttpToInput(context, transform = defaultHttpTransform) {
|
|
65
|
+
return transform(context);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if a value is a fabricService (has $fabric property)
|
|
70
|
+
*/
|
|
71
|
+
function isFabricService(value) {
|
|
72
|
+
return (typeof value === "function" &&
|
|
73
|
+
"$fabric" in value &&
|
|
74
|
+
typeof value.$fabric === "string");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if a service is an HTTP service (has http, authorization, cors properties)
|
|
78
|
+
*/
|
|
79
|
+
function isFabricHttpService(value) {
|
|
80
|
+
return (isFabricService(value) &&
|
|
81
|
+
"authorization" in value &&
|
|
82
|
+
"cors" in value &&
|
|
83
|
+
"http" in value &&
|
|
84
|
+
"stream" in value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Default CORS configuration
|
|
89
|
+
*/
|
|
90
|
+
const DEFAULT_CORS_CONFIG = {
|
|
91
|
+
origin: "*",
|
|
92
|
+
credentials: false,
|
|
93
|
+
headers: ["Content-Type", "Authorization"],
|
|
94
|
+
exposeHeaders: [],
|
|
95
|
+
maxAge: 86400, // 24 hours
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Default allowed methods for CORS
|
|
99
|
+
*/
|
|
100
|
+
const DEFAULT_CORS_METHODS = [
|
|
101
|
+
"GET",
|
|
102
|
+
"POST",
|
|
103
|
+
"DELETE",
|
|
104
|
+
"OPTIONS",
|
|
105
|
+
];
|
|
106
|
+
/**
|
|
107
|
+
* Normalize CORS option to CorsConfig
|
|
108
|
+
* - true → default config
|
|
109
|
+
* - false → disabled (returns undefined)
|
|
110
|
+
* - CorsConfig → merged with defaults
|
|
111
|
+
*/
|
|
112
|
+
function normalizeCorsConfig(option) {
|
|
113
|
+
// Undefined or true → use defaults
|
|
114
|
+
if (option === undefined || option === true) {
|
|
115
|
+
return { ...DEFAULT_CORS_CONFIG };
|
|
116
|
+
}
|
|
117
|
+
// False → disabled
|
|
118
|
+
if (option === false) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
// Merge with defaults
|
|
122
|
+
return {
|
|
123
|
+
...DEFAULT_CORS_CONFIG,
|
|
124
|
+
...option,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the allowed origin for a request
|
|
129
|
+
* @param config - CORS configuration
|
|
130
|
+
* @param requestOrigin - Origin header from request
|
|
131
|
+
* @returns The origin to allow, or undefined if not allowed
|
|
132
|
+
*/
|
|
133
|
+
function getAllowedOrigin(config, requestOrigin) {
|
|
134
|
+
const { origin } = config;
|
|
135
|
+
// Wildcard allows all
|
|
136
|
+
if (origin === "*") {
|
|
137
|
+
return "*";
|
|
138
|
+
}
|
|
139
|
+
// No origin in request
|
|
140
|
+
if (!requestOrigin) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
// Array of allowed origins
|
|
144
|
+
if (Array.isArray(origin)) {
|
|
145
|
+
if (origin.includes(requestOrigin)) {
|
|
146
|
+
return requestOrigin;
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
// Single origin string
|
|
151
|
+
if (origin === requestOrigin) {
|
|
152
|
+
return requestOrigin;
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Build CORS headers for a response
|
|
158
|
+
* @param config - CORS configuration
|
|
159
|
+
* @param requestOrigin - Origin header from request
|
|
160
|
+
* @param methods - Allowed HTTP methods
|
|
161
|
+
* @returns Object with CORS headers, or empty object if CORS is disabled
|
|
162
|
+
*/
|
|
163
|
+
function buildCorsHeaders(config, requestOrigin, methods = DEFAULT_CORS_METHODS) {
|
|
164
|
+
if (!config) {
|
|
165
|
+
return {};
|
|
166
|
+
}
|
|
167
|
+
const headers = {};
|
|
168
|
+
// Access-Control-Allow-Origin
|
|
169
|
+
const allowedOrigin = getAllowedOrigin(config, requestOrigin);
|
|
170
|
+
if (allowedOrigin) {
|
|
171
|
+
headers["Access-Control-Allow-Origin"] = allowedOrigin;
|
|
172
|
+
}
|
|
173
|
+
// Access-Control-Allow-Methods
|
|
174
|
+
headers["Access-Control-Allow-Methods"] = methods.join(", ");
|
|
175
|
+
// Access-Control-Allow-Headers
|
|
176
|
+
if (config.headers && config.headers.length > 0) {
|
|
177
|
+
headers["Access-Control-Allow-Headers"] = config.headers.join(", ");
|
|
178
|
+
}
|
|
179
|
+
// Access-Control-Allow-Credentials
|
|
180
|
+
if (config.credentials) {
|
|
181
|
+
headers["Access-Control-Allow-Credentials"] = "true";
|
|
182
|
+
}
|
|
183
|
+
// Access-Control-Expose-Headers
|
|
184
|
+
if (config.exposeHeaders && config.exposeHeaders.length > 0) {
|
|
185
|
+
headers["Access-Control-Expose-Headers"] = config.exposeHeaders.join(", ");
|
|
186
|
+
}
|
|
187
|
+
// Access-Control-Max-Age
|
|
188
|
+
if (config.maxAge !== undefined) {
|
|
189
|
+
headers["Access-Control-Max-Age"] = String(config.maxAge);
|
|
190
|
+
}
|
|
191
|
+
return headers;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Check if request is a CORS preflight request
|
|
195
|
+
*/
|
|
196
|
+
function isPreflightRequest(method, headers) {
|
|
197
|
+
return (method.toUpperCase() === "OPTIONS" &&
|
|
198
|
+
headers.has("access-control-request-method"));
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Build preflight response headers
|
|
202
|
+
* Includes all CORS headers needed for preflight response
|
|
203
|
+
*/
|
|
204
|
+
function buildPreflightHeaders(config, requestOrigin, requestMethod, requestHeaders, methods = DEFAULT_CORS_METHODS) {
|
|
205
|
+
if (!config) {
|
|
206
|
+
return {};
|
|
207
|
+
}
|
|
208
|
+
const headers = buildCorsHeaders(config, requestOrigin, methods);
|
|
209
|
+
// Include requested headers in response if not already covered
|
|
210
|
+
if (requestHeaders) {
|
|
211
|
+
const requestedHeaders = requestHeaders.split(",").map((h) => h.trim());
|
|
212
|
+
const allowedHeaders = config.headers || [];
|
|
213
|
+
const combinedHeaders = [
|
|
214
|
+
...new Set([...allowedHeaders, ...requestedHeaders]),
|
|
215
|
+
];
|
|
216
|
+
headers["Access-Control-Allow-Headers"] = combinedHeaders.join(", ");
|
|
217
|
+
}
|
|
218
|
+
return headers;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Default HTTP methods for fabric services
|
|
223
|
+
*/
|
|
224
|
+
const DEFAULT_HTTP_METHODS = ["GET", "POST", "DELETE"];
|
|
225
|
+
// #endregion
|
|
226
|
+
// #region Streaming
|
|
227
|
+
/**
|
|
228
|
+
* HTTP stream event types for SSE/NDJSON streaming
|
|
229
|
+
*/
|
|
230
|
+
var HttpStreamEventType;
|
|
231
|
+
(function (HttpStreamEventType) {
|
|
232
|
+
/** Stream complete */
|
|
233
|
+
HttpStreamEventType["Complete"] = "complete";
|
|
234
|
+
/** Final response data */
|
|
235
|
+
HttpStreamEventType["Data"] = "data";
|
|
236
|
+
/** Error event */
|
|
237
|
+
HttpStreamEventType["Error"] = "error";
|
|
238
|
+
/** Fabric progress message (from sendMessage) */
|
|
239
|
+
HttpStreamEventType["Message"] = "message";
|
|
240
|
+
/** Keep-alive signal (no content) */
|
|
241
|
+
HttpStreamEventType["Noop"] = "noop";
|
|
242
|
+
/** LLM text chunk */
|
|
243
|
+
HttpStreamEventType["Text"] = "text";
|
|
244
|
+
/** LLM tool call event */
|
|
245
|
+
HttpStreamEventType["ToolCall"] = "tool_call";
|
|
246
|
+
/** LLM tool result event */
|
|
247
|
+
HttpStreamEventType["ToolResult"] = "tool_result";
|
|
248
|
+
})(HttpStreamEventType || (HttpStreamEventType = {}));
|
|
249
|
+
// #endregion
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Convert Express request headers to Headers object
|
|
253
|
+
*/
|
|
254
|
+
function expressHeadersToHeaders(req) {
|
|
255
|
+
const headers = new Headers();
|
|
256
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
257
|
+
if (value !== undefined) {
|
|
258
|
+
if (Array.isArray(value)) {
|
|
259
|
+
// Join array headers with comma
|
|
260
|
+
headers.set(key, value.join(", "));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
headers.set(key, value);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return headers;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Create HTTP context from Express request
|
|
271
|
+
*/
|
|
272
|
+
function createHttpContextFromExpress(req, pathPattern) {
|
|
273
|
+
const headers = expressHeadersToHeaders(req);
|
|
274
|
+
// Build query string from Express query object
|
|
275
|
+
const queryString = new URLSearchParams(req.query).toString();
|
|
276
|
+
return createHttpContext({
|
|
277
|
+
body: req.body,
|
|
278
|
+
headers,
|
|
279
|
+
method: req.method,
|
|
280
|
+
path: req.path,
|
|
281
|
+
queryString,
|
|
282
|
+
params: req.params,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Send JSON:API success response
|
|
287
|
+
*/
|
|
288
|
+
function sendDataResponse(res, data, statusCode = 200) {
|
|
289
|
+
if (data === null || data === undefined) {
|
|
290
|
+
res.status(204).send();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
res.status(statusCode).json({ data });
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Send JSON:API error response
|
|
297
|
+
*/
|
|
298
|
+
function sendErrorResponse(res, error) {
|
|
299
|
+
const status = error.status ?? 500;
|
|
300
|
+
const title = error.title ?? error.name ?? "Internal Server Error";
|
|
301
|
+
const detail = error.message;
|
|
302
|
+
res.status(status).json({
|
|
303
|
+
errors: [
|
|
304
|
+
{
|
|
305
|
+
detail,
|
|
306
|
+
status,
|
|
307
|
+
title,
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Apply CORS headers to response
|
|
314
|
+
*/
|
|
315
|
+
function applyCorsHeaders(res, corsHeaders) {
|
|
316
|
+
for (const [key, value] of Object.entries(corsHeaders)) {
|
|
317
|
+
if (value !== undefined) {
|
|
318
|
+
res.set(key, value);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Create Express middleware from a fabric HTTP service
|
|
324
|
+
*
|
|
325
|
+
* Wraps a FabricHttpService for use with Express:
|
|
326
|
+
* - Extracts HTTP context from Express request
|
|
327
|
+
* - Handles CORS preflight requests
|
|
328
|
+
* - Transforms input using the service's http function
|
|
329
|
+
* - Calls the service with transformed input
|
|
330
|
+
* - Sends response in JSON:API format
|
|
331
|
+
*/
|
|
332
|
+
function fabricExpress(config) {
|
|
333
|
+
const { service, methods = DEFAULT_HTTP_METHODS } = config;
|
|
334
|
+
// Validate service
|
|
335
|
+
if (!isFabricHttpService(service)) {
|
|
336
|
+
throw new Error("fabricExpress requires a FabricHttpService. Use fabricHttp() to create one.");
|
|
337
|
+
}
|
|
338
|
+
// Determine path from config or service alias
|
|
339
|
+
const path = config.path ?? `/${service.alias ?? ""}`;
|
|
340
|
+
// Normalize CORS configuration
|
|
341
|
+
const corsConfig = normalizeCorsConfig(service.cors);
|
|
342
|
+
// Create the middleware function
|
|
343
|
+
const middleware = async (req, res, next) => {
|
|
344
|
+
try {
|
|
345
|
+
// Create HTTP context from Express request
|
|
346
|
+
const httpContext = createHttpContextFromExpress(req, path);
|
|
347
|
+
// Get request origin for CORS
|
|
348
|
+
const requestOrigin = req.get("origin") ?? null;
|
|
349
|
+
// Handle CORS preflight
|
|
350
|
+
if (isPreflightRequest(req.method, httpContext.headers)) {
|
|
351
|
+
const preflightHeaders = buildPreflightHeaders(corsConfig, requestOrigin, req.get("access-control-request-method") ?? null, req.get("access-control-request-headers") ?? null, methods);
|
|
352
|
+
applyCorsHeaders(res, preflightHeaders);
|
|
353
|
+
res.status(204).send();
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
// Apply CORS headers to response
|
|
357
|
+
const corsHeaders = buildCorsHeaders(corsConfig, requestOrigin, methods);
|
|
358
|
+
applyCorsHeaders(res, corsHeaders);
|
|
359
|
+
// Check if method is allowed
|
|
360
|
+
if (!methods.includes(req.method.toUpperCase())) {
|
|
361
|
+
res.status(405).json({
|
|
362
|
+
errors: [
|
|
363
|
+
{
|
|
364
|
+
detail: `Method ${req.method} not allowed`,
|
|
365
|
+
status: 405,
|
|
366
|
+
title: "Method Not Allowed",
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
});
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
// Transform HTTP context to service input
|
|
373
|
+
const input = await transformHttpToInput(httpContext, service.http);
|
|
374
|
+
// Create service context with HTTP info
|
|
375
|
+
const serviceContext = {
|
|
376
|
+
http: httpContext,
|
|
377
|
+
};
|
|
378
|
+
// Call the service
|
|
379
|
+
const result = await service(input, serviceContext);
|
|
380
|
+
// Send response
|
|
381
|
+
sendDataResponse(res, result);
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
// Send error response
|
|
385
|
+
sendErrorResponse(res, error);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
// Attach metadata to middleware
|
|
389
|
+
const expressMiddleware = middleware;
|
|
390
|
+
expressMiddleware.service = service;
|
|
391
|
+
expressMiddleware.path = path;
|
|
392
|
+
expressMiddleware.methods = methods;
|
|
393
|
+
return expressMiddleware;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Check if a value is a FabricExpressMiddleware
|
|
397
|
+
*/
|
|
398
|
+
function isFabricExpressMiddleware(value) {
|
|
399
|
+
return (typeof value === "function" &&
|
|
400
|
+
"service" in value &&
|
|
401
|
+
"path" in value &&
|
|
402
|
+
"methods" in value);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Check if entry is a FabricExpressConfig (has service property)
|
|
407
|
+
*/
|
|
408
|
+
function isServiceConfig(entry) {
|
|
409
|
+
return (typeof entry === "object" &&
|
|
410
|
+
entry !== null &&
|
|
411
|
+
"service" in entry &&
|
|
412
|
+
isFabricHttpService(entry.service));
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Create an Express Router with multiple fabric services
|
|
416
|
+
*
|
|
417
|
+
* Provides a convenient way to mount multiple fabricHttp services:
|
|
418
|
+
* - Auto-registers each service at /${alias}
|
|
419
|
+
* - Supports custom path and method overrides per service
|
|
420
|
+
* - Optionally applies a prefix to all routes
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* ```typescript
|
|
424
|
+
* const router = FabricRouter({
|
|
425
|
+
* services: [
|
|
426
|
+
* userService,
|
|
427
|
+
* productService,
|
|
428
|
+
* { service: adminService, path: "/admin/:id", methods: ["POST"] },
|
|
429
|
+
* ],
|
|
430
|
+
* prefix: "/api",
|
|
431
|
+
* });
|
|
432
|
+
*
|
|
433
|
+
* app.use(router);
|
|
434
|
+
* // Routes: /api/users, /api/products, /api/admin/:id
|
|
435
|
+
* ```
|
|
436
|
+
*/
|
|
437
|
+
function FabricRouter(config) {
|
|
438
|
+
const { services, prefix } = config;
|
|
439
|
+
// Create base router
|
|
440
|
+
const router = express.Router();
|
|
441
|
+
// Track registered services
|
|
442
|
+
const registeredServices = [];
|
|
443
|
+
// Register each service
|
|
444
|
+
for (const entry of services) {
|
|
445
|
+
let service;
|
|
446
|
+
let path;
|
|
447
|
+
let methods;
|
|
448
|
+
if (isServiceConfig(entry)) {
|
|
449
|
+
// Config object with service + overrides
|
|
450
|
+
service = entry.service;
|
|
451
|
+
path = entry.path;
|
|
452
|
+
methods = entry.methods;
|
|
453
|
+
}
|
|
454
|
+
else if (isFabricHttpService(entry)) {
|
|
455
|
+
// Direct service
|
|
456
|
+
service = entry;
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
throw new Error("FabricRouter: Each service entry must be a FabricHttpService or { service: FabricHttpService }");
|
|
460
|
+
}
|
|
461
|
+
// Create middleware
|
|
462
|
+
const middleware = fabricExpress({
|
|
463
|
+
methods: methods ?? DEFAULT_HTTP_METHODS,
|
|
464
|
+
path,
|
|
465
|
+
service,
|
|
466
|
+
});
|
|
467
|
+
// Determine mount path
|
|
468
|
+
const mountPath = middleware.path;
|
|
469
|
+
// Register all methods for this path
|
|
470
|
+
for (const method of middleware.methods) {
|
|
471
|
+
const lowerMethod = method.toLowerCase();
|
|
472
|
+
// Express router methods
|
|
473
|
+
if (lowerMethod === "options") {
|
|
474
|
+
// OPTIONS is handled by the middleware for preflight
|
|
475
|
+
router.options(mountPath, middleware);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
router[lowerMethod](mountPath, middleware);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
// Also handle OPTIONS for CORS preflight if not already included
|
|
482
|
+
if (!middleware.methods.includes("OPTIONS")) {
|
|
483
|
+
router.options(mountPath, middleware);
|
|
484
|
+
}
|
|
485
|
+
registeredServices.push(service);
|
|
486
|
+
}
|
|
487
|
+
// Attach metadata
|
|
488
|
+
router.services = registeredServices;
|
|
489
|
+
router.prefix = prefix;
|
|
490
|
+
return router;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Check if a value is a FabricExpressRouter
|
|
494
|
+
*/
|
|
495
|
+
function isFabricExpressRouter(value) {
|
|
496
|
+
return (typeof value === "function" &&
|
|
497
|
+
"services" in value &&
|
|
498
|
+
Array.isArray(value.services));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
exports.FabricRouter = FabricRouter;
|
|
502
|
+
exports.fabricExpress = fabricExpress;
|
|
503
|
+
exports.isFabricExpressMiddleware = isFabricExpressMiddleware;
|
|
504
|
+
exports.isFabricExpressRouter = isFabricExpressRouter;
|
|
505
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","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":["Router"],"mappings":"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"}
|
|
@@ -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";
|