@browserlessapi/inferlo 0.6.0 → 0.7.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 (95) hide show
  1. package/README.md +7 -4
  2. package/dist/ai/ai-sdk.d.ts +48 -0
  3. package/dist/ai/ai-sdk.js +235 -0
  4. package/dist/ai/ai-sdk.js.map +1 -0
  5. package/dist/ai/index.d.ts +37 -3
  6. package/dist/ai/index.js +96 -7
  7. package/dist/ai/index.js.map +1 -1
  8. package/dist/ai/public.d.ts +5 -1
  9. package/dist/ai/public.js +2 -0
  10. package/dist/ai/public.js.map +1 -1
  11. package/dist/ai/ui.d.ts +47 -0
  12. package/dist/ai/ui.js +33 -0
  13. package/dist/ai/ui.js.map +1 -0
  14. package/dist/app.d.ts +31 -4
  15. package/dist/app.js +106 -29
  16. package/dist/app.js.map +1 -1
  17. package/dist/astro.d.ts +60 -0
  18. package/dist/astro.js +68 -0
  19. package/dist/astro.js.map +1 -0
  20. package/dist/audit.d.ts +8 -1
  21. package/dist/audit.js +9 -2
  22. package/dist/audit.js.map +1 -1
  23. package/dist/auth.d.ts +1 -0
  24. package/dist/auth.js +1 -0
  25. package/dist/auth.js.map +1 -1
  26. package/dist/azure.d.ts +66 -0
  27. package/dist/azure.js +119 -0
  28. package/dist/azure.js.map +1 -0
  29. package/dist/cache.d.ts +13 -9
  30. package/dist/cache.js +11 -9
  31. package/dist/cache.js.map +1 -1
  32. package/dist/cli/main.js +4 -4
  33. package/dist/cli/main.js.map +1 -1
  34. package/dist/client-ip.d.ts +36 -1
  35. package/dist/client-ip.js +80 -1
  36. package/dist/client-ip.js.map +1 -1
  37. package/dist/db/memory.js +2 -1
  38. package/dist/db/memory.js.map +1 -1
  39. package/dist/db/postgres.js +4 -1
  40. package/dist/db/postgres.js.map +1 -1
  41. package/dist/db/table.d.ts +37 -5
  42. package/dist/db/table.js +96 -15
  43. package/dist/db/table.js.map +1 -1
  44. package/dist/db/types.d.ts +2 -0
  45. package/dist/describe.d.ts +15 -4
  46. package/dist/describe.js +10 -2
  47. package/dist/describe.js.map +1 -1
  48. package/dist/events.d.ts +134 -0
  49. package/dist/events.js +196 -0
  50. package/dist/events.js.map +1 -0
  51. package/dist/index.d.ts +12 -5
  52. package/dist/index.js +4 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/jobs.d.ts +50 -10
  55. package/dist/jobs.js +66 -13
  56. package/dist/jobs.js.map +1 -1
  57. package/dist/langchain.d.ts +58 -0
  58. package/dist/langchain.js +220 -0
  59. package/dist/langchain.js.map +1 -0
  60. package/dist/model.d.ts +23 -6
  61. package/dist/model.js +35 -6
  62. package/dist/model.js.map +1 -1
  63. package/dist/rate-limit.d.ts +5 -3
  64. package/dist/rate-limit.js +3 -3
  65. package/dist/rate-limit.js.map +1 -1
  66. package/dist/redis-events.d.ts +27 -0
  67. package/dist/redis-events.js +163 -0
  68. package/dist/redis-events.js.map +1 -0
  69. package/dist/redis-jobs.d.ts +24 -0
  70. package/dist/redis-jobs.js +203 -0
  71. package/dist/redis-jobs.js.map +1 -0
  72. package/dist/redis.d.ts +30 -0
  73. package/dist/redis.js +106 -0
  74. package/dist/redis.js.map +1 -0
  75. package/dist/response-body.d.ts +6 -0
  76. package/dist/response-body.js +7 -0
  77. package/dist/response-body.js.map +1 -0
  78. package/dist/route.d.ts +14 -1
  79. package/dist/route.js.map +1 -1
  80. package/dist/schema.d.ts +2 -2
  81. package/dist/serve.d.ts +6 -1
  82. package/dist/serve.js +64 -7
  83. package/dist/serve.js.map +1 -1
  84. package/dist/service-client.d.ts +91 -0
  85. package/dist/service-client.js +177 -0
  86. package/dist/service-client.js.map +1 -0
  87. package/dist/sessions.d.ts +2 -0
  88. package/dist/sessions.js +1 -0
  89. package/dist/sessions.js.map +1 -1
  90. package/dist/tracing.d.ts +7 -3
  91. package/dist/tracing.js +8 -2
  92. package/dist/tracing.js.map +1 -1
  93. package/llms.txt +1 -0
  94. package/package.json +36 -4
  95. package/templates/app/AGENTS.md +5 -3
