@browserlessapi/inferlo 0.4.0 → 0.6.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 (142) hide show
  1. package/README.md +21 -3
  2. package/dist/adonisjs.d.ts +33 -0
  3. package/dist/adonisjs.js +30 -0
  4. package/dist/adonisjs.js.map +1 -0
  5. package/dist/ai/index.d.ts +22 -8
  6. package/dist/ai/index.js +107 -15
  7. package/dist/ai/index.js.map +1 -1
  8. package/dist/ai/providers.js +5 -4
  9. package/dist/ai/providers.js.map +1 -1
  10. package/dist/ai/public.d.ts +21 -0
  11. package/dist/ai/public.js +17 -0
  12. package/dist/ai/public.js.map +1 -0
  13. package/dist/ai/tool.d.ts +47 -0
  14. package/dist/ai/tool.js +85 -0
  15. package/dist/ai/tool.js.map +1 -0
  16. package/dist/ai-client.d.ts +3 -0
  17. package/dist/ai-client.js +8 -0
  18. package/dist/ai-client.js.map +1 -0
  19. package/dist/api-version.d.ts +32 -0
  20. package/dist/api-version.js +45 -0
  21. package/dist/api-version.js.map +1 -0
  22. package/dist/app.d.ts +117 -5
  23. package/dist/app.js +667 -156
  24. package/dist/app.js.map +1 -1
  25. package/dist/audit.d.ts +50 -0
  26. package/dist/audit.js +92 -0
  27. package/dist/audit.js.map +1 -0
  28. package/dist/cache.d.ts +92 -0
  29. package/dist/cache.js +245 -0
  30. package/dist/cache.js.map +1 -0
  31. package/dist/cli/main.js +45 -5
  32. package/dist/cli/main.js.map +1 -1
  33. package/dist/config.d.ts +16 -0
  34. package/dist/config.js +101 -0
  35. package/dist/config.js.map +1 -0
  36. package/dist/db/table.d.ts +31 -0
  37. package/dist/db/table.js +140 -1
  38. package/dist/db/table.js.map +1 -1
  39. package/dist/deprecation.d.ts +23 -0
  40. package/dist/deprecation.js +70 -0
  41. package/dist/deprecation.js.map +1 -0
  42. package/dist/describe.d.ts +68 -5
  43. package/dist/describe.js +38 -3
  44. package/dist/describe.js.map +1 -1
  45. package/dist/elysia.d.ts +49 -0
  46. package/dist/elysia.js +10 -0
  47. package/dist/elysia.js.map +1 -0
  48. package/dist/env.d.ts +2 -0
  49. package/dist/env.js +5 -4
  50. package/dist/env.js.map +1 -1
  51. package/dist/express.d.ts +38 -0
  52. package/dist/express.js +18 -0
  53. package/dist/express.js.map +1 -0
  54. package/dist/fastify.d.ts +52 -0
  55. package/dist/fastify.js +65 -0
  56. package/dist/fastify.js.map +1 -0
  57. package/dist/h3.d.ts +76 -0
  58. package/dist/h3.js +61 -0
  59. package/dist/h3.js.map +1 -0
  60. package/dist/hapi.d.ts +45 -0
  61. package/dist/hapi.js +57 -0
  62. package/dist/hapi.js.map +1 -0
  63. package/dist/hono.d.ts +26 -0
  64. package/dist/hono.js +10 -0
  65. package/dist/hono.js.map +1 -0
  66. package/dist/index.d.ts +27 -5
  67. package/dist/index.js +9 -2
  68. package/dist/index.js.map +1 -1
  69. package/dist/jobs.d.ts +24 -0
  70. package/dist/jobs.js +35 -6
  71. package/dist/jobs.js.map +1 -1
  72. package/dist/koa.d.ts +51 -0
  73. package/dist/koa.js +45 -0
  74. package/dist/koa.js.map +1 -0
  75. package/dist/lambda.d.ts +110 -0
  76. package/dist/lambda.js +169 -0
  77. package/dist/lambda.js.map +1 -0
  78. package/dist/logging.d.ts +23 -0
  79. package/dist/logging.js +87 -0
  80. package/dist/logging.js.map +1 -0
  81. package/dist/mcp.d.ts +1 -7
  82. package/dist/mcp.js +18 -4
  83. package/dist/mcp.js.map +1 -1
  84. package/dist/metrics.d.ts +48 -0
  85. package/dist/metrics.js +184 -0
  86. package/dist/metrics.js.map +1 -0
  87. package/dist/module.d.ts +52 -0
  88. package/dist/module.js +152 -0
  89. package/dist/module.js.map +1 -0
  90. package/dist/nestjs.d.ts +43 -0
  91. package/dist/nestjs.js +47 -0
  92. package/dist/nestjs.js.map +1 -0
  93. package/dist/nextjs.d.ts +35 -0
  94. package/dist/nextjs.js +33 -0
  95. package/dist/nextjs.js.map +1 -0
  96. package/dist/openapi.d.ts +3 -1
  97. package/dist/openapi.js +16 -3
  98. package/dist/openapi.js.map +1 -1
  99. package/dist/permissions.d.ts +26 -0
  100. package/dist/permissions.js +78 -0
  101. package/dist/permissions.js.map +1 -0
  102. package/dist/react-router.d.ts +41 -0
  103. package/dist/react-router.js +42 -0
  104. package/dist/react-router.js.map +1 -0
  105. package/dist/redact.d.ts +19 -0
  106. package/dist/redact.js +150 -0
  107. package/dist/redact.js.map +1 -0
  108. package/dist/request-matcher.d.ts +4 -0
  109. package/dist/request-matcher.js +14 -0
  110. package/dist/request-matcher.js.map +1 -0
  111. package/dist/route.d.ts +54 -1
  112. package/dist/route.js +24 -0
  113. package/dist/route.js.map +1 -1
  114. package/dist/secure-headers.d.ts +8 -0
  115. package/dist/secure-headers.js +61 -0
  116. package/dist/secure-headers.js.map +1 -0
  117. package/dist/serve.d.ts +72 -1
  118. package/dist/serve.js +201 -61
  119. package/dist/serve.js.map +1 -1
  120. package/dist/sessions.d.ts +72 -0
  121. package/dist/sessions.js +171 -0
  122. package/dist/sessions.js.map +1 -0
  123. package/dist/sveltekit.d.ts +72 -0
  124. package/dist/sveltekit.js +68 -0
  125. package/dist/sveltekit.js.map +1 -0
  126. package/dist/tracing.d.ts +118 -0
  127. package/dist/tracing.js +204 -0
  128. package/dist/tracing.js.map +1 -0
  129. package/dist/trpc.d.ts +57 -0
  130. package/dist/trpc.js +142 -0
  131. package/dist/trpc.js.map +1 -0
  132. package/dist/tsed.d.ts +32 -0
  133. package/dist/tsed.js +13 -0
  134. package/dist/tsed.js.map +1 -0
  135. package/llms.txt +15 -5
  136. package/package.json +99 -3
  137. package/templates/app/AGENTS.md +12 -6
  138. package/templates/app/_env.example +2 -0
  139. package/templates/app/src/app.ts +15 -8
  140. package/templates/app/src/config.ts +17 -0
  141. package/templates/app/src/server.ts +9 -9
  142. package/templates/app/src/routes/health.ts +0 -3
