@browserlessapi/inferlo 0.0.0-stage → 0.3.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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -2
  3. package/dist/ai/index.d.ts +96 -0
  4. package/dist/ai/index.js +327 -0
  5. package/dist/ai/index.js.map +1 -0
  6. package/dist/ai/providers.d.ts +97 -0
  7. package/dist/ai/providers.js +204 -0
  8. package/dist/ai/providers.js.map +1 -0
  9. package/dist/app.d.ts +94 -0
  10. package/dist/app.js +365 -0
  11. package/dist/app.js.map +1 -0
  12. package/dist/auth.d.ts +29 -0
  13. package/dist/auth.js +61 -0
  14. package/dist/auth.js.map +1 -0
  15. package/dist/cli/main.d.ts +2 -0
  16. package/dist/cli/main.js +467 -0
  17. package/dist/cli/main.js.map +1 -0
  18. package/dist/db/memory.d.ts +2 -0
  19. package/dist/db/memory.js +128 -0
  20. package/dist/db/memory.js.map +1 -0
  21. package/dist/db/migrate.d.ts +84 -0
  22. package/dist/db/migrate.js +355 -0
  23. package/dist/db/migrate.js.map +1 -0
  24. package/dist/db/postgres.d.ts +37 -0
  25. package/dist/db/postgres.js +338 -0
  26. package/dist/db/postgres.js.map +1 -0
  27. package/dist/db/table.d.ts +72 -0
  28. package/dist/db/table.js +177 -0
  29. package/dist/db/table.js.map +1 -0
  30. package/dist/db/types.d.ts +36 -0
  31. package/dist/db/types.js +2 -0
  32. package/dist/db/types.js.map +1 -0
  33. package/dist/describe.d.ts +56 -0
  34. package/dist/describe.js +64 -0
  35. package/dist/describe.js.map +1 -0
  36. package/dist/env.d.ts +19 -0
  37. package/dist/env.js +72 -0
  38. package/dist/env.js.map +1 -0
  39. package/dist/errors.d.ts +40 -0
  40. package/dist/errors.js +99 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/index.d.ts +26 -0
  43. package/dist/index.js +18 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/mcp.d.ts +18 -0
  46. package/dist/mcp.js +166 -0
  47. package/dist/mcp.js.map +1 -0
  48. package/dist/model.d.ts +36 -0
  49. package/dist/model.js +76 -0
  50. package/dist/model.js.map +1 -0
  51. package/dist/openapi.d.ts +6 -0
  52. package/dist/openapi.js +71 -0
  53. package/dist/openapi.js.map +1 -0
  54. package/dist/route.d.ts +125 -0
  55. package/dist/route.js +28 -0
  56. package/dist/route.js.map +1 -0
  57. package/dist/schema.d.ts +156 -0
  58. package/dist/schema.js +430 -0
  59. package/dist/schema.js.map +1 -0
  60. package/dist/serve.d.ts +11 -0
  61. package/dist/serve.js +83 -0
  62. package/dist/serve.js.map +1 -0
  63. package/dist/testing.d.ts +16 -0
  64. package/dist/testing.js +30 -0
  65. package/dist/testing.js.map +1 -0
  66. package/llms.txt +27 -0
  67. package/package.json +82 -4
  68. package/templates/app/AGENTS.md +53 -0
  69. package/templates/app/CLAUDE.md +1 -0
  70. package/templates/app/README.md +14 -0
  71. package/templates/app/_env.example +5 -0
  72. package/templates/app/_gitignore +3 -0
  73. package/templates/app/package.json.tpl +31 -0
  74. package/templates/app/src/app.ts +38 -0
  75. package/templates/app/src/models.ts +31 -0
  76. package/templates/app/src/routes/health.ts +3 -0
  77. package/templates/app/src/routes/notes.ts +56 -0
  78. package/templates/app/src/server.ts +16 -0
  79. package/templates/app/test/notes.test.ts +50 -0
  80. package/templates/app/tsconfig.json +17 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * AI providers. Each one turns a provider-neutral request into an HTTP call.
