@browserlessapi/inferlo 0.3.0 → 0.5.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 (115) hide show
  1. package/README.md +18 -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 +51 -2
  6. package/dist/ai/index.js +186 -37
  7. package/dist/ai/index.js.map +1 -1
  8. package/dist/ai/providers.d.ts +56 -3
  9. package/dist/ai/providers.js +102 -11
  10. package/dist/ai/providers.js.map +1 -1
  11. package/dist/ai/public.d.ts +20 -0
  12. package/dist/ai/public.js +17 -0
  13. package/dist/ai/public.js.map +1 -0
  14. package/dist/ai/tool.d.ts +47 -0
  15. package/dist/ai/tool.js +85 -0
  16. package/dist/ai/tool.js.map +1 -0
  17. package/dist/ai-client.d.ts +3 -0
  18. package/dist/ai-client.js +8 -0
  19. package/dist/ai-client.js.map +1 -0
  20. package/dist/app.d.ts +102 -2
  21. package/dist/app.js +509 -111
  22. package/dist/app.js.map +1 -1
  23. package/dist/cli/main.js +76 -4
  24. package/dist/cli/main.js.map +1 -1
  25. package/dist/client-ip.d.ts +7 -0
  26. package/dist/client-ip.js +27 -0
  27. package/dist/client-ip.js.map +1 -0
  28. package/dist/config.d.ts +16 -0
  29. package/dist/config.js +101 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/cron.d.ts +17 -0
  32. package/dist/cron.js +143 -0
  33. package/dist/cron.js.map +1 -0
  34. package/dist/db/migrate.d.ts +6 -3
  35. package/dist/db/migrate.js +126 -10
  36. package/dist/db/migrate.js.map +1 -1
  37. package/dist/db/table.d.ts +83 -7
  38. package/dist/db/table.js +245 -9
  39. package/dist/db/table.js.map +1 -1
  40. package/dist/deprecation.d.ts +23 -0
  41. package/dist/deprecation.js +70 -0
  42. package/dist/deprecation.js.map +1 -0
  43. package/dist/describe.d.ts +45 -5
  44. package/dist/describe.js +19 -2
  45. package/dist/describe.js.map +1 -1
  46. package/dist/elysia.d.ts +49 -0
  47. package/dist/elysia.js +10 -0
  48. package/dist/elysia.js.map +1 -0
  49. package/dist/env.d.ts +2 -0
  50. package/dist/env.js +5 -4
  51. package/dist/env.js.map +1 -1
  52. package/dist/express.d.ts +38 -0
  53. package/dist/express.js +18 -0
  54. package/dist/express.js.map +1 -0
  55. package/dist/fastify.d.ts +44 -0
  56. package/dist/fastify.js +47 -0
  57. package/dist/fastify.js.map +1 -0
  58. package/dist/hono.d.ts +26 -0
  59. package/dist/hono.js +10 -0
  60. package/dist/hono.js.map +1 -0
  61. package/dist/index.d.ts +20 -6
  62. package/dist/index.js +7 -3
  63. package/dist/index.js.map +1 -1
  64. package/dist/jobs.d.ts +181 -0
  65. package/dist/jobs.js +391 -0
  66. package/dist/jobs.js.map +1 -0
  67. package/dist/logging.d.ts +23 -0
  68. package/dist/logging.js +87 -0
  69. package/dist/logging.js.map +1 -0
  70. package/dist/mcp.d.ts +4 -6
  71. package/dist/mcp.js +53 -38
  72. package/dist/mcp.js.map +1 -1
  73. package/dist/metrics.d.ts +48 -0
  74. package/dist/metrics.js +184 -0
  75. package/dist/metrics.js.map +1 -0
  76. package/dist/nestjs.d.ts +43 -0
  77. package/dist/nestjs.js +47 -0
  78. package/dist/nestjs.js.map +1 -0
  79. package/dist/openapi.d.ts +0 -1
  80. package/dist/openapi.js +7 -0
  81. package/dist/openapi.js.map +1 -1
  82. package/dist/rate-limit.d.ts +45 -0
  83. package/dist/rate-limit.js +93 -0
  84. package/dist/rate-limit.js.map +1 -0
  85. package/dist/redact.d.ts +19 -0
  86. package/dist/redact.js +150 -0
  87. package/dist/redact.js.map +1 -0
  88. package/dist/route.d.ts +24 -0
  89. package/dist/route.js.map +1 -1
  90. package/dist/schema.d.ts +10 -2
  91. package/dist/schema.js +13 -1
  92. package/dist/schema.js.map +1 -1
  93. package/dist/secure-headers.d.ts +8 -0
  94. package/dist/secure-headers.js +61 -0
  95. package/dist/secure-headers.js.map +1 -0
  96. package/dist/serve.d.ts +53 -1
  97. package/dist/serve.js +158 -59
  98. package/dist/serve.js.map +1 -1
  99. package/dist/trpc.d.ts +57 -0
  100. package/dist/trpc.js +142 -0
  101. package/dist/trpc.js.map +1 -0
  102. package/dist/tsed.d.ts +32 -0
  103. package/dist/tsed.js +13 -0
  104. package/dist/tsed.js.map +1 -0
  105. package/llms.txt +10 -4
  106. package/package.json +57 -3
  107. package/templates/app/AGENTS.md +14 -8
  108. package/templates/app/README.md +2 -0
  109. package/templates/app/_env.example +2 -0
  110. package/templates/app/package.json.tpl +1 -0
  111. package/templates/app/src/app.ts +15 -8
  112. package/templates/app/src/config.ts +17 -0
  113. package/templates/app/src/routes/notes.ts +1 -1
  114. package/templates/app/src/server.ts +13 -3
  115. package/templates/app/src/routes/health.ts +0 -3