@@ -0,0 +1,220 @@
1
+ /**
2
+ * LangChain.js: Inferlo's AI aliases as a LangChain chat model, and Inferlo tools (function tools and routes)
3
+ * as LangChain tools.
4
+ *
5
+ * import { toLangChainModel, toLangChainTools } from "@browserlessapi/inferlo/langchain";
6
+ *
7
+ * const model = toLangChainModel(ctx.ai, { model: "fast", for: user.id });
8
+ * const agent = createAgent({ model, tools: toLangChainTools([getWeather, createTicket], { ai: ctx.ai }) });
9
+ *
10
+ * The model keeps Inferlo's aliases, fallback, budgets, usage tracking and tracing; LangChain runs the agent
11
+ * loop and the tools. Needs @langchain/core 0.3 or later (an optional peer dependency).
12
+ */
13
+ import { BaseChatModel } from "@langchain/core/language_models/chat_models";
14
+ import { AIMessage, AIMessageChunk } from "@langchain/core/messages";
15
+ import { ChatGenerationChunk } from "@langchain/core/outputs";
16
+ import { DynamicStructuredTool } from "@langchain/core/tools";
17
+ import { convertToOpenAITool } from "@langchain/core/utils/function_calling";
18
+ import { callModel, routeToolsOf } from "./ai/index.js";
19
+ import { functionToolSpec, isTool, runFunctionTool } from "./ai/tool.js";
20
+ import { InferloError } from "./errors.js";
21
+ const invalid = (message, fix) => new InferloError("IL5030", message, { fix });
22
+ /** Inferlo's AI client as a LangChain chat model. Make one with toLangChainModel(ai, { model }). */
23
+ export class InferloChatModel extends BaseChatModel {
24
+ ai;
25
+ options;
26
+ constructor(ai, options = {}) {
27
+ super({});
28
+ this.ai = ai;
29
+ this.options = options;
30
+ }
31
+ static lc_name() {
32
+ return "InferloChatModel";
33
+ }
34
+ _llmType() {
35
+ return "inferlo";
36
+ }
37
+ /** Offer tools to the model: LangChain tools, OpenAI-style tool definitions, or Inferlo function tools. */
38
+ bindTools(tools, kwargs) {
39
+ return this.withConfig({ ...kwargs, tools: tools });
40
+ }
41
+ async _generate(messages, options) {
42
+ const result = await callModel(this.ai, {
43
+ model: this.options.model,
44
+ messages: toMessages(messages),
45
+ tools: toolSpecs(options.tools),
46
+ temperature: this.options.temperature,
47
+ maxTokens: this.options.maxTokens,
48
+ for: this.options.for,
49
+ signal: options.signal,
50
+ });
51
+ const usage = { input_tokens: result.usage.inputTokens, output_tokens: result.usage.outputTokens, total_tokens: result.usage.inputTokens + result.usage.outputTokens };
52
+ const message = new AIMessage({
53
+ content: result.text,
54
+ tool_calls: result.toolCalls.map((call) => ({ id: call.id, name: call.name, args: toolArgs(call.input), type: "tool_call" })),
55
+ usage_metadata: usage,
56
+ response_metadata: { model: result.usage.model, requested: result.usage.requested, cost: result.usage.cost },
57
+ });
58
+ return { generations: [{ text: result.text, message }], llmOutput: { tokenUsage: { promptTokens: usage.input_tokens, completionTokens: usage.output_tokens, totalTokens: usage.total_tokens } } };
59
+ }
60
+ /** Streams text with ai.stream(). With tools bound, the answer (and its tool calls) comes as one chunk. */
61
+ async *_streamResponseChunks(messages, options, runManager) {
62
+ if (toolSpecs(options.tools)?.length) {
63
+ const { generations } = await this._generate(messages, options);
64
+ const message = generations[0].message;
65
+ yield new ChatGenerationChunk({
66
+ text: generations[0].text,
67
+ message: new AIMessageChunk({
68
+ content: message.content,
69
+ tool_call_chunks: (message.tool_calls ?? []).map((call, index) => ({ id: call.id, name: call.name, args: JSON.stringify(call.args), index, type: "tool_call_chunk" })),
70
+ usage_metadata: message.usage_metadata,
71
+ response_metadata: message.response_metadata,
72
+ }),
73
+ });
74
+ return;
75
+ }
76
+ const all = toMessages(messages);
77
+ const system = all.filter((m) => m.role === "system").map((m) => m.content).join("\n\n");
78
+ const stream = this.ai.stream({
79
+ model: this.options.model,
80
+ ...(system ? { system } : {}),
81
+ messages: all.filter((m) => m.role !== "system"),
82
+ temperature: this.options.temperature,
83
+ maxTokens: this.options.maxTokens,
84
+ for: this.options.for,
85
+ signal: options.signal,
86
+ });
87
+ for await (const text of stream) {
88
+ yield new ChatGenerationChunk({ text, message: new AIMessageChunk({ content: text }) });
89
+ await runManager?.handleLLMNewToken(text);
90
+ }
91
+ const usage = await stream.usage();
92
+ yield new ChatGenerationChunk({
93
+ text: "",
94
+ message: new AIMessageChunk({
95
+ content: "",
96
+ usage_metadata: { input_tokens: usage.inputTokens, output_tokens: usage.outputTokens, total_tokens: usage.inputTokens + usage.outputTokens },
97
+ response_metadata: { model: usage.model, requested: usage.requested, cost: usage.cost },
98
+ }),
99
+ });
100
+ }
101
+ }
102
+ /**
103
+ * A LangChain chat model that calls Inferlo's AI: toLangChainModel(ctx.ai, { model: "fast", for: user.id }).
104
+ * Use it anywhere LangChain takes a chat model (createAgent, chains, LangGraph).
105
+ */
106
+ export function toLangChainModel(ai, options = {}) {
107
+ if (!ai || typeof ai !== "object" || typeof ai.generate !== "function") {
108
+ throw invalid("toLangChainModel(ai) needs Inferlo's AI client.", 'Pass ctx.ai in a route handler or job, app.ai, or the client createAI() returns: toLangChainModel(ctx.ai, { model: "fast" }).');
109
+ }
110
+ if (options === null || typeof options !== "object")
111
+ throw invalid("toLangChainModel() options must be an object.", 'Use toLangChainModel(ai, { model: "fast" }).');
112
+ for (const key of Object.keys(options)) {
113
+ if (!["model", "for", "temperature", "maxTokens"].includes(key))
114
+ throw invalid(`Unknown toLangChainModel() option "${key}".`, "Options: model, for, temperature, maxTokens.");
115
+ }
116
+ return new InferloChatModel(ai, { ...options });
117
+ }
118
+ /**
119
+ * Inferlo tools as LangChain tools. Function tools (tool(name, ...).handle(fn)) work anywhere; routes work with a
120
+ * request's AI client ({ ai: ctx.ai }) and run as the signed-in user, with the route's auth and validation.
121
+ */
122
+ export function toLangChainTools(tools, options = {}) {
123
+ if (!Array.isArray(tools))
124
+ throw invalid("toLangChainTools() needs an array of tools.", "Pass [getWeather, createTicket]: function tools and routes.");
125
+ const routeTools = options.ai ? routeToolsOf(options.ai) : undefined;
126
+ const names = new Set();
127
+ return tools.map((entry) => {
128
+ let spec;
129
+ let run;
130
+ if (isTool(entry)) {
131
+ spec = functionToolSpec(entry);
132
+ run = async (input) => (await runFunctionTool(entry, input, undefined)).text;
133
+ }
134
+ else if (entry && typeof entry === "object" && "path" in entry && "method" in entry) {
135
+ if (!routeTools) {
136
+ throw new InferloError("IL5009", "Routes as LangChain tools need the AI client of a request.", {
137
+ fix: "Call toLangChainTools([createTicket], { ai: ctx.ai }) in a route handler, so each route runs as the signed-in user with its auth and validation, or make a function tool with tool(name, { description, input }).handle(fn).",
138
+ });
139
+ }
140
+ const route = entry;
141
+ spec = routeTools.describe(route);
142
+ run = async (input) => (await routeTools.runner(route, input)).text;
143
+ }
144
+ else {
145
+ throw invalid("toLangChainTools() takes function tools made with tool(...).handle(fn) and routes.", "Pass [getWeather, createTicket].");
146
+ }
147
+ if (names.has(spec.name))
148
+ throw new InferloError("IL5013", `Two tools are named "${spec.name}".`, { fix: "Give each tool a unique name (a route's tool name is its export name, or tool: { name })." });
149
+ names.add(spec.name);
150
+ return new DynamicStructuredTool({ name: spec.name, description: spec.description, schema: spec.inputSchema, func: async (input) => run(input) });
151
+ });
152
+ }
153
+ /** Bound tools as Inferlo tool specs. */
154
+ function toolSpecs(tools) {
155
+ if (!tools?.length)
156
+ return undefined;
157
+ return tools.map((tool) => {
158
+ if (isTool(tool))
159
+ return functionToolSpec(tool);
160
+ const converted = convertToOpenAITool(tool);
161
+ const fn = converted.function;
162
+ if (!fn?.name)
163
+ throw invalid("A tool bound to the Inferlo chat model has no name.", "Bind LangChain tools, { type: \"function\", function: { name, description, parameters } } objects, or Inferlo function tools.");
164
+ return { name: fn.name, description: fn.description ?? "", inputSchema: fn.parameters ?? { type: "object", properties: {} } };
165
+ });
166
+ }
167
+ function toolArgs(input) {
168
+ return input && typeof input === "object" && !Array.isArray(input) ? input : { input };
169
+ }
170
+ function typeOf(message) {
171
+ const m = message;
172
+ return typeof m.getType === "function" ? m.getType() : typeof m._getType === "function" ? m._getType() : String(m.type);
173
+ }
174
+ /** LangChain messages as Inferlo messages. */
175
+ function toMessages(messages) {
176
+ return messages.map((message) => {
177
+ const type = typeOf(message);
178
+ const { text, images } = contentOf(message.content);
179
+ if (type === "system")
180
+ return { role: "system", content: text };
181
+ if (type === "human" || type === "generic")
182
+ return { role: "user", content: text, ...(images.length ? { images } : {}) };
183
+ if (type === "ai") {
184
+ const calls = message.tool_calls ?? [];
185
+ return { role: "assistant", content: text, ...(calls.length ? { toolCalls: calls.map((c) => ({ id: c.id ?? "", name: c.name, input: c.args })) } : {}) };
186
+ }
187
+ if (type === "tool") {
188
+ const tool = message;
189
+ return { role: "tool", content: text, toolCallId: tool.tool_call_id, ...(tool.status === "error" ? { isError: true } : {}) };
190
+ }
191
+ throw invalid(`The Inferlo chat model does not take "${type}" messages.`, "Use system, human, AI and tool messages.");
192
+ });
193
+ }
194
+ function contentOf(content) {
195
+ if (typeof content === "string")
196
+ return { text: content, images: [] };
197
+ const images = [];
198
+ let text = "";
199
+ for (const part of Array.isArray(content) ? content : []) {
200
+ if (!part || typeof part !== "object")
201
+ continue;
202
+ const p = part;
203
+ if (p.type === "text" && typeof p.text === "string")
204
+ text += p.text;
205
+ else if (p.type === "image_url") {
206
+ const url = typeof p.image_url === "string" ? p.image_url : p.image_url?.url;
207
+ if (url)
208
+ images.push({ url });
209
+ }
210
+ else if (p.type === "image") {
211
+ const mediaType = p.mimeType ?? p.mime_type;
212
+ if (typeof p.url === "string")
213
+ images.push({ url: p.url });
214
+ else if (typeof p.data === "string" && mediaType)
215
+ images.push({ base64: p.data, mediaType: mediaType });
216
+ }
217
+ }
218
+ return { text, images };
219
+ }
220
+ //# sourceMappingURL=langchain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langchain.js","sourceRoot":"","sources":["../src/langchain.ts"],"names":[],"mappings":"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"}
package/dist/model.d.ts CHANGED
@@ -4,27 +4,43 @@ export type SystemShape = {
4
4
  createdAt: Schema<Date, Date | string>;
5
5
  updatedAt: Schema<Date, Date | string>;
6
6
  };