package/dist/route.js CHANGED
@@ -25,4 +25,28 @@ export const route = {
25
25
  export function isRoute(value) {
26
26
  return typeof value === "object" && value !== null && value.kind === "inferlo.route";
27
27
  }
28
+ /** The routes in route sources: routes, arrays and modules (import * as tickets), named after their exports. */
29
+ export function collectRoutes(sources) {
30
+ const out = [];
31
+ const seen = new Set();
32
+ const visit = (source, name) => {
33
+ if (!source || typeof source !== "object" || seen.has(source))
34
+ return;
35
+ seen.add(source);
36
+ if (isRoute(source)) {
37
+ out.push(name && !source.name ? { ...source, name } : source);
38
+ return;
39
+ }
40
+ if (Array.isArray(source)) {
41
+ for (const item of source)
42
+ visit(item);
43
+ return;
44
+ }
45
+ for (const [key, value] of Object.entries(source))
46
+ if (isRoute(value) || Array.isArray(value))
47
+ visit(value, key === "default" ? undefined : key);
48
+ };
49
+ visit(sources);
50
+ return out;
51
+ }
28
52
  //# sourceMappingURL=route.js.map
package/dist/route.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AA6GA,MAAM,OAAO,YAAY;IACd,MAAM,CAAS;IACf,IAAI,CAAO;IACX,OAAO,CAAwB;IAExC,YAAY,MAAc,EAAE,IAAU,EAAE,OAA8B;QACpE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,qFAAqF;IACrF,MAAM,CACJ,OAQC;QAED,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAuC,EAE5I,CAAC;IACJ,CAAC;CACF;AAED,SAAS,OAAO,CAAC,MAAc;IAC7B,OAAO,CAOL,IAAU,EACV,UAAgD,EAAE,EAClD,EAAE,CAAC,IAAI,YAAY,CAAmB,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC;IACrB,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC;CAC1B,CAAC;AAEF,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAAkB,CAAC,IAAI,KAAK,eAAe,CAAC;AACrG,CAAC"}
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AA8JA,MAAM,OAAO,YAAY;IACd,MAAM,CAAS;IACf,IAAI,CAAO;IACX,OAAO,CAAwB;IAExC,YAAY,MAAc,EAAE,IAAU,EAAE,OAA8B;QACpE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,qFAAqF;IACrF,MAAM,CACJ,OAQC;QAED,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAuC,EAE5I,CAAC;IACJ,CAAC;CACF;AAED,SAAS,OAAO,CAAC,MAAc;IAC7B,OAAO,CAOL,IAAU,EACV,UAAgD,EAAE,EAClD,EAAE,CAAC,IAAI,YAAY,CAAmB,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC;IACrB,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC;CAC1B,CAAC;AAEF,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAK,KAAkB,CAAC,IAAI,KAAK,eAAe,CAAC;AACrG,CAAC;AAED,gHAAgH;AAChH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAChC,MAAM,KAAK,GAAG,CAAC,MAAe,EAAE,IAAa,EAAE,EAAE;QAC/C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO;QACtE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjB,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACpB,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,KAAK,MAAM,IAAI,IAAI,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACnJ,CAAC,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,CAAC;IACf,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** Header name to value; false leaves the header out. Names are case-insensitive. */
2
+ export type SecureHeadersConfig = Record<string, string | false>;
3
+ /** Sent on every response by default. Strict-Transport-Security is sent only over HTTPS. */
4
+ export declare const DEFAULT_SECURE_HEADERS: Readonly<Record<string, string>>;
5
+ /** The headers to send (lowercase names), from createApp({ secureHeaders }). */
6
+ export declare function resolveSecureHeaders(option: boolean | SecureHeadersConfig | undefined): [string, string][];
7
+ /** Add the headers the response does not set itself. Strict-Transport-Security only when the request came over HTTPS. */
8
+ export declare function applySecureHeaders(response: Response, headers: [string, string][], https: boolean): Response;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Secure response headers, sent on every response unless the response already has the header:
3
+ *
4
+ * createApp({ secureHeaders: { "X-Frame-Options": "SAMEORIGIN", "Content-Security-Policy": false } })
5
+ * createApp({ secureHeaders: false }) // none of them
6
+ */
7
+ import { InferloError } from "./errors.js";
8
+ /** Sent on every response by default. Strict-Transport-Security is sent only over HTTPS. */
9
+ export const DEFAULT_SECURE_HEADERS = Object.freeze({
10
+ "content-security-policy": "default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'",
11
+ "cross-origin-opener-policy": "same-origin",
12
+ "cross-origin-resource-policy": "same-origin",
13
+ "referrer-policy": "no-referrer",
14
+ "strict-transport-security": "max-age=31536000; includeSubDomains",
15
+ "x-content-type-options": "nosniff",
16
+ "x-frame-options": "DENY",
17
+ });
18
+ const HSTS = "strict-transport-security";
19
+ const TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
20
+ /** The headers to send (lowercase names), from createApp({ secureHeaders }). */
21
+ export function resolveSecureHeaders(option) {
22
+ if (option === false)
23
+ return [];
24
+ const fix = 'Use createApp({ secureHeaders: { "X-Frame-Options": "SAMEORIGIN", "Content-Security-Policy": false } }), or secureHeaders: false to send none.';
25
+ if (option !== undefined && option !== true && (typeof option !== "object" || option === null || Array.isArray(option))) {
26
+ throw new InferloError("IL6016", `secureHeaders must be true, false or an object of header names, got ${JSON.stringify(option)}.`, { fix });
27
+ }
28
+ const headers = new Map(Object.entries(DEFAULT_SECURE_HEADERS));
29
+ for (const [name, value] of Object.entries(typeof option === "object" ? option : {})) {
30
+ if (!TOKEN.test(name))
31
+ throw new InferloError("IL6016", `secureHeaders: "${name}" is not a valid header name.`, { fix });
32
+ if (value === false) {
33
+ headers.delete(name.toLowerCase());
34
+ continue;
35
+ }
36
+ if (typeof value !== "string" || /[\r\n\0]/.test(value)) {
37
+ throw new InferloError("IL6016", `secureHeaders["${name}"] must be a string (without line breaks) or false, got ${JSON.stringify(value)}.`, { fix });
38
+ }
39
+ headers.set(name.toLowerCase(), value);
40
+ }
41
+ return [...headers];
42
+ }
43
+ /** Add the headers the response does not set itself. Strict-Transport-Security only when the request came over HTTPS. */
44
+ export function applySecureHeaders(response, headers, https) {
45
+ const missing = headers.filter(([name]) => (name !== HSTS || https) && !response.headers.has(name));
46
+ if (!missing.length)
47
+ return response;
48
+ try {
49
+ for (const [name, value] of missing)
50
+ response.headers.set(name, value);
51
+ return response;
52
+ }
53
+ catch {
54
+ // Immutable headers (Response.redirect, a fetch() response passed through): copy the response.
55
+ const copy = new Response(response.body, response);
56
+ for (const [name, value] of missing)
57
+ copy.headers.set(name, value);
58
+ return copy;
59
+ }
60
+ }
61
+ //# sourceMappingURL=secure-headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-headers.js","sourceRoot":"","sources":["../src/secure-headers.ts"],"names":[],"mappings":"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"}
package/dist/serve.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /** Start an HTTP server on Bun, Deno or Node using the app's fetch handler. */
2
1
  import type { App } from "./app.ts";
3
2
  export interface ServeOptions {
4
3
  port?: number;
@@ -8,4 +7,76 @@ export interface Server {
8
7
  port: number;
9
8
  close(): Promise<void>;
10
9
  }
10
+ /**
11
+ * The parts of a Node.js http.IncomingMessage that Inferlo reads. Express, Fastify (request.raw),
12
+ * NestJS, Koa (ctx.req) and plain node:http requests all have this shape.
13
+ */
14
+ export interface NodeRequest {
15
+ method?: string;
16
+ url?: string;
17
+ headers: Record<string, string | string[] | undefined>;
18
+ socket?: {
19
+ remoteAddress?: string;
20
+ encrypted?: boolean;
21
+ } | null;
22
+ /**
23
+ * A body the host framework already read (express.json(), body-parser): a string, bytes, or a plain object or
24
+ * array. Used instead of the stream. Instances of other classes are ignored and the stream is read.
25
+ */
26
+ body?: unknown;
27
+ [Symbol.asyncIterator](): AsyncIterator<unknown>;
28
+ }
29
+ /** The parts of a Node.js http.ServerResponse that Inferlo writes to. */
30
+ export interface NodeResponse {
31
+ readonly headersSent: boolean;
32
+ readonly writableFinished?: boolean;
33
+ writeHead(status: number, headers: Record<string, string | string[]>): unknown;
34
+ write(chunk: Uint8Array): boolean;
35
+ end(chunk?: string): unknown;
36
+ once(event: "drain", listener: () => void): unknown;
37
+ on(event: "close", listener: () => void): unknown;
38
+ }
39
+ export interface NodeHandlerOptions {
40
+ /**
41
+ * Path the app is mounted under, for example "/ai". It is removed from the URL before routing, so
42
+ * GET /ai/tickets matches route.get("/tickets"). Requests outside it go to next() (or get a 404).
43
+ * Leave it out when the host framework already strips the mount path (Express app.use("/ai", ...)).
44
+ */
45
+ prefix?: string;
46
+ /**
47
+ * Pass requests the app has no route for (by method and path, outside its OpenAPI, MCP, health and metrics
48
+ * endpoints) to the host framework's next() instead of answering 404 or 405. Mount the app before the host's
49
+ * routes with it, to move routes to Inferlo one at a time at the same URLs. Needs an app from createApp and
50
+ * a host that calls the handler with next (Express, NestJS, Connect). Default false.
51
+ */
52
+ fallthrough?: boolean;
53
+ }
54
+ export interface FromNodeRequestOptions extends NodeHandlerOptions {
55
+ /** Aborts the request (for example when the client disconnects). */
56
+ signal?: AbortSignal;
57
+ }
58
+ export type NodeHandler = (req: NodeRequest, res: NodeResponse, next?: (error?: unknown) => void) => Promise<void>;
59
+ export declare function normalizePrefix(prefix: string | undefined): string;
60
+ /** The path and query of a Node request with the prefix removed, or null when it is outside the prefix. */
61
+ export declare function stripPrefix(rawUrl: string, prefix: string): string | null;
62
+ /**
63
+ * Whether toNodeHandler(app, { prefix, fallthrough: true }) answers a Node request itself instead of passing it
64
+ * on. For hosts that must decide before handing the request over, such as a Fastify onRequest hook.
65
+ */
66
+ export declare function answersNodeRequest(app: object, req: Pick<NodeRequest, "url" | "method">, prefix?: string): boolean;
67
+ export declare function buildRequest(req: NodeRequest, path: string, signal?: AbortSignal): Request;
68
+ /**
69
+ * Convert a Node.js request (node:http, Express, Fastify's request.raw, NestJS) to a Web Request.
70
+ * With prefix, the prefix is removed from the path; a request outside it keeps its path.
71
+ */
72
+ export declare function fromNodeRequest(req: NodeRequest, options?: FromNodeRequestOptions): Request;
73
+ /** Write a Web Response (status, headers with every Set-Cookie, streamed body) to a Node response. */
74
+ export declare function writeResponse(res: NodeResponse, response: Response, method: string): Promise<void>;
75
+ /**
76
+ * A (req, res, next) handler that runs a whole Inferlo app (routes, OpenAPI, MCP) inside node:http,
77
+ * Express, Fastify, NestJS or any framework that hands out Node requests and responses.
78
+ */
79
+ export declare function toNodeHandler(app: Pick<App<any>, "fetch">, options?: NodeHandlerOptions): NodeHandler;
11
80
  export declare function serve(app: Pick<App<any>, "fetch">, options?: ServeOptions): Promise<Server>;
81
+ /** Closes every open connection of a Node server from serve(), for app.close() after its timeout. */
82
+ export declare const forceClosers: WeakMap<Server, () => void>;
package/dist/serve.js CHANGED
@@ -1,86 +1,226 @@
1
+ /**
2
+ * Run an app's fetch handler as an HTTP server (Bun, Deno or Node), or inside another Node framework:
3
+ *
4
+ * await serve(app, { port: 3000 })
5
+ * expressApp.use("/ai", toNodeHandler(app)) // Express strips the mount path
6
+ * http.createServer(toNodeHandler(app, { prefix: "/ai" })) // or strip it with prefix
7
+ */
8
+ import { createRedactor } from "./redact.js";
9
+ import { appAnswers } from "./request-matcher.js";
10
+ import { InferloError } from "./errors.js";
1
11
  import { clientIps } from "./client-ip.js";
2
- export async function serve(app, options = {}) {
3
- const port = options.port ?? 3000;
4
- const hostname = options.hostname ?? "0.0.0.0";
5
- const g = globalThis;
6
- if (g.Bun) {
7
- const server = g.Bun.serve({ port, hostname, fetch: (req, bunServer) => app.fetch(req, bunServer) });
8
- return { port: server.port, close: async () => server.stop(true) };
12
+ export function normalizePrefix(prefix) {
13
+ if (!prefix || prefix === "/")
14
+ return "";
15
+ return ("/" + prefix.replace(/^\/+|\/+$/g, "")).replace(/\/+/g, "/");
16
+ }
17
+ /** The path and query of a Node request with the prefix removed, or null when it is outside the prefix. */
18
+ export function stripPrefix(rawUrl, prefix) {
19
+ const url = rawUrl.startsWith("/") ? rawUrl : "/" + rawUrl;
20
+ if (!prefix)
21
+ return url;
22
+ if (!url.startsWith(prefix))
23
+ return null;
24
+ const rest = url.slice(prefix.length);
25
+ if (rest === "" || rest[0] === "?")
26
+ return "/" + rest;
27
+ if (rest[0] !== "/")
28
+ return null;
29
+ return rest;
30
+ }
31
+ /** Whether the app answers a method and a path (with query, prefix already removed) itself. */
32
+ function answersPath(app, method, path) {
33
+ let pathname = path.split("?")[0];
34
+ try {
35
+ pathname = new URL(pathname, "http://localhost").pathname;
9
36
  }
10
- if (g.Deno) {
11
- const server = g.Deno.serve({ port, hostname }, (req, info) => app.fetch(req, info));
12
- return { port: server.addr.port, close: () => server.shutdown() };
37
+ catch {
38
+ // Leave a path the URL parser rejects to the app, which answers it.
13
39
  }
14
- const http = await import("node:http");
15
- const { Readable } = await import("node:stream");
16
- const server = http.createServer(async (req, res) => {
17
- try {
18
- const host = req.headers.host ?? `localhost:${port}`;
19
- const url = new URL(req.url ?? "/", `http://${host}`);
20
- const headers = new Headers();
21
- for (const [k, v] of Object.entries(req.headers)) {
22
- if (v === undefined)
23
- continue;
24
- if (Array.isArray(v))
25
- for (const item of v)
26
- headers.append(k, item);
27
- else
28
- headers.set(k, v);
40
+ return appAnswers(app, method, pathname) === true;
41
+ }
42
+ /**
43
+ * Whether toNodeHandler(app, { prefix, fallthrough: true }) answers a Node request itself instead of passing it
44
+ * on. For hosts that must decide before handing the request over, such as a Fastify onRequest hook.
45
+ */
46
+ export function answersNodeRequest(app, req, prefix) {
47
+ const path = stripPrefix(req.url ?? "/", normalizePrefix(prefix));
48
+ return path !== null && answersPath(app, req.method ?? "GET", path);
49
+ }
50
+ function bodyStream(req) {
51
+ const iterator = req[Symbol.asyncIterator]();
52
+ return new ReadableStream({
53
+ async pull(controller) {
54
+ try {
55
+ const { value, done } = await iterator.next();
56
+ if (done)
57
+ return controller.close();
58
+ controller.enqueue(typeof value === "string" ? new TextEncoder().encode(value) : value);
59
+ }
60
+ catch (error) {
61
+ controller.error(error);
29
62
  }
30
- const hasBody = req.method !== "GET" && req.method !== "HEAD";
63
+ },
64
+ async cancel() {
65
+ await iterator.return?.();
66
+ },
67
+ });
68
+ }
69
+ /**
70
+ * True when req.body holds a body the host framework already read: a string or bytes (body-parser text and
71
+ * raw), or a plain object or array (express.json(), urlencoded forms). An instance of some other class is the
72
+ * host's own object, such as the body reader of an Encore raw request, and the stream is read instead.
73
+ */
74
+ function isParsedBody(body) {
75
+ if (body === undefined)
76
+ return false;
77
+ if (body === null || typeof body !== "object" || body instanceof Uint8Array || Array.isArray(body))
78
+ return true;
79
+ const proto = Object.getPrototypeOf(body);
80
+ return proto === Object.prototype || proto === null;
81
+ }
82
+ export function buildRequest(req, path, signal) {
83
+ const host = [req.headers.host].flat()[0] ?? "localhost";
84
+ const url = new URL(path, `${req.socket?.encrypted ? "https" : "http"}://${host}`);
85
+ const headers = new Headers();
86
+ for (const [k, v] of Object.entries(req.headers)) {
87
+ if (v === undefined || k.startsWith(":"))
88
+ continue;
89
+ if (Array.isArray(v))
90
+ for (const item of v)
91
+ headers.append(k, item);
92
+ else
93
+ headers.set(k, v);
94
+ }
95
+ const method = (req.method ?? "GET").toUpperCase();
96
+ let body;
97
+ if (method !== "GET" && method !== "HEAD") {
98
+ if (isParsedBody(req.body)) {
99
+ // The host framework already read the stream: use what it parsed.
100
+ headers.delete("content-length");
101
+ if (typeof req.body === "string" || req.body instanceof Uint8Array)
102
+ body = req.body;
103
+ else {
104
+ body = JSON.stringify(req.body);
105
+ headers.set("content-type", "application/json");
106
+ }
107
+ }
108
+ else
109
+ body = bodyStream(req);
110
+ }
111
+ const request = new Request(url, {
112
+ method,
113
+ headers,
114
+ body,
115
+ signal,
116
+ // @ts-expect-error duplex is required by Node for streaming bodies
117
+ duplex: "half",
118
+ });
119
+ if (req.socket?.remoteAddress)
120
+ clientIps.set(request, req.socket.remoteAddress);
121
+ return request;
122
+ }
123
+ /**
124
+ * Convert a Node.js request (node:http, Express, Fastify's request.raw, NestJS) to a Web Request.
125
+ * With prefix, the prefix is removed from the path; a request outside it keeps its path.
126
+ */
127
+ export function fromNodeRequest(req, options = {}) {
128
+ const raw = req.url ?? "/";
129
+ const path = stripPrefix(raw, normalizePrefix(options.prefix)) ?? (raw.startsWith("/") ? raw : "/" + raw);
130
+ return buildRequest(req, path, options.signal);
131
+ }
132
+ /** Write a Web Response (status, headers with every Set-Cookie, streamed body) to a Node response. */
133
+ export async function writeResponse(res, response, method) {
134
+ const outHeaders = {};
135
+ response.headers.forEach((value, key) => {
136
+ if (key === "set-cookie")
137
+ return;
138
+ outHeaders[key] = value;
139
+ });
140
+ const cookies = response.headers.getSetCookie?.() ?? [];
141
+ if (cookies.length)
142
+ outHeaders["set-cookie"] = cookies;
143
+ res.writeHead(response.status, outHeaders);
144
+ if (!response.body || method === "HEAD")
145
+ return void res.end();
146
+ const reader = response.body.getReader();
147
+ while (true) {
148
+ const { value, done } = await reader.read();
149
+ if (done)
150
+ break;
151
+ if (!res.write(value))
152
+ await new Promise((r) => res.once("drain", () => r()));
153
+ }
154
+ res.end();
155
+ }
156
+ /**
157
+ * A (req, res, next) handler that runs a whole Inferlo app (routes, OpenAPI, MCP) inside node:http,
158
+ * Express, Fastify, NestJS or any framework that hands out Node requests and responses.
159
+ */
160
+ export function toNodeHandler(app, options = {}) {
161
+ const prefix = normalizePrefix(options.prefix);
162
+ if (options.fallthrough !== undefined && typeof options.fallthrough !== "boolean") {
163
+ throw new InferloError("IL5019", "toNodeHandler fallthrough must be true or false.", { fix: "Use toNodeHandler(app, { fallthrough: true })." });
164
+ }
165
+ if (options.fallthrough && appAnswers(app, "GET", "/") === undefined) {
166
+ throw new InferloError("IL5019", "toNodeHandler(app, { fallthrough: true }) needs an app from createApp.", {
167
+ fix: "Pass the app returned by createApp, which knows its routes; a plain fetch handler cannot tell which requests to pass on.",
168
+ });
169
+ }
170
+ return async (req, res, next) => {
171
+ const path = stripPrefix(req.url ?? "/", prefix);
172
+ if (path === null && next)
173
+ return next();
174
+ if (options.fallthrough && next && path !== null && !answersPath(app, req.method ?? "GET", path))
175
+ return next();
176
+ try {
31
177
  const controller = new AbortController();
32
178
  res.on("close", () => {
33
179
  if (!res.writableFinished)
34
180
  controller.abort();
35
181
  });
36
- const request = new Request(url, {
37
- method: req.method,
38
- headers,
39
- body: hasBody ? Readable.toWeb(req) : undefined,
40
- signal: controller.signal,
41
- // @ts-expect-error duplex is required by Node for streaming bodies
42
- duplex: "half",
43
- });
44
- if (req.socket.remoteAddress)
45
- clientIps.set(request, req.socket.remoteAddress);
182
+ const request = buildRequest(req, path ?? (req.url ?? "/"), controller.signal);
46
183
  const response = await app.fetch(request);
47
- const outHeaders = {};
48
- response.headers.forEach((value, key) => {
49
- if (key === "set-cookie")
50
- return;
51
- outHeaders[key] = value;
52
- });
53
- const cookies = response.headers.getSetCookie?.() ?? [];
54
- if (cookies.length)
55
- outHeaders["set-cookie"] = cookies;
56
- res.writeHead(response.status, outHeaders);
57
- if (!response.body || req.method === "HEAD")
58
- return void res.end();
59
- const reader = response.body.getReader();
60
- while (true) {
61
- const { value, done } = await reader.read();
62
- if (done)
63
- break;
64
- if (!res.write(value))
65
- await new Promise((r) => res.once("drain", r));
66
- }
67
- res.end();
184
+ await writeResponse(res, response, request.method);
68
185
  }
69
186
  catch (error) {
70
- console.error("[inferlo] server error", error);
187
+ console.error("[inferlo] server error", createRedactor([]).value(error));
71
188
  if (!res.headersSent)
72
189
  res.writeHead(500, { "content-type": "application/json" });
73
190
  res.end(JSON.stringify({ error: { code: "IL9000", message: "Internal server error" } }));
74
191
  }
75
- });
192
+ };
193
+ }
194
+ export async function serve(app, options = {}) {
195
+ const port = options.port ?? 3000;
196
+ const hostname = options.hostname ?? "0.0.0.0";
197
+ const g = globalThis;
198
+ if (g.Bun) {
199
+ const server = g.Bun.serve({ port, hostname, fetch: (req, bunServer) => app.fetch(req, bunServer) });
200
+ return { port: server.port, close: async () => server.stop(true) };
201
+ }
202
+ if (g.Deno) {
203
+ const server = g.Deno.serve({ port, hostname }, (req, info) => app.fetch(req, info));
204
+ return { port: server.addr.port, close: () => server.shutdown() };
205
+ }
206
+ const http = await import("node:http");
207
+ const handler = toNodeHandler(app);
208
+ const server = http.createServer((req, res) => void handler(req, res));
76
209
  await new Promise((resolve, reject) => {
77
210
  server.once("error", reject);
78
211
  server.listen(port, hostname, () => resolve());
79
212
  });
80
213
  const address = server.address();
81
- return {
214
+ const result = {
82
215
  port: typeof address === "object" && address ? address.port : port,
83
- close: () => new Promise((resolve) => server.close(() => resolve())),
216
+ close: () => new Promise((resolve) => {
217
+ server.close(() => resolve());
218
+ server.closeIdleConnections();
219
+ }),
84
220
  };
221
+ forceClosers.set(result, () => server.closeAllConnections());
222
+ return result;
85
223
  }
224
+ /** Closes every open connection of a Node server from serve(), for app.close() after its timeout. */
225
+ export const forceClosers = new WeakMap();
86
226
  //# sourceMappingURL=serve.js.map
package/dist/serve.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"serve.js","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Cookie sessions for browser apps: signed, HttpOnly cookies and CSRF protection, with no session table.
3
+ *
4
+ * export const session = sessions({
5
+ * secret: config.SESSION_SECRET,
6
+ * user: ({ userId }, { db }) => db.users.find(userId),
7
+ * });
8
+ * createApp({ auth: session, ... });
9
+ *
10
+ * // in a login route (auth: "public"), after checking the password:
11
+ * const { csrfToken } = await session.signIn(ctx, user.id);
12
+ * // in a logout route:
13
+ * session.signOut(ctx);
14
+ *
15
+ * Requests that change data (POST, PUT, PATCH, DELETE) with a session cookie must send the CSRF token in an
16
+ * X-CSRF-Token header or a _csrf form field, or they are rejected with IL3005.
17
+ */
18
+ import type { AuthConfig } from "./app.ts";
19
+ import type { AppDb, AppUser } from "./route.ts";
20
+ export interface SessionData {
21
+ /** The id passed to session.signIn(ctx, userId). */
22
+ userId: string;
23
+ /** When the session was created (milliseconds since 1970). Compare it to a "signed out everywhere" time to revoke older sessions. */
24
+ issuedAt: number;
25
+ }
26
+ export interface SessionCookieOptions {
27
+ /** Cookie name. Default "inferlo_session"; the CSRF cookie is the same name with "_csrf" added. */
28
+ name?: string;
29
+ /** SameSite attribute. Default "lax" (links from other sites keep the session, cross-site form posts do not send it). */
30
+ sameSite?: "lax" | "strict";
31
+ /** Secure attribute. Default true, except for plain http on localhost, 127.0.0.1 and ::1 during development. */
32
+ secure?: boolean;
33
+ /** Domain attribute, to share the session with subdomains. Default: none (only the host that set it). */
34
+ domain?: string;
35
+ /** Path attribute. Default "/". */
36
+ path?: string;
37
+ }
38
+ export interface SessionsOptions {
39
+ /**
40
+ * The signing secret, at least 32 characters: keep it in config({ secrets }). To rotate it, pass
41
+ * [newSecret, oldSecret]: new sessions are signed with the first, and sessions signed with any of them stay valid.
42
+ */
43
+ secret: string | readonly string[];
44
+ /** Load the signed-in user for a session, or return null to end it (deleted or disabled users, revoked sessions). */
45
+ user: (session: SessionData, ctx: {
46
+ db: AppDb;
47
+ req: Request;
48
+ }) => AppUser | null | undefined | Promise<AppUser | null | undefined>;
49
+ /** How long a session lasts after sign-in, in milliseconds. Default 7 days; 1 minute to 400 days. */
50
+ maxAgeMs?: number;
51
+ cookie?: SessionCookieOptions;
52
+ /** Roles of a user, checked when a route uses auth: "<role>". Default: user.roles ?? []. */
53
+ roles?: (user: AppUser) => string[];
54
+ }
55
+ /** What session.signIn and session.signOut need from the route context. */
56
+ export interface SessionResponseContext {
57
+ url: URL;
58
+ header(name: string, value: string): void;
59
+ }
60
+ /** createApp({ auth: session }) with sign-in, sign-out and the CSRF token of the current session. */
61
+ export interface Sessions extends AuthConfig {
62
+ /** Start a session for this user: sets the session and CSRF cookies. Returns the CSRF token to send with changes. */
63
+ signIn(ctx: SessionResponseContext, userId: string): Promise<{
64
+ csrfToken: string;
65
+ }>;
66
+ /** End the session: clears both cookies. */
67
+ signOut(ctx: SessionResponseContext): void;
68
+ /** The CSRF token of the request's session (to put in a form's _csrf field), or null without a valid session. */
69
+ csrfToken(req: Request): Promise<string | null>;
70
+ }
71
+ /** Signed cookie sessions with CSRF protection: createApp({ auth: sessions({ secret, user }) }). */
72
+ export declare function sessions(options: SessionsOptions): Sessions;