package/dist/app.d.ts CHANGED
@@ -8,6 +8,11 @@ import type { Adapter } from "./db/types.ts";
8
8
  import { type AppDescription } from "./describe.ts";
9
9
  import type { AnyModel } from "./model.ts";
10
10
  import { type AppDb, type AppUser, type Method, type RouteDef } from "./route.ts";
11
+ import { type RateLimitConfig } from "./rate-limit.ts";
12
+ import { type AppJobs, type JobQueueConfig, type JobSource } from "./jobs.ts";
13
+ import { type LogFields, type LoggingConfig } from "./logging.ts";
14
+ import { type MetricsConfig } from "./metrics.ts";
15
+ import { type SecureHeadersConfig } from "./secure-headers.ts";
11
16
  export interface AuthConfig {
12
17
  /** Return the signed-in user for this request, or null. */
13
18
  resolve(req: Request, ctx: {
@@ -28,11 +33,48 @@ export interface MiddlewareContext {
28
33
  req: Request;
29
34
  url: URL;
30
35
  state: Record<string, unknown>;
36
+ /** This request's id, sent back in the X-Request-Id header and added to its log entries. */
37
+ requestId: string;
31
38
  }
32
39
  export type Middleware = (ctx: MiddlewareContext, next: () => Promise<Response>) => Promise<Response>;
40
+ /**
41
+ * Where the app writes logs. fields holds structured values such as requestId (a request's log entries)
42
+ * or method, path, status and durationMs (request logs); loggers that only take two arguments ignore them.
43
+ */
33
44
  export interface Logger {
34
- info(message: string, data?: unknown): void;
35
- error(message: string, data?: unknown): void;
45
+ info(message: string, data?: unknown, fields?: LogFields): void;
46
+ error(message: string, data?: unknown, fields?: LogFields): void;
47
+ }
48
+ /** A readiness check: resolve (or return) when the dependency is usable, throw when it is not. */
49
+ export type HealthCheck = () => unknown | Promise<unknown>;
50
+ export interface HealthConfig {
51
+ /** Liveness endpoint: 200 while the process can answer requests. Default "/health". */
52
+ path?: string;
53
+ /** Readiness endpoint: 200 when every check passes, 503 otherwise. Default "/ready". */
54
+ readyPath?: string;
55
+ /** Your own checks, by name ("database" and "ai" are built in): { redis: () => redis.ping() }. */
56
+ checks?: Record<string, HealthCheck>;
57
+ /** Time each check may take before it fails. Default 5000 ms. */
58
+ timeoutMs?: number;
59
+ }
60
+ export interface CheckResult {
61
+ status: "ok" | "error";
62
+ durationMs: number;
63
+ /** "Check failed." unless the check threw an exposed InferloError (httpError) or exposeErrors is on. */
64
+ error?: string;
65
+ }
66
+ export interface CloseOptions {
67
+ /**
68
+ * Keep serving requests for this long after /ready starts answering 503, so load balancers stop sending
69
+ * traffic first (for example a few seconds more than the readiness probe period). Default 0.
70
+ */
71
+ delayMs?: number;
72
+ /** Longest wait for in-flight requests, waitUntil tasks and the running job before closing anyway. Default 10000. */
73
+ timeoutMs?: number;
74
+ }
75
+ export interface ReadinessReport {
76
+ status: "ready" | "not_ready";
77
+ checks: Record<string, CheckResult>;
36
78
  }
37
79
  /** Anything that contains routes: a route, an array, or a module (import * as tickets from "./routes/tickets.ts"). */
38
80
  export type RouteSource = RouteDef | readonly RouteSource[] | {
@@ -45,6 +87,10 @@ export interface AppConfig<Models extends readonly AnyModel[]> {
45
87
  description?: string;
46
88
  models?: Models;
47
89
  routes?: RouteSource[];
90
+ /** Background jobs and crons: jobs, cron(schedule, job) values, arrays or modules (import * as jobs from "./jobs.ts"). */
91
+ jobs?: JobSource[];
92
+ /** Where queued jobs are kept: { store: "memory" } (default) or { store: "database" } (Postgres table inferlo_jobs, shared by every instance). */
93
+ jobQueue?: JobQueueConfig;
48
94
  /** Database adapter. Default: memory(). Use postgres() from "@browserlessapi/inferlo/postgres" in production. */
49
95
  db?: Adapter;
50
96
  auth?: AuthConfig;
@@ -57,9 +103,51 @@ export interface AppConfig<Models extends readonly AnyModel[]> {
57
103
  mcp?: string | false;
58
104
  /** Maximum request body in bytes. Default 1 MiB. */
59
105
  maxBodySize?: number;
106
+ /** Where route rateLimit counts are kept: { store: "memory" } (default) or { store: "database" } (Postgres, shared by every instance). */
107
+ rateLimit?: RateLimitConfig;
108
+ /**
109
+ * Behind a load balancer or proxy that sets X-Forwarded-For: true uses its first address as the client IP
110
+ * (for rateLimit by "ip"). Default false, because clients can send that header themselves.
111
+ */
112
+ trustProxy?: boolean;
113
+ /**
114
+ * Health endpoints for load balancers and orchestrators: GET /health (liveness) and GET /ready (readiness:
115
+ * the database, the AI configuration and your checks). Public, never cached. Off by default.
116
+ */
117
+ health?: boolean | HealthConfig;
118
+ /**
119
+ * Security headers sent on every response that does not set them itself: Content-Security-Policy,
120
+ * Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy, Referrer-Policy, X-Content-Type-Options,
121
+ * X-Frame-Options, and Strict-Transport-Security over HTTPS. Change one by name, false leaves it out:
122
+ * { "X-Frame-Options": "SAMEORIGIN", "Content-Security-Policy": false }. false sends none. Default true.
123
+ */
124
+ secureHeaders?: boolean | SecureHeadersConfig;
125
+ /**
126
+ * Longest time in milliseconds a route may take (reading the body and running the handler) before it answers
127
+ * 503 IL2007 and ctx.signal is aborted. Routes can set their own timeoutMs. false turns it off. Default 60000.
128
+ */
129
+ requestTimeoutMs?: number | false;
130
+ /**
131
+ * More values to hide from logs, besides credentials Inferlo finds itself (authorization and cookie headers,
132
+ * tokens, API keys, passwords in URLs) and the AI provider keys: your config() result (its secrets) or
133
+ * strings: redact: [settings, process.env.WEBHOOK_SECRET]. They are replaced with "[redacted]".
134
+ */
135
+ redact?: readonly (string | object | undefined | null)[];
60
136
  /** Include error messages of unexpected (500) errors in responses. Default false. */
61
137
  exposeErrors?: boolean;
138
+ /** Your own logger (for example pino or winston): { info(message, data, fields), error(message, data, fields) }. */
62
139
  logger?: Logger;
140
+ /**
141
+ * The built-in logger's format ("text" or "json", one object per line) and request logs (requests: true logs
142
+ * each request's id, method, path, status and duration). Every response has an X-Request-Id header.
143
+ */
144
+ logging?: LoggingConfig;
145
+ /**
146
+ * Prometheus metrics at GET /metrics: requests by route and status with durations, job runs, and AI calls,
147
+ * tokens and cost per alias. { token } requires Authorization: Bearer <token>; without it the endpoint is
148
+ * public, so keep it off the internet. Off by default.
149
+ */
150
+ metrics?: boolean | MetricsConfig;
63
151
  }
64
152
  export interface RequestOptions {
65
153
  method?: Method | Lowercase<Method> | "OPTIONS" | "HEAD";
@@ -78,6 +166,8 @@ export interface App<Models extends readonly AnyModel[]> {
78
166
  readonly models: Models;
79
167
  readonly db: Db<Models>;
80
168
  readonly ai: AI;
169
+ /** Background jobs: app.jobs.enqueue(job, input), app.jobs.start() to run them, app.jobs.runDue() in tests. */
170
+ readonly jobs: AppJobs;
81
171
  /** Standard fetch handler: export default app works on Bun, Deno and Cloudflare Workers. */
82
172
  fetch(req: Request, ...rest: unknown[]): Promise<Response>;
83
173
  /** In-process request for tests: await app.request("/tickets", { method: "POST", json: {...}, as: user }). */
@@ -87,6 +177,16 @@ export interface App<Models extends readonly AnyModel[]> {
87
177
  port: number;
88
178
  close(): Promise<void>;
89
179
  }>;
180
+ /** Run the readiness checks (the same report as GET /ready, also when health is off). */
181
+ checkReady(): Promise<ReadinessReport>;
182
+ /** True once app.close() was called: /ready answers 503. */
183
+ readonly closing: boolean;
184
+ /**
185
+ * Graceful shutdown, for SIGTERM: /ready answers 503, then (after delayMs) new requests get 503 IL2006,
186
+ * in-flight requests, waitUntil tasks and the job workers from app.jobs.start() finish (up to timeoutMs),
187
+ * servers from app.listen() close, then the database. Calling it again returns the same promise.
188
+ */
189
+ close(options?: CloseOptions): Promise<void>;
90
190
  /** Machine-readable map of the whole app: routes, models, auth and AI. */
91
191
  describe(): AppDescription;
92
192
  openapi(): Record<string, unknown>;