7
- export declare class Model<N extends string = string, S extends Shape = Shape> {
7
+ /** Options of model(). */
8
+ export interface ModelOptions {
9
+ /**
10
+ * true: the table belongs to tenants (organisations, workspaces, customers). Every row gets a
11
+ * tenantId column, and ctx.db filters every query by and stamps every insert with the current
12
+ * tenant (auth.tenant(user), default user.tenantId). Unique fields are unique per tenant.
13
+ */
14
+ tenant?: boolean;
15
+ }
16
+ /** Longest tenant id Inferlo accepts. */
17
+ export declare const MAX_TENANT_ID = 200;
18
+ export type TenantShape = {
19
+ tenantId: Schema<string>;
20
+ };
21
+ export declare class Model<N extends string = string, S extends Shape = Shape, T extends boolean = false> {
8
22
  /** Table name, also the property name on `db` (db.tickets). */
9
23
  readonly name: N;
10
24
  /** Fields you defined. */
11
25
  readonly fields: S;
12
- /** Full row schema including id, createdAt and updatedAt. */
13
- readonly row: ObjectSchema<SystemShape & S>;
26
+ /** Full row schema including id, createdAt and updatedAt (and tenantId on tenant-scoped models). */
27
+ readonly row: ObjectSchema<SystemShape & S & (T extends true ? TenantShape : {})>;
28
+ /** True when the model is tenant-scoped (model(name, fields, { tenant: true })). */
29
+ readonly tenant: T;
14
30
  /** Input schema for inserts. Fields with defaults or .optional() may be left out. */
15
31
  readonly create: ObjectSchema<S>;
16
32
  /** Input schema for updates. Every field optional. */
17
33
  readonly update: ObjectSchema<PartialShape<S>>;
18
34
  /** Type-only: the row type. Prefer Row<typeof Model>. */
19
- readonly $row: ShapeOutput<SystemShape & S>;
35
+ readonly $row: ShapeOutput<SystemShape & S & (T extends true ? TenantShape : {})>;
20
36
  readonly $create: ShapeInput<S>;
21
- constructor(name: N, fields: S);
37
+ constructor(name: N, fields: S, options?: ModelOptions);
22
38
  /** Input schema with only some fields, e.g. for a route body: Ticket.pick("title", "body"). */
23
39
  pick<K extends keyof S & string>(...keys: K[]): ObjectSchema<Pick<S, K>>;
24
40
  /** Input schema without some fields, e.g. Ticket.omit("ownerId"). */
25
41
  omit<K extends keyof S & string>(...keys: K[]): ObjectSchema<Omit<S, K>>;
26
42
  }
27
- export type AnyModel = Model<string, any>;
43
+ export type AnyModel = Model<string, any, boolean>;
28
44
  /** Row type of a model: Row<typeof Ticket>. */
29
45
  export type Row<M extends AnyModel> = M["$row"];
30
46
  /** Insert input type of a model. */
@@ -32,5 +48,6 @@ export type CreateInput<M extends AnyModel> = M["$create"];
32
48
  /** Update input type of a model. */
33
49
  export type UpdateInput<M extends AnyModel> = Partial<M["$create"]>;
34
50
  export declare function model<const N extends string, S extends Shape>(name: N, fields: S): Model<N, S>;
51
+ export declare function model<const N extends string, S extends Shape, const O extends ModelOptions>(name: N, fields: S, options: O): Model<N, S, O["tenant"] extends true ? true : false>;
35
52
  /** camelCase field name to snake_case column name. */
36
53
  export declare function columnName(field: string): string;
package/dist/model.js CHANGED
@@ -8,6 +8,10 @@
8
8
  * })