3
+ * openaiCompatible() covers OpenAI, DeepSeek, Qwen (DashScope), Groq, Together, OpenRouter,
4
+ * Ollama, vLLM, LM Studio and any other server that speaks the Chat Completions API.
5
+ */
6
+ import { InferloError } from "../errors.ts";
7
+ export interface Message {
8
+ role: "system" | "user" | "assistant";
9
+ content: string;
10
+ }
11
+ export interface ProviderRequest {
12
+ model: string;
13
+ messages: Message[];
14
+ temperature?: number;
15
+ maxTokens?: number;
16
+ /** Ask for a JSON object response (when the provider supports it). */
17
+ json?: boolean;
18
+ /** JSON Schema of the expected object, for providers with native structured output. */
19
+ jsonSchema?: Record<string, unknown>;
20
+ signal?: AbortSignal;
21
+ }
22
+ export interface ProviderUsage {
23
+ inputTokens: number;
24
+ outputTokens: number;
25
+ }
26
+ export interface ProviderResponse {
27
+ text: string;
28
+ usage: ProviderUsage;
29
+ }
30
+ export interface Provider {
31
+ readonly name: string;
32
+ generate(request: ProviderRequest): Promise<ProviderResponse>;
33
+ stream?(request: ProviderRequest): AsyncIterable<string | {
34
+ usage: ProviderUsage;
35
+ }>;
36
+ embed?(request: {
37
+ model: string;
38
+ input: string[];
39
+ signal?: AbortSignal;
40
+ }): Promise<{
41
+ embeddings: number[][];
42
+ usage: ProviderUsage;
43
+ }>;
44
+ }
45
+ /** Raised when a provider call fails. retryable errors move on to the next fallback model. */
46
+ export declare class ProviderError extends InferloError {
47
+ readonly retryable: boolean;
48
+ constructor(provider: string, status: number, body: string);
49
+ }
50
+ type FetchLike = typeof fetch;
51
+ /** Parse a server-sent events stream into data payloads. */
52
+ export declare function sseData(body: ReadableStream<Uint8Array>): AsyncIterable<string>;
53
+ export interface OpenAICompatibleOptions {
54
+ /** Name used in model ids ("openai:gpt-5-mini"). */
55
+ name?: string;
56
+ baseURL: string;
57
+ apiKey?: string;
58
+ headers?: Record<string, string>;
59
+ /** Send response_format json_schema for structured output (default true for OpenAI, false otherwise). */
60
+ nativeStructuredOutput?: boolean;
61
+ fetch?: FetchLike;
62
+ }
63
+ export declare function openaiCompatible(options: OpenAICompatibleOptions): Provider;
64
+ export declare function openai(options: {
65
+ apiKey: string;
66
+ baseURL?: string;
67
+ organization?: string;
68
+ fetch?: FetchLike;
69
+ }): Provider;
70
+ /** Local models through Ollama's OpenAI-compatible endpoint. */
71
+ export declare function ollama(options?: {
72
+ baseURL?: string;
73
+ fetch?: FetchLike;
74
+ }): Provider;
75
+ export declare function anthropic(options: {
76
+ apiKey: string;
77
+ baseURL?: string;
78
+ version?: string;
79
+ fetch?: FetchLike;
80
+ }): Provider;
81
+ /** Gemini through Google's OpenAI-compatible endpoint. */
82
+ export declare function gemini(options: {
83
+ apiKey: string;
84
+ fetch?: FetchLike;
85
+ }): Provider;
86
+ /**
87
+ * Deterministic provider for tests. respond receives the request and returns the text.
88
+ *
89
+ * mockProvider({ respond: () => JSON.stringify({ priority: "urgent", summary: "Server down" }) })
90
+ */
91
+ export declare function mockProvider(options: {
92
+ name?: string;
93
+ respond: (request: ProviderRequest) => string | Promise<string>;
94
+ }): Provider & {
95
+ calls: ProviderRequest[];
96
+ };
97
+ export {};
@@ -0,0 +1,204 @@
1
+ /**
2
+ * AI providers. Each one turns a provider-neutral request into an HTTP call.
3
+ * openaiCompatible() covers OpenAI, DeepSeek, Qwen (DashScope), Groq, Together, OpenRouter,
4
+ * Ollama, vLLM, LM Studio and any other server that speaks the Chat Completions API.
5
+ */
6
+ import { InferloError } from "../errors.js";
7
+ /** Raised when a provider call fails. retryable errors move on to the next fallback model. */
8
+ export class ProviderError extends InferloError {
9
+ retryable;
10
+ constructor(provider, status, body) {
11
+ const retryable = status === 0 || status === 408 || status === 409 || status === 429 || status >= 500;
12
+ super("IL5006", `${provider} returned ${status || "a network error"}: ${body.slice(0, 300)}`, {
13
+ status: 502,
14
+ expose: false,
15
+ fix: status === 401 || status === 403 ? `Check the API key for ${provider}.` : retryable ? "Add a fallback model to the alias in createApp({ ai })." : undefined,
16
+ });
17
+ this.retryable = retryable;
18
+ }
19
+ }
20
+ async function post(provider, fetchImpl, url, headers, body, signal) {
21
+ let response;
22
+ try {
23
+ response = await fetchImpl(url, { method: "POST", headers: { "content-type": "application/json", ...headers }, body: JSON.stringify(body), signal });
24
+ }
25
+ catch (error) {
26
+ if (error.name === "AbortError")
27
+ throw error;
28
+ throw new ProviderError(provider, 0, String(error.message ?? error));
29
+ }
30
+ if (!response.ok)
31
+ throw new ProviderError(provider, response.status, await response.text().catch(() => ""));
32
+ return response;
33
+ }
34
+ /** Parse a server-sent events stream into data payloads. */
35
+ export async function* sseData(body) {
36
+ const reader = body.getReader();
37
+ const decoder = new TextDecoder();
38
+ let buffer = "";
39
+ while (true) {
40
+ const { value, done } = await reader.read();
41
+ if (done)
42
+ break;
43
+ buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");
44
+ let index;
45
+ while ((index = buffer.indexOf("\n\n")) !== -1) {
46
+ const event = buffer.slice(0, index);
47
+ buffer = buffer.slice(index + 2);
48
+ const data = event
49
+ .split("\n")
50
+ .filter((line) => line.startsWith("data:"))
51
+ .map((line) => line.slice(5).trimStart())
52
+ .join("\n");
53
+ if (data)
54
+ yield data;
55
+ }
56
+ }
57
+ }
58
+ export function openaiCompatible(options) {
59
+ const name = options.name ?? "openai-compatible";
60
+ const base = options.baseURL.replace(/\/+$/, "");
61
+ const fetchImpl = options.fetch ?? fetch;
62
+ const headers = { ...(options.apiKey ? { authorization: `Bearer ${options.apiKey}` } : {}), ...options.headers };
63
+ const body = (r, stream) => {
64
+ const out = { model: r.model, messages: r.messages, stream };
65
+ if (r.temperature !== undefined)
66
+ out.temperature = r.temperature;
67
+ if (r.maxTokens !== undefined)
68
+ out.max_tokens = r.maxTokens;
69
+ if (r.json) {
70
+ out.response_format =
71
+ options.nativeStructuredOutput && r.jsonSchema
72
+ ? { type: "json_schema", json_schema: { name: "output", schema: r.jsonSchema, strict: false } }
73
+ : { type: "json_object" };
74
+ }
75
+ if (stream)
76
+ out.stream_options = { include_usage: true };
77
+ return out;
78
+ };
79
+ return {
80
+ name,
81
+ async generate(r) {
82
+ const response = await post(name, fetchImpl, `${base}/chat/completions`, headers, body(r, false), r.signal);
83
+ const data = (await response.json());
84
+ return {
85
+ text: data.choices?.[0]?.message?.content ?? "",
86
+ usage: { inputTokens: data.usage?.prompt_tokens ?? 0, outputTokens: data.usage?.completion_tokens ?? 0 },
87
+ };
88
+ },
89
+ async *stream(r) {
90
+ const response = await post(name, fetchImpl, `${base}/chat/completions`, headers, body(r, true), r.signal);
91
+ for await (const data of sseData(response.body)) {
92
+ if (data === "[DONE]")
93
+ break;
94
+ const chunk = JSON.parse(data);
95
+ const text = chunk.choices?.[0]?.delta?.content;
96
+ if (text)
97
+ yield text;
98
+ if (chunk.usage)
99
+ yield { usage: { inputTokens: chunk.usage.prompt_tokens ?? 0, outputTokens: chunk.usage.completion_tokens ?? 0 } };
100
+ }
101
+ },
102
+ async embed({ model, input, signal }) {
103
+ const response = await post(name, fetchImpl, `${base}/embeddings`, headers, { model, input }, signal);
104
+ const data = (await response.json());
105
+ const embeddings = [...data.data].sort((a, b) => a.index - b.index).map((d) => d.embedding);
106
+ return { embeddings, usage: { inputTokens: data.usage?.prompt_tokens ?? 0, outputTokens: 0 } };
107
+ },
108
+ };
109
+ }
110
+ export function openai(options) {
111
+ return openaiCompatible({
112
+ name: "openai",
113
+ baseURL: options.baseURL ?? "https://api.openai.com/v1",
114
+ apiKey: options.apiKey,
115
+ headers: options.organization ? { "openai-organization": options.organization } : undefined,
116
+ nativeStructuredOutput: true,
117
+ fetch: options.fetch,
118
+ });
119
+ }
120
+ /** Local models through Ollama's OpenAI-compatible endpoint. */
121
+ export function ollama(options = {}) {
122
+ return openaiCompatible({ name: "ollama", baseURL: options.baseURL ?? "http://127.0.0.1:11434/v1", fetch: options.fetch });
123
+ }
124
+ export function anthropic(options) {
125
+ const name = "anthropic";
126
+ const base = (options.baseURL ?? "https://api.anthropic.com").replace(/\/+$/, "");
127
+ const fetchImpl = options.fetch ?? fetch;
128
+ const headers = { "x-api-key": options.apiKey, "anthropic-version": options.version ?? "2023-06-01" };
129
+ const body = (r, stream) => {
130
+ const system = r.messages.filter((m) => m.role === "system").map((m) => m.content).join("\n\n");
131
+ const out = {
132
+ model: r.model,
133
+ max_tokens: r.maxTokens ?? 4096,
134
+ messages: r.messages.filter((m) => m.role !== "system"),
135
+ stream,
136
+ };
137
+ if (system)
138
+ out.system = system;
139
+ if (r.temperature !== undefined)
140
+ out.temperature = r.temperature;
141
+ return out;
142
+ };
143
+ return {
144
+ name,
145
+ async generate(r) {
146
+ const response = await post(name, fetchImpl, `${base}/v1/messages`, headers, body(r, false), r.signal);
147
+ const data = (await response.json());
148
+ const text = (data.content ?? []).filter((c) => c.type === "text").map((c) => c.text ?? "").join("");
149
+ return { text, usage: { inputTokens: data.usage?.input_tokens ?? 0, outputTokens: data.usage?.output_tokens ?? 0 } };
150
+ },
151
+ async *stream(r) {
152
+ const response = await post(name, fetchImpl, `${base}/v1/messages`, headers, body(r, true), r.signal);
153
+ const usage = { inputTokens: 0, outputTokens: 0 };
154
+ for await (const data of sseData(response.body)) {
155
+ const event = JSON.parse(data);
156
+ if (event.type === "content_block_delta" && event.delta?.type === "text_delta" && event.delta.text)
157
+ yield event.delta.text;
158
+ if (event.type === "message_start")
159
+ usage.inputTokens = event.message?.usage?.input_tokens ?? 0;
160
+ if (event.type === "message_delta")
161
+ usage.outputTokens = event.usage?.output_tokens ?? 0;
162
+ }
163
+ yield { usage };
164
+ },
165
+ };
166
+ }
167
+ /** Gemini through Google's OpenAI-compatible endpoint. */
168
+ export function gemini(options) {
169
+ return openaiCompatible({ name: "gemini", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", apiKey: options.apiKey, fetch: options.fetch });
170
+ }
171
+ /**
172
+ * Deterministic provider for tests. respond receives the request and returns the text.
173
+ *
174
+ * mockProvider({ respond: () => JSON.stringify({ priority: "urgent", summary: "Server down" }) })
175
+ */
176
+ export function mockProvider(options) {
177
+ const calls = [];
178
+ const tokens = (s) => Math.ceil(s.length / 4);
179
+ return {
180
+ name: options.name ?? "mock",
181
+ calls,
182
+ async generate(r) {
183
+ calls.push(r);
184
+ const text = await options.respond(r);
185
+ return { text, usage: { inputTokens: tokens(r.messages.map((m) => m.content).join("")), outputTokens: tokens(text) } };
186
+ },
187
+ async *stream(r) {
188
+ const { text, usage } = await this.generate(r);
189
+ for (const part of text.match(/.{1,8}/gs) ?? [])
190
+ yield part;
191
+ yield { usage };
192
+ },
193
+ async embed({ input }) {
194
+ const embeddings = input.map((s) => {
195
+ const v = new Array(8).fill(0);
196
+ for (let i = 0; i < s.length; i++)
197
+ v[i % 8] += s.charCodeAt(i) / 1000;
198
+ return v;
199
+ });
200
+ return { embeddings, usage: { inputTokens: tokens(input.join("")), outputTokens: 0 } };
201
+ },
202
+ };
203
+ }
204
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"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"}
package/dist/app.d.ts ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * createApp wires models, routes, database, auth and AI together and gives you a standard
3
+ * fetch(Request) => Response handler that runs on Node, Bun, Deno and edge runtimes.
4
+ */
5
+ import { type AI, type AIConfig } from "./ai/index.ts";
6
+ import { type Db } from "./db/table.ts";
7
+ import type { Adapter } from "./db/types.ts";
8
+ import { type AppDescription } from "./describe.ts";
9
+ import type { AnyModel } from "./model.ts";
10
+ import { type AppDb, type AppUser, type Method, type RouteDef } from "./route.ts";
11
+ export interface AuthConfig {
12
+ /** Return the signed-in user for this request, or null. */
13
+ resolve(req: Request, ctx: {
14
+ db: AppDb;
15
+ url: URL;
16
+ }): AppUser | null | undefined | Promise<AppUser | null | undefined>;
17
+ /** Roles of a user, checked when a route uses auth: "<role>". Default: user.roles ?? []. */
18
+ roles?(user: AppUser): string[];
19
+ }
20
+ export interface CorsConfig {
21
+ /** Allowed origins, or "*". */
22
+ origin: string | string[];
23
+ credentials?: boolean;
24
+ headers?: string[];
25
+ maxAge?: number;
26
+ }
27
+ export interface MiddlewareContext {
28
+ req: Request;
29
+ url: URL;
30
+ state: Record<string, unknown>;
31
+ }
32
+ export type Middleware = (ctx: MiddlewareContext, next: () => Promise<Response>) => Promise<Response>;
33
+ export interface Logger {
34
+ info(message: string, data?: unknown): void;
35
+ error(message: string, data?: unknown): void;
36
+ }
37
+ /** Anything that contains routes: a route, an array, or a module (import * as tickets from "./routes/tickets.ts"). */
38
+ export type RouteSource = RouteDef | readonly RouteSource[] | {
39
+ readonly [name: string]: unknown;
40
+ };
41
+ export interface AppConfig<Models extends readonly AnyModel[]> {
42
+ /** Shown in OpenAPI, MCP and describe. */
43
+ name?: string;
44
+ version?: string;
45
+ description?: string;
46
+ models?: Models;
47
+ routes?: RouteSource[];
48
+ /** Database adapter. Default: memory(). Use postgres() from "@browserlessapi/inferlo/postgres" in production. */
49
+ db?: Adapter;
50
+ auth?: AuthConfig;
51
+ ai?: AIConfig;
52
+ cors?: boolean | CorsConfig;
53
+ middleware?: Middleware[];
54
+ /** Path for the OpenAPI document, or false to disable. Default "/openapi.json". */
55
+ openapi?: string | false;
56
+ /** Path for the MCP endpoint, or false to disable. Default "/mcp" when any route sets tool. */
57
+ mcp?: string | false;
58
+ /** Maximum request body in bytes. Default 1 MiB. */
59
+ maxBodySize?: number;
60
+ /** Include error messages of unexpected (500) errors in responses. Default false. */
61
+ exposeErrors?: boolean;
62
+ logger?: Logger;
63
+ }
64
+ export interface RequestOptions {
65
+ method?: Method | Lowercase<Method> | "OPTIONS" | "HEAD";
66
+ headers?: Record<string, string>;
67
+ /** JSON body. */
68
+ json?: unknown;
69
+ body?: BodyInit;
70
+ query?: Record<string, string | number | boolean | undefined>;
71
+ /** Run as this user, skipping auth.resolve (tests only, never reachable over HTTP). */
72
+ as?: AppUser | null;
73
+ }
74
+ export interface App<Models extends readonly AnyModel[]> {
75
+ readonly name: string;
76
+ readonly version: string;
77
+ readonly routes: readonly RouteDef[];
78
+ readonly models: Models;
79
+ readonly db: Db<Models>;
80
+ readonly ai: AI;
81
+ /** Standard fetch handler: export default app works on Bun, Deno and Cloudflare Workers. */
82
+ fetch(req: Request, ...rest: unknown[]): Promise<Response>;
83
+ /** In-process request for tests: await app.request("/tickets", { method: "POST", json: {...}, as: user }). */
84
+ request(path: string, options?: RequestOptions): Promise<Response>;
85
+ /** Start an HTTP server (Node, Bun or Deno). */
86
+ listen(port?: number, hostname?: string): Promise<{
87
+ port: number;
88
+ close(): Promise<void>;
89
+ }>;
90
+ /** Machine-readable map of the whole app: routes, models, auth and AI. */
91
+ describe(): AppDescription;
92
+ openapi(): Record<string, unknown>;
93
+ }
94
+ export declare function createApp<const Models extends readonly AnyModel[] = []>(config?: AppConfig<Models>): App<Models>;