@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.
Files changed (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +130 -2
  3. package/dist/ai/index.d.ts +138 -0
  4. package/dist/ai/index.js +450 -0
  5. package/dist/ai/index.js.map +1 -0
  6. package/dist/ai/providers.d.ts +150 -0
  7. package/dist/ai/providers.js +294 -0
  8. package/dist/ai/providers.js.map +1 -0
  9. package/dist/app.d.ts +109 -0
  10. package/dist/app.js +419 -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 +520 -0
  17. package/dist/cli/main.js.map +1 -0
  18. package/dist/client-ip.d.ts +7 -0
  19. package/dist/client-ip.js +27 -0
  20. package/dist/client-ip.js.map +1 -0
  21. package/dist/cron.d.ts +17 -0
  22. package/dist/cron.js +143 -0
  23. package/dist/cron.js.map +1 -0
  24. package/dist/db/memory.d.ts +2 -0
  25. package/dist/db/memory.js +128 -0
  26. package/dist/db/memory.js.map +1 -0
  27. package/dist/db/migrate.d.ts +87 -0
  28. package/dist/db/migrate.js +471 -0
  29. package/dist/db/migrate.js.map +1 -0
  30. package/dist/db/postgres.d.ts +37 -0
  31. package/dist/db/postgres.js +338 -0
  32. package/dist/db/postgres.js.map +1 -0
  33. package/dist/db/table.d.ts +117 -0
  34. package/dist/db/table.js +274 -0
  35. package/dist/db/table.js.map +1 -0
  36. package/dist/db/types.d.ts +36 -0
  37. package/dist/db/types.js +2 -0
  38. package/dist/db/types.js.map +1 -0
  39. package/dist/describe.d.ts +74 -0
  40. package/dist/describe.js +69 -0
  41. package/dist/describe.js.map +1 -0
  42. package/dist/env.d.ts +19 -0
  43. package/dist/env.js +72 -0
  44. package/dist/env.js.map +1 -0
  45. package/dist/errors.d.ts +40 -0
  46. package/dist/errors.js +99 -0
  47. package/dist/errors.js.map +1 -0
  48. package/dist/index.d.ts +31 -0
  49. package/dist/index.js +20 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/jobs.d.ts +177 -0
  52. package/dist/jobs.js +374 -0
  53. package/dist/jobs.js.map +1 -0
  54. package/dist/mcp.d.ts +22 -0
  55. package/dist/mcp.js +171 -0
  56. package/dist/mcp.js.map +1 -0
  57. package/dist/model.d.ts +36 -0
  58. package/dist/model.js +76 -0
  59. package/dist/model.js.map +1 -0
  60. package/dist/openapi.d.ts +6 -0
  61. package/dist/openapi.js +74 -0
  62. package/dist/openapi.js.map +1 -0
  63. package/dist/rate-limit.d.ts +45 -0
  64. package/dist/rate-limit.js +93 -0
  65. package/dist/rate-limit.js.map +1 -0
  66. package/dist/route.d.ts +131 -0
  67. package/dist/route.js +28 -0
  68. package/dist/route.js.map +1 -0
  69. package/dist/schema.d.ts +164 -0
  70. package/dist/schema.js +442 -0
  71. package/dist/schema.js.map +1 -0
  72. package/dist/serve.d.ts +11 -0
  73. package/dist/serve.js +86 -0
  74. package/dist/serve.js.map +1 -0
  75. package/dist/testing.d.ts +16 -0
  76. package/dist/testing.js +30 -0
  77. package/dist/testing.js.map +1 -0
  78. package/llms.txt +27 -0
  79. package/package.json +82 -4
  80. package/templates/app/AGENTS.md +55 -0
  81. package/templates/app/CLAUDE.md +1 -0
  82. package/templates/app/README.md +16 -0
  83. package/templates/app/_env.example +5 -0
  84. package/templates/app/_gitignore +3 -0
  85. package/templates/app/package.json.tpl +32 -0
  86. package/templates/app/src/app.ts +38 -0
  87. package/templates/app/src/models.ts +31 -0
  88. package/templates/app/src/routes/health.ts +3 -0
  89. package/templates/app/src/routes/notes.ts +56 -0
  90. package/templates/app/src/server.ts +26 -0
  91. package/templates/app/test/notes.test.ts +50 -0
  92. package/templates/app/tsconfig.json +17 -0
package/dist/cron.js ADDED
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Cron: run a job on a schedule. cron("0 * * * *", hourlyReport) enqueues hourlyReport at the start
3
+ * of every hour (UTC) while a worker runs (app.jobs.start() or inferlo worker).
4
+ *
5
+ * A cron schedules a job, so retries, logging and the job queue work the same way. Each tick gets a
6
+ * fixed job id, so with the database queue every instance can run the schedule and the job is
7
+ * still queued once per tick.
8
+ */
9
+ import { InferloError } from "./errors.js";
10
+ const FIELDS = [
11
+ { min: 0, max: 59 },
12
+ { min: 0, max: 23 },
13
+ { min: 1, max: 31 },
14
+ { min: 1, max: 12, names: ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"] },
15
+ { min: 0, max: 7, names: ["sun", "mon", "tue", "wed", "thu", "fri", "sat"] },
16
+ ];
17
+ const FIELD_NAMES = ["minute", "hour", "day of month", "month", "day of week"];
18
+ const FIX = 'Use five fields "minute hour day-of-month month day-of-week" in UTC, for example "0 * * * *" (every hour), "*/15 * * * *" (every 15 minutes) or "30 3 * * 1-5" (03:30 on weekdays).';
19
+ function invalid(schedule, problem) {
20
+ return new InferloError("IL6013", `Invalid cron schedule ${JSON.stringify(schedule)}: ${problem}.`, { fix: FIX });
21
+ }
22
+ function parseValue(text, field, schedule, name) {
23
+ const lower = text.toLowerCase();
24
+ const named = field.names?.indexOf(lower) ?? -1;
25
+ if (named !== -1)
26
+ return named + field.min;
27
+ if (!/^\d+$/.test(text))
28
+ throw invalid(schedule, `"${text}" is not a valid ${name}`);
29
+ const n = Number(text);
30
+ if (n < field.min || n > field.max)
31
+ throw invalid(schedule, `${name} ${n} is outside ${field.min}-${field.max}`);
32
+ return n;
33
+ }
34
+ /** The allowed values of one field, and whether it was "*" (no restriction). */
35
+ function parseField(text, field, schedule, name) {
36
+ const values = new Set();
37
+ for (const part of text.split(",")) {
38
+ const [range, stepText, extra] = part.split("/");
39
+ if (extra !== undefined || range === undefined || range === "")
40
+ throw invalid(schedule, `"${part}" is not a valid ${name}`);
41
+ let step = 1;
42
+ if (stepText !== undefined) {
43
+ if (!/^\d+$/.test(stepText) || Number(stepText) < 1)
44
+ throw invalid(schedule, `step "${stepText}" in the ${name} must be a whole number of at least 1`);
45
+ step = Number(stepText);
46
+ }
47
+ let from;
48
+ let to;
49
+ if (range === "*") {
50
+ from = field.min;
51
+ to = field.max;
52
+ }
53
+ else if (range.includes("-")) {
54
+ const [a, b, more] = range.split("-");
55
+ if (more !== undefined || !a || !b)
56
+ throw invalid(schedule, `"${range}" is not a valid ${name} range`);
57
+ from = parseValue(a, field, schedule, name);
58
+ to = parseValue(b, field, schedule, name);
59
+ if (from > to)
60
+ throw invalid(schedule, `the ${name} range "${range}" goes backwards`);
61
+ }
62
+ else {
63
+ from = parseValue(range, field, schedule, name);
64
+ to = stepText === undefined ? from : field.max;
65
+ }
66
+ for (let v = from; v <= to; v += step)
67
+ values.add(v);
68
+ }
69
+ return { values, any: text === "*" };
70
+ }
71
+ /** Parse a schedule into a function giving the first tick strictly after a time. Raises IL6013. */
72
+ export function parseCron(schedule) {
73
+ if (typeof schedule !== "string")
74
+ throw invalid(schedule, "it must be a string");
75
+ const parts = schedule.trim().split(/\s+/);
76
+ if (parts.length !== 5)
77
+ throw invalid(schedule, `it has ${parts.length} field(s), not 5`);
78
+ const [minute, hour, dom, month, dow] = parts.map((p, i) => parseField(p, FIELDS[i], schedule, FIELD_NAMES[i]));
79
+ if (dow.values.has(7))
80
+ dow.values.add(0); // 7 is Sunday too
81
+ const dayMatches = (d) => {
82
+ const domOk = dom.values.has(d.getUTCDate());
83
+ const dowOk = dow.values.has(d.getUTCDay());
84
+ // Standard cron: when both day fields are restricted, either one matching is enough.
85
+ if (!dom.any && !dow.any)
86
+ return domOk || dowOk;
87
+ return domOk && dowOk;
88
+ };
89
+ return (after) => {
90
+ const t = new Date(after.getTime());
91
+ t.setUTCSeconds(0, 0);
92
+ t.setUTCMinutes(t.getUTCMinutes() + 1);
93
+ // Enough steps to reach any valid tick (February 29 comes every four years, or eight around 2100).
94
+ for (let guard = 0; guard < 366 * 5 * 24 * 2; guard++) {
95
+ if (!month.values.has(t.getUTCMonth() + 1)) {
96
+ t.setUTCMonth(t.getUTCMonth() + 1, 1);
97
+ t.setUTCHours(0, 0, 0, 0);
98
+ }
99
+ else if (!dayMatches(t)) {
100
+ t.setUTCDate(t.getUTCDate() + 1);
101
+ t.setUTCHours(0, 0, 0, 0);
102
+ }
103
+ else if (!hour.values.has(t.getUTCHours())) {
104
+ t.setUTCHours(t.getUTCHours() + 1, 0, 0, 0);
105
+ }
106
+ else if (!minute.values.has(t.getUTCMinutes())) {
107
+ t.setUTCMinutes(t.getUTCMinutes() + 1, 0, 0);
108
+ }
109
+ else
110
+ return t;
111
+ }
112
+ throw invalid(schedule, "it never matches a date");
113
+ };
114
+ }
115
+ /** Run a job on a schedule: export const hourly = cron("0 * * * *", sendReport). Times are UTC. */
116
+ export function cron(schedule, job) {
117
+ const next = parseCron(schedule);
118
+ if (!job || job.kind !== "inferlo.job") {
119
+ throw new InferloError("IL6013", `cron(${JSON.stringify(schedule)}, ...) needs a job as its second argument.`, {
120
+ fix: 'Pass a job: cron("0 * * * *", job("hourly-report", { input: t.object({}) }).handle(async ({ db }) => { ... })).',
121
+ });
122
+ }
123
+ if (!job.options.input.safeParse({}).ok) {
124
+ throw new InferloError("IL6013", `The job "${job.name}" is run by cron with the input {}, but its input schema does not accept {}.`, {
125
+ fix: "Give jobs run by cron the input t.object({}) (or fields with defaults), and read what they need from the database.",
126
+ });
127
+ }
128
+ next(new Date(0)); // a schedule that never matches (such as "0 0 31 2 *") fails here, not in the worker
129
+ return { kind: "inferlo.cron", schedule: schedule.trim().split(/\s+/).join(" "), job, next };
130
+ }
131
+ export function isCron(value) {
132
+ return typeof value === "object" && value !== null && value.kind === "inferlo.cron";
133
+ }
134
+ /** A fixed UUID for one tick of a cron, so every instance queues the same job id. */
135
+ export async function cronTickId(def, tick) {
136
+ const data = new TextEncoder().encode(`inferlo.cron:${def.job.name}:${def.schedule}:${tick.toISOString()}`);
137
+ const bytes = new Uint8Array(await crypto.subtle.digest("SHA-256", data)).slice(0, 16);
138
+ bytes[6] = (bytes[6] & 0x0f) | 0x80; // version 8 (custom)
139
+ bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant
140
+ const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
141
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
142
+ }
143
+ //# sourceMappingURL=cron.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.js","sourceRoot":"","sources":["../src/cron.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Adapter } from "./types.ts";
2
+ export declare function memory(): Adapter;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * In-memory adapter for tests, prototypes and examples. Data is lost when the process exits.
3
+ * Enforces unique fields the same way Postgres does (IL4004, HTTP 409).
4
+ */
5
+ import { InferloError } from "../errors.js";
6
+ function compare(a, b) {
7
+ const x = a instanceof Date ? a.getTime() : a;
8
+ const y = b instanceof Date ? b.getTime() : b;
9
+ if (x === y)
10
+ return 0;
11
+ if (x === null || x === undefined)
12
+ return 1;
13
+ if (y === null || y === undefined)
14
+ return -1;
15
+ return x < y ? -1 : 1;
16
+ }
17
+ function likeToRegex(pattern, flags) {
18
+ const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/%/g, ".*").replace(/_/g, ".");
19
+ return new RegExp(`^${escaped}$`, flags);
20
+ }
21
+ function matches(row, conditions) {
22
+ return conditions.every(({ field, op, value }) => {
23
+ const v = row[field];
24
+ switch (op) {
25
+ case "eq":
26
+ return compare(v, value) === 0 && v !== null && v !== undefined;
27
+ case "ne":
28
+ return v !== null && v !== undefined && compare(v, value) !== 0;
29
+ case "gt":
30
+ return v != null && compare(v, value) > 0;
31
+ case "gte":
32
+ return v != null && compare(v, value) >= 0;
33
+ case "lt":
34
+ return v != null && compare(v, value) < 0;
35
+ case "lte":
36
+ return v != null && compare(v, value) <= 0;
37
+ case "in":
38
+ return value.some((x) => compare(v, x) === 0);
39
+ case "notIn":
40
+ return v != null && !value.some((x) => compare(v, x) === 0);
41
+ case "like":
42
+ return typeof v === "string" && likeToRegex(String(value), "").test(v);
43
+ case "ilike":
44
+ return typeof v === "string" && likeToRegex(String(value), "i").test(v);
45
+ case "isNull":
46
+ return value ? v === null || v === undefined : v !== null && v !== undefined;
47
+ }
48
+ });
49
+ }
50
+ function clone(row) {
51
+ return structuredClone(row);
52
+ }
53
+ export function memory() {
54
+ const tables = new Map();
55
+ const rowsOf = (model) => {
56
+ let rows = tables.get(model.name);
57
+ if (!rows)
58
+ tables.set(model.name, (rows = []));
59
+ return rows;
60
+ };
61
+ const checkUnique = (model, candidate, ignoreId) => {
62
+ for (const [field, schema] of Object.entries(model.fields)) {
63
+ if (!schema.def.unique || candidate[field] == null)
64
+ continue;
65
+ const clash = rowsOf(model).find((r) => r.id !== ignoreId && compare(r[field], candidate[field]) === 0);
66
+ if (clash) {
67
+ throw new InferloError("IL4004", `A ${model.name} row with this ${field} already exists.`, { status: 409, details: { table: model.name, field } });
68
+ }
69
+ }
70
+ };
71
+ return {
72
+ dialect: "memory",
73
+ async insert(model, row) {
74
+ checkUnique(model, row);
75
+ const stored = clone(row);
76
+ for (const key of Object.keys(model.fields))
77
+ if (!(key in stored))
78
+ stored[key] = null;
79
+ rowsOf(model).push(stored);
80
+ return clone(stored);
81
+ },
82
+ async select(model, query) {
83
+ let rows = rowsOf(model).filter((r) => matches(r, query.where));
84
+ if (query.orderBy.length) {
85
+ rows = [...rows].sort((a, b) => {
86
+ for (const [field, dir] of query.orderBy) {
87
+ const c = compare(a[field], b[field]);
88
+ if (c !== 0)
89
+ return dir === "asc" ? c : -c;
90
+ }
91
+ return 0;
92
+ });
93
+ }
94
+ const start = query.offset ?? 0;
95
+ return rows.slice(start, query.limit === undefined ? undefined : start + query.limit).map(clone);
96
+ },
97
+ async update(model, where, patch) {
98
+ const out = [];
99
+ for (const row of rowsOf(model)) {
100
+ if (!matches(row, where))
101
+ continue;
102
+ checkUnique(model, { ...row, ...patch }, row.id);
103
+ Object.assign(row, clone(patch));
104
+ out.push(clone(row));
105
+ }
106
+ return out;
107
+ },
108
+ async delete(model, where) {
109
+ const rows = rowsOf(model);
110
+ const keep = rows.filter((r) => !matches(r, where));
111
+ const removed = rows.length - keep.length;
112
+ tables.set(model.name, keep);
113
+ return removed;
114
+ },
115
+ async count(model, where) {
116
+ return rowsOf(model).filter((r) => matches(r, where)).length;
117
+ },
118
+ async sync(models) {
119
+ for (const m of models)
120
+ rowsOf(m);
121
+ return [];
122
+ },
123
+ async close() {
124
+ tables.clear();
125
+ },
126
+ };
127
+ }
128
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/db/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import { type AnyModel } from "../model.ts";
2
+ import type { DbRecord } from "./types.ts";
3
+ /** One column in migrations/snapshot.json. Compared field by field to find column changes. */
4
+ export interface MigrationSnapshotColumn {
5
+ /** Postgres type, e.g. "text", "varchar(80)", "integer", "jsonb". */
6
+ type: string;
7
+ /** NOT NULL (required fields). */
8
+ notNull: boolean;
9
+ /** SQL DEFAULT expression, e.g. "0", "'open'", "now()". Absent when there is no fixed default. */
10
+ default?: string;
11
+ /** Allowed values of a t.enum field (CHECK constraint). */
12
+ enum?: string[];
13
+ /** Foreign key of a t.ref field. */
14
+ references?: {
15
+ table: string;
16
+ onDelete: "restrict" | "cascade" | "set null";
17
+ };
18
+ /** Only the "id" column. */
19
+ primaryKey?: true;
20
+ }
21
+ /** The models as of the last generated migration. Stored as migrations/snapshot.json. */
22
+ export interface MigrationSnapshot {
23
+ inferlo: 2;
24
+ tables: Record<string, {
25
+ columns: Record<string, MigrationSnapshotColumn>;
26
+ indexes: Record<string, string>;
27
+ }>;
28
+ }
29
+ /** The snapshot format written by Inferlo 0.2.0 (each column as its SQL definition). planMigration upgrades it. */
30
+ export interface MigrationSnapshotV1 {
31
+ inferlo: 1;
32
+ tables: Record<string, {
33
+ columns: Record<string, string>;
34
+ indexes: Record<string, string>;
35
+ }>;
36
+ }
37
+ export interface MigrationPlan {
38
+ /** SQL statements to put in the new migration file, in order. Empty when nothing changed. */
39
+ statements: string[];
40
+ /** Snapshot to save after writing the file. */
41
+ snapshot: MigrationSnapshot;
42
+ /** The drops included in `statements`, e.g. "drop column tasks.notes". Empty unless allowDrop was set. */
43
+ drops: string[];
44
+ /** The column changes included in `statements`, e.g. "change column tasks.done (default false -> none)". Empty unless allowChange was set. */
45
+ changes: string[];
46
+ }
47
+ export interface PlanMigrationOptions {
48
+ /** Generate DROP statements for removed tables, columns and indexes. These delete data. Default false. */
49
+ allowDrop?: boolean;
50
+ /**
51
+ * Generate type, default, required/optional and enum value changes of existing columns (ALTER
52
+ * COLUMN ... TYPE, SET DEFAULT, DROP DEFAULT, SET NOT NULL, DROP NOT NULL, and replacing the enum's
53
+ * CHECK constraint). Changing the type fails at apply time (IL4022) if an existing value does not
54
+ * convert. Making a column required fails at apply time (IL4020) if rows still have NULL in it,
55
+ * unless the field has a fixed default, which fills them. Removing an enum value fails at apply
56
+ * time (IL4021) if rows still use it. Default false.
57
+ */
58
+ allowChange?: boolean;
59
+ }
60
+ export interface Migration {
61
+ /** File name without .sql, e.g. "0001_init". Sorted by name to decide the order. */
62
+ name: string;
63
+ sql: string;
64
+ }
65
+ /** SQL to bring the database from `previous` (or an empty database) to `models`. */
66
+ export declare function planMigration(models: readonly AnyModel[], previous?: MigrationSnapshot | MigrationSnapshotV1, options?: PlanMigrationOptions): MigrationPlan;
67
+ interface SqlDb {
68
+ $sql(text: string, params?: unknown[]): Promise<DbRecord[]>;
69
+ $transaction<T>(fn: (tx: SqlDb) => Promise<T>): Promise<T>;
70
+ }
71
+ export interface ApplyMigrationsOptions {
72
+ /**
73
+ * Called with the names of migrations that were already applied but whose SQL has changed since
74
+ * (IL4018). They are not run again. Restore the applied SQL and put the change in a new file.
75
+ */
76
+ onEdited?: (names: string[]) => void;
77
+ }
78
+ /**
79
+ * Run the migrations that are not yet recorded in the "inferlo_migrations" table, in name order,
80
+ * each in its own transaction. Returns the names it applied. Safe to run from several processes
81
+ * at once (a Postgres advisory lock serialises them).
82
+ *
83
+ * Each applied migration is recorded with a checksum of its SQL. Applied migrations whose SQL has
84
+ * changed since are reported to options.onEdited (IL4018) and are not run again.
85
+ */
86
+ export declare function applyMigrations(db: SqlDb, migrations: readonly Migration[], options?: ApplyMigrationsOptions): Promise<string[]>;
87
+ export {};