9
9
  *
10
10
  * Every model gets id (uuid), createdAt and updatedAt automatically.
11
+ *
12
+ * Tenant-scoped models (multi-tenant apps) also get tenantId, set from the signed-in user:
13
+ *
14
+ * export const Ticket = model("tickets", { title: t.string() }, { tenant: true })
11
15
  */
12
16
  import { InferloError } from "./errors.js";
13
17
  import { ObjectSchema, Schema, t } from "./schema.js";
@@ -17,24 +21,45 @@ const RESERVED = new Set(["id", "createdAt", "updatedAt"]);
17
21
  function system(schema, kind) {
18
22
  return new Schema({ ...schema.def, system: kind });
19
23
  }
24
+ /** Longest tenant id Inferlo accepts. */
25
+ export const MAX_TENANT_ID = 200;
20
26
  export class Model {
21
27
  /** Table name, also the property name on `db` (db.tickets). */
22
28
  name;
23
29
  /** Fields you defined. */
24
30
  fields;
25
- /** Full row schema including id, createdAt and updatedAt. */
31
+ /** Full row schema including id, createdAt and updatedAt (and tenantId on tenant-scoped models). */
26
32
  row;
33
+ /** True when the model is tenant-scoped (model(name, fields, { tenant: true })). */
34
+ tenant;
27
35
  /** Input schema for inserts. Fields with defaults or .optional() may be left out. */
28
36
  create;
29
37
  /** Input schema for updates. Every field optional. */
30
38
  update;
31
- constructor(name, fields) {
39
+ constructor(name, fields, options = {}) {
32
40
  if (!TABLE_NAME.test(name)) {
33
41
  throw new InferloError("IL4005", `Model name "${name}" is not a valid table name.`, {
34
42
  fix: 'Use lowercase letters, digits and underscores, starting with a letter, e.g. model("support_tickets", {...}).',
35
43
  });
36
44
  }
45
+ if (options === null || typeof options !== "object" || Array.isArray(options)) {
46
+ throw new InferloError("IL4026", `The options of model "${name}" must be an object.`, { fix: `Pass model("${name}", { ...fields }, { tenant: true }), or leave the options out.` });
47
+ }
48
+ for (const key of Object.keys(options)) {
49
+ if (key !== "tenant") {
50
+ throw new InferloError("IL4026", `Unknown option "${key}" in model "${name}".`, { fix: "model() takes one option: { tenant: true }." });
51
+ }
52
+ }
53
+ if (options.tenant !== undefined && typeof options.tenant !== "boolean") {
54
+ throw new InferloError("IL4026", `The tenant option of model "${name}" must be true or false.`, { fix: `Use model("${name}", { ...fields }, { tenant: true }).` });
55
+ }
56
+ const tenant = options.tenant === true;
37
57
  for (const key of Object.keys(fields)) {
58
+ if (tenant && key === "tenantId") {
59
+ throw new InferloError("IL4006", `Model "${name}" defines "tenantId", which Inferlo adds to tenant-scoped models.`, {
60
+ fix: 'Remove "tenantId" from the model. With { tenant: true } every row already has tenantId, set from the current tenant.',
61
+ });
62
+ }
38
63
  if (RESERVED.has(key)) {
39
64
  throw new InferloError("IL4006", `Model "${name}" defines "${key}", which Inferlo adds automatically.`, {
40
65
  fix: `Remove "${key}" from the model. Every model already has id, createdAt and updatedAt.`,
@@ -47,15 +72,19 @@ export class Model {
47
72
  }
48
73
  }
49
74
  this.name = name;
50
- this.fields = fields;
75
+ this.tenant = tenant;
51
76
  this.create = t.object(fields);
52
77
  this.update = this.create.partial();
78
+ // tenantId is a column like the others for the adapters, migrations and describe(), but never input.
79
+ this.fields = (tenant
80
+ ? { ...fields, tenantId: system(t.string().min(1).max(MAX_TENANT_ID).index().describe("Set automatically from the current tenant"), "tenantId") }
81
+ : fields);
53
82
  const systemShape = {
54
83
  id: system(t.uuid(), "id"),
55
84
  createdAt: system(t.date(), "createdAt"),
56
85
  updatedAt: system(t.date(), "updatedAt"),
57
86
  };
58
- this.row = t.object({ ...systemShape, ...fields });
87
+ this.row = t.object({ ...systemShape, ...this.fields });
59
88
  }
60
89
  /** Input schema with only some fields, e.g. for a route body: Ticket.pick("title", "body"). */
61
90
  pick(...keys) {
@@ -66,8 +95,8 @@ export class Model {
66
95
  return this.create.omit(...keys);
67
96
  }
68
97
  }
69
- export function model(name, fields) {
70
- return new Model(name, fields);
98
+ export function model(name, fields, options) {
99
+ return new Model(name, fields, options);
71
100
  }
72
101
  /** camelCase field name to snake_case column name. */
73
102
  export function columnName(field) {
package/dist/model.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
@@ -11,16 +11,18 @@ export interface RateLimit {
11
11
  per: "second" | "minute" | "hour" | "day";
12
12
  /**
13
13
  * Who is counted. "user": each signed-in user (requests without a user count by IP).
14
- * "ip": each client IP address. Default "user".
14
+ * "tenant": each tenant (organisation) in multi-tenant apps, shared by all its users (users without a tenant
15
+ * count one by one, requests without a user by IP). "ip": each client IP address. Default "user".
15
16
  */
16
- by?: "user" | "ip";
17
+ by?: "user" | "tenant" | "ip";
17
18
  }
18
19
  export interface RateLimitConfig {
19
20
  /**
20
21
  * Where counts are kept. "memory" (default): in this process, for one instance and tests.
21
22
  * "database": in the inferlo_rate_limits table of the app's Postgres database, shared by every instance.
23
+ * "redis": in the Redis of createApp({ redis }), shared by every instance.
22
24
  */
23
- store?: "memory" | "database";
25
+ store?: "memory" | "database" | "redis";
24
26
  }
25
27
  /** Counts hits per key in fixed windows. */
26
28
  export interface RateLimitStore {
@@ -14,12 +14,12 @@ export function checkRateLimit(limit, where) {
14
14
  problems.push("max must be a whole number of at least 1");
15
15
  if (!Object.hasOwn(WINDOWS, l.per))
16
16
  problems.push(`per must be one of ${Object.keys(WINDOWS).map((k) => `"${k}"`).join(", ")}`);
17
- if (l.by !== undefined && l.by !== "user" && l.by !== "ip")
18
- problems.push('by must be "user" or "ip"');
17
+ if (l.by !== undefined && l.by !== "user" && l.by !== "tenant" && l.by !== "ip")
18
+ problems.push('by must be "user", "tenant" or "ip"');
19
19
  }
20
20
  if (problems.length) {
21
21
  throw new InferloError("IL6007", `Invalid rateLimit on ${where}: ${problems.join(", ")}.`, {
22
- fix: 'Use rateLimit: { max: 10, per: "minute", by: "user" } (per: "second" | "minute" | "hour" | "day", by: "user" | "ip").',
22
+ fix: 'Use rateLimit: { max: 10, per: "minute", by: "user" } (per: "second" | "minute" | "hour" | "day", by: "user" | "tenant" | "ip").',
23
23
  });
24
24
  }
25
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Events between services over Redis Streams: createApp({ name: "billing", redis, events: { transport: "redis" } }).
3
+ *
4
+ * Keys (shared by every app on the Redis, so services find each other's events):
5
+ * inferlo:events:<event name> a stream with one entry per published event (fields id, payload, publishedAt,
6
+ * and traceparent and tracestate with tracing), trimmed to about maxLength entries
7
+ *
8
+ * Each app reads with a consumer group named after the app (createApp({ name })), so every service subscribed to
9
+ * an event gets each event once, and its instances share the work. An entry is acknowledged (XACK) after its jobs
10
+ * are queued; an entry a crashed instance read but did not acknowledge is claimed again (XAUTOCLAIM) after
11
+ * staleAfterMs. Delivery is at least once; the jobs it queues have ids derived from the event id, so a repeated
12
+ * delivery queues nothing new.
13
+ */
14
+ import type { EventTransport } from "./events.ts";
15
+ import type { RedisClient } from "./redis.ts";
16
+ export declare const EVENT_STREAM_PREFIX = "inferlo:events:";
17
+ export interface RedisEventTransportOptions {
18
+ /** The consumer group: the app name. */
19
+ group: string;
20
+ /** Entries kept per event stream (approximately, trimmed by Redis as events are added). Default 100,000. */
21
+ maxLength?: number;
22
+ /** An entry read but not acknowledged for this long (its instance stopped) is delivered again. Default 30 seconds. */
23
+ staleAfterMs?: number;
24
+ /** Entries read per stream and call. Default 100. */
25
+ batch?: number;
26
+ }
27
+ export declare function redisEventTransport(client: RedisClient, options: RedisEventTransportOptions): EventTransport;