@browserlessapi/inferlo 0.0.0-stage → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +130 -2
- package/dist/ai/index.d.ts +138 -0
- package/dist/ai/index.js +450 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/providers.d.ts +150 -0
- package/dist/ai/providers.js +294 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/app.d.ts +109 -0
- package/dist/app.js +419 -0
- package/dist/app.js.map +1 -0
- package/dist/auth.d.ts +29 -0
- package/dist/auth.js +61 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +520 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/client-ip.d.ts +7 -0
- package/dist/client-ip.js +27 -0
- package/dist/client-ip.js.map +1 -0
- package/dist/cron.d.ts +17 -0
- package/dist/cron.js +143 -0
- package/dist/cron.js.map +1 -0
- package/dist/db/memory.d.ts +2 -0
- package/dist/db/memory.js +128 -0
- package/dist/db/memory.js.map +1 -0
- package/dist/db/migrate.d.ts +87 -0
- package/dist/db/migrate.js +471 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/postgres.d.ts +37 -0
- package/dist/db/postgres.js +338 -0
- package/dist/db/postgres.js.map +1 -0
- package/dist/db/table.d.ts +117 -0
- package/dist/db/table.js +274 -0
- package/dist/db/table.js.map +1 -0
- package/dist/db/types.d.ts +36 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/describe.d.ts +74 -0
- package/dist/describe.js +69 -0
- package/dist/describe.js.map +1 -0
- package/dist/env.d.ts +19 -0
- package/dist/env.js +72 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.js +99 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs.d.ts +177 -0
- package/dist/jobs.js +374 -0
- package/dist/jobs.js.map +1 -0
- package/dist/mcp.d.ts +22 -0
- package/dist/mcp.js +171 -0
- package/dist/mcp.js.map +1 -0
- package/dist/model.d.ts +36 -0
- package/dist/model.js +76 -0
- package/dist/model.js.map +1 -0
- package/dist/openapi.d.ts +6 -0
- package/dist/openapi.js +74 -0
- package/dist/openapi.js.map +1 -0
- package/dist/rate-limit.d.ts +45 -0
- package/dist/rate-limit.js +93 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/route.d.ts +131 -0
- package/dist/route.js +28 -0
- package/dist/route.js.map +1 -0
- package/dist/schema.d.ts +164 -0
- package/dist/schema.js +442 -0
- package/dist/schema.js.map +1 -0
- package/dist/serve.d.ts +11 -0
- package/dist/serve.js +86 -0
- package/dist/serve.js.map +1 -0
- package/dist/testing.d.ts +16 -0
- package/dist/testing.js +30 -0
- package/dist/testing.js.map +1 -0
- package/llms.txt +27 -0
- package/package.json +82 -4
- package/templates/app/AGENTS.md +55 -0
- package/templates/app/CLAUDE.md +1 -0
- package/templates/app/README.md +16 -0
- package/templates/app/_env.example +5 -0
- package/templates/app/_gitignore +3 -0
- package/templates/app/package.json.tpl +32 -0
- package/templates/app/src/app.ts +38 -0
- package/templates/app/src/models.ts +31 -0
- package/templates/app/src/routes/health.ts +3 -0
- package/templates/app/src/routes/notes.ts +56 -0
- package/templates/app/src/server.ts +26 -0
- package/templates/app/test/notes.test.ts +50 -0
- package/templates/app/tsconfig.json +17 -0
package/dist/db/table.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed table clients: db.tickets.insert(...), db.tickets.findMany({ where: { status: "open" } }).
|
|
3
|
+
* Inserts and updates are always validated against the model, and every query is parameterised.
|
|
4
|
+
*/
|
|
5
|
+
import { InferloError, didYouMean, notFound } from "../errors.js";
|
|
6
|
+
import { ValidationError } from "../schema.js";
|
|
7
|
+
const OPS = ["eq", "ne", "gt", "gte", "lt", "lte", "in", "notIn", "like", "ilike", "isNull"];
|
|
8
|
+
const DEFAULT_LIMIT = 100;
|
|
9
|
+
const MAX_LIMIT = 1000;
|
|
10
|
+
export class Table {
|
|
11
|
+
model;
|
|
12
|
+
#adapter;
|
|
13
|
+
#models;
|
|
14
|
+
constructor(model, adapter, models = [model]) {
|
|
15
|
+
this.model = model;
|
|
16
|
+
this.#adapter = adapter;
|
|
17
|
+
this.#models = models;
|
|
18
|
+
}
|
|
19
|
+
get #fields() {
|
|
20
|
+
return ["id", "createdAt", "updatedAt", ...Object.keys(this.model.fields)];
|
|
21
|
+
}
|
|
22
|
+
/** Validate and insert one row. Returns the stored row. */
|
|
23
|
+
async insert(data) {
|
|
24
|
+
const parsed = this.#validate(this.model.create, data, "insert");
|
|
25
|
+
const now = new Date();
|
|
26
|
+
const row = { id: crypto.randomUUID(), createdAt: now, updatedAt: now, ...parsed };
|
|
27
|
+
return (await this.#adapter().insert(this.model, row));
|
|
28
|
+
}
|
|
29
|
+
async insertMany(items) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const item of items)
|
|
32
|
+
out.push(await this.insert(item));
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/** Row by id, or null. */
|
|
36
|
+
async find(id, options = {}) {
|
|
37
|
+
const relations = this.#relations(options.include);
|
|
38
|
+
const rows = await this.#adapter().select(this.model, { where: [{ field: "id", op: "eq", value: id }], orderBy: [], limit: 1 });
|
|
39
|
+
await this.#load(rows, relations);
|
|
40
|
+
return rows[0] ?? null;
|
|
41
|
+
}
|
|
42
|
+
/** Row by id. Throws IL4001 (HTTP 404) when it does not exist. */
|
|
43
|
+
async get(id, options = {}) {
|
|
44
|
+
const row = await this.find(id, options);
|
|
45
|
+
if (!row)
|
|
46
|
+
throw notFound(`${singular(this.model.name)} ${id} was not found.`, { table: this.model.name, id });
|
|
47
|
+
return row;
|
|
48
|
+
}
|
|
49
|
+
/** First row matching where, or null. */
|
|
50
|
+
async findOne(where, options = {}) {
|
|
51
|
+
const rows = await this.findMany({ where, limit: 1, include: options.include });
|
|
52
|
+
return rows[0] ?? null;
|
|
53
|
+
}
|
|
54
|
+
/** Rows matching where. include: { owner: true } loads related rows with one extra query per relation. */
|
|
55
|
+
async findMany(options = {}) {
|
|
56
|
+
const relations = this.#relations(options.include);
|
|
57
|
+
const rows = await this.#adapter().select(this.model, this.#query(options));
|
|
58
|
+
await this.#load(rows, relations);
|
|
59
|
+
return rows;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Relations of this model. "one": a t.ref field <name>Id of this model (owner for ownerId).
|
|
63
|
+
* "many": a t.ref field <name>Id of another model that points here (tickets for tickets.ownerId,
|
|
64
|
+
* or ticketsByOwner when tickets has several such fields).
|
|
65
|
+
*/
|
|
66
|
+
#available() {
|
|
67
|
+
const eligible = (m) => Object.entries(m.fields).filter(([field, schema]) => schema.def.kind === "ref" && field.length > 2 && field.endsWith("Id") && !(field.slice(0, -2) in m.fields));
|
|
68
|
+
const forward = [];
|
|
69
|
+
for (const [field, schema] of eligible(this.model)) {
|
|
70
|
+
const target = this.#models.find((m) => m.name === schema.def.refTable);
|
|
71
|
+
forward.push({ kind: "one", name: field.slice(0, -2), field, table: schema.def.refTable, target });
|
|
72
|
+
}
|
|
73
|
+
const taken = new Set([...this.#fields, ...forward.map((r) => r.name)]);
|
|
74
|
+
const reverse = [];
|
|
75
|
+
for (const m of this.#models) {
|
|
76
|
+
const fields = eligible(m).filter(([, schema]) => schema.def.refTable === this.model.name);
|
|
77
|
+
for (const [field] of fields) {
|
|
78
|
+
const relation = field.slice(0, -2);
|
|
79
|
+
const name = fields.length === 1 ? m.name : `${m.name}By${relation.charAt(0).toUpperCase()}${relation.slice(1)}`;
|
|
80
|
+
if (!taken.has(name))
|
|
81
|
+
reverse.push({ kind: "many", name, field, table: m.name, target: m });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return [...forward, ...reverse];
|
|
85
|
+
}
|
|
86
|
+
/** The included relations. Unknown names raise IL4023. */
|
|
87
|
+
#relations(include) {
|
|
88
|
+
if (!include)
|
|
89
|
+
return [];
|
|
90
|
+
const available = this.#available();
|
|
91
|
+
const out = [];
|
|
92
|
+
for (const [name, wanted] of Object.entries(include)) {
|
|
93
|
+
if (wanted === undefined || wanted === false)
|
|
94
|
+
continue;
|
|
95
|
+
const relation = available.find((r) => r.name === name);
|
|
96
|
+
if (!relation || wanted !== true) {
|
|
97
|
+
const names = available.map((r) => r.name);
|
|
98
|
+
const ambiguous = available.filter((r) => r.kind === "many" && r.table === name);
|
|
99
|
+
throw new InferloError("IL4023", relation
|
|
100
|
+
? `include.${name} must be true or false.`
|
|
101
|
+
: ambiguous.length
|
|
102
|
+
? `"${name}" has several t.ref fields to "${this.model.name}", so include.${name} is ambiguous.`
|
|
103
|
+
: `"${this.model.name}" has no relation "${name}".${didYouMean(name, names)}`, {
|
|
104
|
+
fix: ambiguous.length
|
|
105
|
+
? `Name the field: ${ambiguous.map((r) => `${r.name} (${name}.${r.field})`).join(", ")}. Use include: { ${ambiguous[0].name}: true }.`
|
|
106
|
+
: names.length
|
|
107
|
+
? `Relations of "${this.model.name}": ${available.map(describeRelation).join(", ")}. Use include: { ${names[0]}: true }.`
|
|
108
|
+
: `"${this.model.name}" has no relations. Add a t.ref field named <name>Id, e.g. ownerId: t.ref("users"), to include owner; models that reference "${this.model.name}" that way can be included by their table name.`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (!relation.target)
|
|
112
|
+
throw new InferloError("IL6005", `${this.model.name}.${relation.field} references "${relation.table}", which is not a registered model.`);
|
|
113
|
+
out.push(relation);
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
/** One query per relation: every referenced id at once, never one query per row. */
|
|
118
|
+
async #load(rows, relations) {
|
|
119
|
+
for (const relation of relations) {
|
|
120
|
+
const target = relation.target;
|
|
121
|
+
if (relation.kind === "many") {
|
|
122
|
+
const ids = [...new Set(rows.map((row) => row.id))];
|
|
123
|
+
const related = ids.length
|
|
124
|
+
? await this.#adapter().select(target, { where: [{ field: relation.field, op: "in", value: ids }], orderBy: [["createdAt", "asc"], ["id", "asc"]] })
|
|
125
|
+
: [];
|
|
126
|
+
const byParent = new Map();
|
|
127
|
+
for (const r of related) {
|
|
128
|
+
const list = byParent.get(r[relation.field]);
|
|
129
|
+
if (list)
|
|
130
|
+
list.push(r);
|
|
131
|
+
else
|
|
132
|
+
byParent.set(r[relation.field], [r]);
|
|
133
|
+
}
|
|
134
|
+
for (const row of rows)
|
|
135
|
+
row[relation.name] = byParent.get(row.id) ?? [];
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const ids = [...new Set(rows.map((row) => row[relation.field]).filter((id) => typeof id === "string"))];
|
|
139
|
+
const related = ids.length
|
|
140
|
+
? await this.#adapter().select(target, { where: [{ field: "id", op: "in", value: ids }], orderBy: [], limit: ids.length })
|
|
141
|
+
: [];
|
|
142
|
+
const byId = new Map(related.map((r) => [r.id, r]));
|
|
143
|
+
for (const row of rows)
|
|
144
|
+
row[relation.name] = (typeof row[relation.field] === "string" ? byId.get(row[relation.field]) : undefined) ?? null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async count(where = {}) {
|
|
148
|
+
return this.#adapter().count(this.model, this.#where(where));
|
|
149
|
+
}
|
|
150
|
+
/** Validate and update one row by id. Throws IL4001 (HTTP 404) when it does not exist. */
|
|
151
|
+
async update(id, patch) {
|
|
152
|
+
const parsed = this.#validate(this.model.update, patch, "update");
|
|
153
|
+
const rows = await this.#adapter().update(this.model, [{ field: "id", op: "eq", value: id }], { ...parsed, updatedAt: new Date() });
|
|
154
|
+
if (!rows[0])
|
|
155
|
+
throw notFound(`${singular(this.model.name)} ${id} was not found.`, { table: this.model.name, id });
|
|
156
|
+
return rows[0];
|
|
157
|
+
}
|
|
158
|
+
/** Update every row matching where. Returns the updated rows. */
|
|
159
|
+
async updateMany(where, patch) {
|
|
160
|
+
const conditions = this.#where(where);
|
|
161
|
+
const parsed = this.#validate(this.model.update, patch, "update");
|
|
162
|
+
return (await this.#adapter().update(this.model, conditions, { ...parsed, updatedAt: new Date() }));
|
|
163
|
+
}
|
|
164
|
+
/** Delete by id. Returns true if a row was deleted. */
|
|
165
|
+
async delete(id) {
|
|
166
|
+
return (await this.#adapter().delete(this.model, [{ field: "id", op: "eq", value: id }])) > 0;
|
|
167
|
+
}
|
|
168
|
+
/** Delete every row matching where. Refuses an empty where to prevent accidental wipes. */
|
|
169
|
+
async deleteMany(where) {
|
|
170
|
+
const conditions = this.#where(where);
|
|
171
|
+
if (!conditions.length) {
|
|
172
|
+
throw new InferloError("IL4007", `deleteMany() on "${this.model.name}" needs a where filter.`, {
|
|
173
|
+
fix: "Pass a filter, e.g. deleteMany({ status: \"closed\" }). To delete everything use deleteMany({ id: { isNull: false } }).",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return this.#adapter().delete(this.model, conditions);
|
|
177
|
+
}
|
|
178
|
+
#validate(schema, data, action) {
|
|
179
|
+
const result = schema.safeParse(data);
|
|
180
|
+
if (!result.ok)
|
|
181
|
+
throw new ValidationError(result.issues, `${singular(this.model.name)} ${action}`);
|
|
182
|
+
return result.value;
|
|
183
|
+
}
|
|
184
|
+
#checkField(field, where) {
|
|
185
|
+
if (!this.#fields.includes(field)) {
|
|
186
|
+
throw new InferloError("IL4003", `Unknown field "${field}" in ${where} on "${this.model.name}".${didYouMean(field, this.#fields)}`, {
|
|
187
|
+
fix: `Use one of: ${this.#fields.join(", ")}`,
|
|
188
|
+
status: 500,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
#where(where = {}) {
|
|
193
|
+
const out = [];
|
|
194
|
+
for (const [field, value] of Object.entries(where)) {
|
|
195
|
+
if (value === undefined)
|
|
196
|
+
continue;
|
|
197
|
+
this.#checkField(field, "where");
|
|
198
|
+
if (value !== null && typeof value === "object" && !(value instanceof Date) && !Array.isArray(value)) {
|
|
199
|
+
for (const [op, operand] of Object.entries(value)) {
|
|
200
|
+
if (operand === undefined)
|
|
201
|
+
continue;
|
|
202
|
+
if (!OPS.includes(op)) {
|
|
203
|
+
throw new InferloError("IL4003", `Unknown operator "${op}" for "${field}".${didYouMean(op, OPS)}`, {
|
|
204
|
+
fix: `Operators: ${OPS.join(", ")}`,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
out.push({ field, op: op, value: operand });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else if (value === null) {
|
|
211
|
+
out.push({ field, op: "isNull", value: true });
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
out.push({ field, op: "eq", value });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
#query(options) {
|
|
220
|
+
const orderBy = [];
|
|
221
|
+
const raw = options.orderBy;
|
|
222
|
+
const entries = Array.isArray(raw) ? raw : Object.entries(raw ?? {});
|
|
223
|
+
for (const [field, direction] of entries) {
|
|
224
|
+
this.#checkField(field, "orderBy");
|
|
225
|
+
if (direction !== "asc" && direction !== "desc") {
|
|
226
|
+
throw new InferloError("IL4003", `orderBy direction for "${field}" must be "asc" or "desc".`);
|
|
227
|
+
}
|
|
228
|
+
orderBy.push([field, direction]);
|
|
229
|
+
}
|
|
230
|
+
const limit = Math.min(Math.max(0, Math.floor(options.limit ?? DEFAULT_LIMIT)), MAX_LIMIT);
|
|
231
|
+
const offset = Math.max(0, Math.floor(options.offset ?? 0));
|
|
232
|
+
return { where: this.#where(options.where), orderBy, limit, offset };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function describeRelation(r) {
|
|
236
|
+
return r.kind === "one" ? `${r.name} (${r.field})` : `${r.name} (${r.table}.${r.field})`;
|
|
237
|
+
}
|
|
238
|
+
function singular(name) {
|
|
239
|
+
const word = name.endsWith("ies") ? name.slice(0, -3) + "y" : name.endsWith("s") ? name.slice(0, -1) : name;
|
|
240
|
+
return word.charAt(0).toUpperCase() + word.slice(1).replace(/_/g, " ");
|
|
241
|
+
}
|
|
242
|
+
export function createDb(models, adapter) {
|
|
243
|
+
const build = (current) => {
|
|
244
|
+
const db = {};
|
|
245
|
+
for (const m of models)
|
|
246
|
+
db[m.name] = new Table(m, () => current, models);
|
|
247
|
+
const helpers = {
|
|
248
|
+
$adapter: current,
|
|
249
|
+
$sync: (options) => current.sync([...models], options),
|
|
250
|
+
$transaction: async (fn) => (current.transaction ? current.transaction((tx) => fn(build(tx))) : fn(build(current))),
|
|
251
|
+
$sql: async (text, params) => {
|
|
252
|
+
if (!current.sql)
|
|
253
|
+
throw new InferloError("IL4008", `Raw SQL is not supported by the ${current.dialect} adapter.`, { fix: "Use postgres() from @browserlessapi/inferlo/postgres." });
|
|
254
|
+
return current.sql(text, params);
|
|
255
|
+
},
|
|
256
|
+
$close: async () => current.close?.(),
|
|
257
|
+
};
|
|
258
|
+
Object.assign(db, helpers);
|
|
259
|
+
return new Proxy(db, {
|
|
260
|
+
get(target, prop) {
|
|
261
|
+
if (typeof prop === "string" && !(prop in target) && !prop.startsWith("$") && prop !== "then" && prop !== "toJSON") {
|
|
262
|
+
const names = models.map((m) => m.name);
|
|
263
|
+
throw new InferloError("IL4002", `db.${prop} does not exist.${didYouMean(prop, names)}`, {
|
|
264
|
+
fix: `Registered tables: ${names.join(", ") || "(none)"}. Add the model to createApp({ models: [...] }).`,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
return Reflect.get(target, prop);
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
};
|
|
271
|
+
adapter.connect?.([...models]);
|
|
272
|
+
return build(adapter);
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/db/table.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AnyModel } from "../model.ts";
|
|
2
|
+
export type Op = "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "like" | "ilike" | "isNull";
|
|
3
|
+
export interface Condition {
|
|
4
|
+
field: string;
|
|
5
|
+
op: Op;
|
|
6
|
+
value: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface Query {
|
|
9
|
+
where: Condition[];
|
|
10
|
+
orderBy: [field: string, direction: "asc" | "desc"][];
|
|
11
|
+
limit?: number;
|
|
12
|
+
offset?: number;
|
|
13
|
+
}
|
|
14
|
+
export type DbRecord = Record<string, unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Storage backend. Inferlo ships memory() and postgres(). Adapters receive validated,
|
|
17
|
+
* already-normalised data with camelCase field names.
|
|
18
|
+
*/
|
|
19
|
+
export interface Adapter {
|
|
20
|
+
readonly dialect: string;
|
|
21
|
+
connect?(models: AnyModel[]): Promise<void> | void;
|
|
22
|
+
insert(model: AnyModel, row: DbRecord): Promise<DbRecord>;
|
|
23
|
+
select(model: AnyModel, query: Query): Promise<DbRecord[]>;
|
|
24
|
+
update(model: AnyModel, where: Condition[], patch: DbRecord): Promise<DbRecord[]>;
|
|
25
|
+
delete(model: AnyModel, where: Condition[]): Promise<number>;
|
|
26
|
+
count(model: AnyModel, where: Condition[]): Promise<number>;
|
|
27
|
+
/** Create missing tables, columns and indexes. Returns the statements it ran (or would run). */
|
|
28
|
+
sync(models: AnyModel[], options?: {
|
|
29
|
+
dryRun?: boolean;
|
|
30
|
+
}): Promise<string[]>;
|
|
31
|
+
/** Run fn inside a transaction, passing an adapter bound to it. */
|
|
32
|
+
transaction?<T>(fn: (tx: Adapter) => Promise<T>): Promise<T>;
|
|
33
|
+
/** Raw parameterised SQL (Postgres only). */
|
|
34
|
+
sql?(text: string, params?: unknown[]): Promise<DbRecord[]>;
|
|
35
|
+
close?(): Promise<void>;
|
|
36
|
+
}
|
package/dist/db/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/db/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* describe() returns a machine-readable map of the whole app. AI coding agents read it
|
|
3
|
+
* (inferlo describe --json) instead of searching the codebase.
|
|
4
|
+
*/
|
|
5
|
+
import type { App } from "./app.ts";
|
|
6
|
+
import type { JSONSchema } from "./schema.ts";
|
|
7
|
+
export interface FieldDescription {
|
|
8
|
+
type: string;
|
|
9
|
+
required: boolean;
|
|
10
|
+
nullable: boolean;
|
|
11
|
+
default?: unknown;
|
|
12
|
+
unique?: boolean;
|
|
13
|
+
index?: boolean;
|
|
14
|
+
references?: string;
|
|
15
|
+
values?: readonly unknown[];
|
|
16
|
+
column: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AppDescription {
|
|
20
|
+
inferlo: string;
|
|
21
|
+
name: string;
|
|
22
|
+
version: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
database: string;
|
|
25
|
+
auth: boolean;
|
|
26
|
+
endpoints: {
|
|
27
|
+
openapi: string | false;
|
|
28
|
+
mcp: string | false;
|
|
29
|
+
};
|
|
30
|
+
models: {
|
|
31
|
+
name: string;
|
|
32
|
+
fields: Record<string, FieldDescription>;
|
|
33
|
+
}[];
|
|
34
|
+
routes: {
|
|
35
|
+
name?: string;
|
|
36
|
+
method: string;
|
|
37
|
+
path: string;
|
|
38
|
+
auth: string;
|
|
39
|
+
summary?: string;
|
|
40
|
+
tool?: string;
|
|
41
|
+
rateLimit?: {
|
|
42
|
+
max: number;
|
|
43
|
+
per: string;
|
|
44
|
+
by: string;
|
|
45
|
+
};
|
|
46
|
+
params?: JSONSchema;
|
|
47
|
+
query?: JSONSchema;
|
|
48
|
+
body?: JSONSchema;
|
|
49
|
+
}[];
|
|
50
|
+
ai: {
|
|
51
|
+
configured: boolean;
|
|
52
|
+
aliases: Record<string, string[]>;
|
|
53
|
+
};
|
|
54
|
+
jobs: {
|
|
55
|
+
name: string;
|
|
56
|
+
summary?: string;
|
|
57
|
+
retries: number;
|
|
58
|
+
input: JSONSchema;
|
|
59
|
+
}[];
|
|
60
|
+
/** Schedules from cron(schedule, job), in UTC. */
|
|
61
|
+
crons: {
|
|
62
|
+
schedule: string;
|
|
63
|
+
job: string;
|
|
64
|
+
}[];
|
|
65
|
+
/** Where queued jobs are kept. */
|
|
66
|
+
jobQueue: "memory" | "database";
|
|
67
|
+
}
|
|
68
|
+
export declare const INFERLO_VERSION = "0.4.0";
|
|
69
|
+
export declare function describeApp(app: App<any>, options: {
|
|
70
|
+
auth: boolean;
|
|
71
|
+
openapi: string | false;
|
|
72
|
+
mcp: string | false;
|
|
73
|
+
description?: string;
|
|
74
|
+
}): AppDescription;
|
package/dist/describe.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { toolName } from "./mcp.js";
|
|
2
|
+
import { columnName } from "./model.js";
|
|
3
|
+
export const INFERLO_VERSION = "0.4.0";
|
|
4
|
+
function field(name, schema) {
|
|
5
|
+
const d = schema.def;
|
|
6
|
+
const out = {
|
|
7
|
+
type: d.kind,
|
|
8
|
+
required: !d.optional && !d.hasDefault,
|
|
9
|
+
nullable: d.nullable,
|
|
10
|
+
column: columnName(name),
|
|
11
|
+
};
|
|
12
|
+
if (d.hasDefault)
|
|
13
|
+
out.default = typeof d.defaultValue === "function" ? "(function)" : d.defaultValue;
|
|
14
|
+
if (d.unique)
|
|
15
|
+
out.unique = true;
|
|
16
|
+
if (d.index)
|
|
17
|
+
out.index = true;
|
|
18
|
+
if (d.refTable)
|
|
19
|
+
out.references = d.refTable;
|
|
20
|
+
if (d.values && d.kind === "enum")
|
|
21
|
+
out.values = d.values;
|
|
22
|
+
if (d.description)
|
|
23
|
+
out.description = d.description;
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
export function describeApp(app, options) {
|
|
27
|
+
return {
|
|
28
|
+
inferlo: INFERLO_VERSION,
|
|
29
|
+
name: app.name,
|
|
30
|
+
version: app.version,
|
|
31
|
+
description: options.description,
|
|
32
|
+
database: app.db.$adapter.dialect,
|
|
33
|
+
auth: options.auth,
|
|
34
|
+
endpoints: { openapi: options.openapi, mcp: options.mcp },
|
|
35
|
+
models: app.models.map((m) => ({
|
|
36
|
+
name: m.name,
|
|
37
|
+
fields: Object.fromEntries([
|
|
38
|
+
["id", { type: "uuid", required: false, nullable: false, column: "id", description: "Set automatically" }],
|
|
39
|
+
...Object.entries(m.fields).map(([k, s]) => [k, field(k, s)]),
|
|
40
|
+
["createdAt", { type: "date", required: false, nullable: false, column: "created_at", description: "Set automatically" }],
|
|
41
|
+
["updatedAt", { type: "date", required: false, nullable: false, column: "updated_at", description: "Set automatically" }],
|
|
42
|
+
]),
|
|
43
|
+
})),
|
|
44
|
+
routes: app.routes.map((r) => {
|
|
45
|
+
const o = r.options;
|
|
46
|
+
const out = { method: r.method, path: r.path, auth: o.auth ?? "user" };
|
|
47
|
+
if (r.name)
|
|
48
|
+
out.name = r.name;
|
|
49
|
+
if (o.summary)
|
|
50
|
+
out.summary = o.summary;
|
|
51
|
+
if (o.tool)
|
|
52
|
+
out.tool = toolName(r);
|
|
53
|
+
if (o.rateLimit)
|
|
54
|
+
out.rateLimit = { max: o.rateLimit.max, per: o.rateLimit.per, by: o.rateLimit.by ?? "user" };
|
|
55
|
+
if (o.params)
|
|
56
|
+
out.params = o.params.toJSONSchema();
|
|
57
|
+
if (o.query)
|
|
58
|
+
out.query = o.query.toJSONSchema();
|
|
59
|
+
if (o.body)
|
|
60
|
+
out.body = o.body.toJSONSchema();
|
|
61
|
+
return out;
|
|
62
|
+
}),
|
|
63
|
+
ai: { configured: app.ai.configured, aliases: app.ai.aliases },
|
|
64
|
+
jobQueue: app.jobs.queue,
|
|
65
|
+
crons: app.jobs.crons.map((c) => ({ schedule: c.schedule, job: c.job.name })),
|
|
66
|
+
jobs: app.jobs.list.map((j) => ({ name: j.name, ...(j.options.summary ? { summary: j.options.summary } : {}), retries: j.options.retries ?? 3, input: j.options.input.toJSONSchema() })),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=describe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Use a fixed set of variables (tests, Cloudflare Workers bindings). */
|
|
2
|
+
export declare function setEnv(values: Record<string, string | undefined> | undefined): void;
|
|
3
|
+
interface EnvFn {
|
|
4
|
+
(name: string): string;
|
|
5
|
+
(name: string, options: {
|
|
6
|
+
default: string;
|
|
7
|
+
}): string;
|
|
8
|
+
(name: string, options: {
|
|
9
|
+
optional: true;
|
|
10
|
+
}): string | undefined;
|
|
11
|
+
int(name: string, options?: {
|
|
12
|
+
default?: number;
|
|
13
|
+
}): number;
|
|
14
|
+
bool(name: string, options?: {
|
|
15
|
+
default?: boolean;
|
|
16
|
+
}): boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare const env: EnvFn;
|
|
19
|
+
export {};
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read environment variables on Node, Bun, Deno and Workers, with clear errors.
|
|
3
|
+
*
|
|
4
|
+
* env("DATABASE_URL") // required string
|
|
5
|
+
* env("PORT", { default: "3000" }) // optional with default
|
|
6
|
+
* env.int("PORT", { default: 3000 })
|
|
7
|
+
* env.bool("DEBUG", { default: false })
|
|
8
|
+
*/
|
|
9
|
+
import { InferloError } from "./errors.js";
|
|
10
|
+
let overrides;
|
|
11
|
+
/** Use a fixed set of variables (tests, Cloudflare Workers bindings). */
|
|
12
|
+
export function setEnv(values) {
|
|
13
|
+
overrides = values;
|
|
14
|
+
}
|
|
15
|
+
function read(name) {
|
|
16
|
+
if (overrides && name in overrides)
|
|
17
|
+
return overrides[name];
|
|
18
|
+
const g = globalThis;
|
|
19
|
+
if (g.process?.env)
|
|
20
|
+
return g.process.env[name];
|
|
21
|
+
if (g.Deno) {
|
|
22
|
+
try {
|
|
23
|
+
return g.Deno.env.get(name);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
function missing(name) {
|
|
32
|
+
return new InferloError("IL7001", `Environment variable ${name} is not set.`, {
|
|
33
|
+
fix: `Set ${name} in your environment or .env file, or pass a default: env("${name}", { default: "..." }).`,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export const env = Object.assign((name, options = {}) => {
|
|
37
|
+
const value = read(name);
|
|
38
|
+
if (value !== undefined && value !== "")
|
|
39
|
+
return value;
|
|
40
|
+
if (options.default !== undefined)
|
|
41
|
+
return options.default;
|
|
42
|
+
if (options.optional)
|
|
43
|
+
return undefined;
|
|
44
|
+
throw missing(name);
|
|
45
|
+
}, {
|
|
46
|
+
int(name, options = {}) {
|
|
47
|
+
const value = read(name);
|
|
48
|
+
if (value === undefined || value === "") {
|
|
49
|
+
if (options.default !== undefined)
|
|
50
|
+
return options.default;
|
|
51
|
+
throw missing(name);
|
|
52
|
+
}
|
|
53
|
+
const n = Number(value);
|
|
54
|
+
if (!Number.isInteger(n))
|
|
55
|
+
throw new InferloError("IL7002", `Environment variable ${name} must be a whole number, got "${value}".`);
|
|
56
|
+
return n;
|
|
57
|
+
},
|
|
58
|
+
bool(name, options = {}) {
|
|
59
|
+
const value = read(name)?.toLowerCase();
|
|
60
|
+
if (value === undefined || value === "") {
|
|
61
|
+
if (options.default !== undefined)
|
|
62
|
+
return options.default;
|
|
63
|
+
throw missing(name);
|
|
64
|
+
}
|
|
65
|
+
if (["1", "true", "yes", "on"].includes(value))
|
|
66
|
+
return true;
|
|
67
|
+
if (["0", "false", "no", "off"].includes(value))
|
|
68
|
+
return false;
|
|
69
|
+
throw new InferloError("IL7002", `Environment variable ${name} must be true or false, got "${value}".`);
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every error Inferlo raises has a stable code, a plain cause, a suggested fix and a docs link.
|
|
3
|
+
* Error codes never change meaning once released, so AI models and humans can rely on them.
|
|
4
|
+
*/
|
|
5
|
+
export declare const DOCS_BASE = "https://github.com/BrowserlessAPI/Inferlo/blob/main/docs/errors.md";
|
|
6
|
+
export declare function docsUrl(code: string): string;
|
|
7
|
+
export interface InferloErrorOptions {
|
|
8
|
+
status?: number;
|
|
9
|
+
fix?: string;
|
|
10
|
+
details?: unknown;
|
|
11
|
+
cause?: unknown;
|
|
12
|
+
/** Set to false to hide the message from API clients (it is still logged). */
|
|
13
|
+
expose?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare class InferloError extends Error {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
readonly status: number;
|
|
18
|
+
readonly fix: string | undefined;
|
|
19
|
+
readonly details: unknown;
|
|
20
|
+
readonly expose: boolean;
|
|
21
|
+
constructor(code: string, message: string, options?: InferloErrorOptions);
|
|
22
|
+
get docs(): string;
|
|
23
|
+
toJSON(): {
|
|
24
|
+
error: Record<string, unknown>;
|
|
25
|
+
};
|
|
26
|
+
/** Multi-line text for terminals and logs. */
|
|
27
|
+
format(): string;
|
|
28
|
+
}
|
|
29
|
+
/** Throw from a handler to return an HTTP error with your own code and message. */
|
|
30
|
+
export declare function httpError(status: number, message: string, options?: {
|
|
31
|
+
code?: string;
|
|
32
|
+
fix?: string;
|
|
33
|
+
details?: unknown;
|
|
34
|
+
}): InferloError;
|
|
35
|
+
export declare function notFound(message?: string, details?: unknown): InferloError;
|
|
36
|
+
export declare function forbidden(message?: string): InferloError;
|
|
37
|
+
export declare function badRequest(message: string, details?: unknown): InferloError;
|
|
38
|
+
/** Closest candidate by edit distance, used for "did you mean" hints. */
|
|
39
|
+
export declare function suggest(input: string, candidates: Iterable<string>): string | undefined;
|
|
40
|
+
export declare function didYouMean(input: string, candidates: Iterable<string>): string;
|