@shaferllc/keel 0.66.0 → 0.74.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 (239) hide show
  1. package/AGENTS.md +169 -0
  2. package/README.md +44 -6
  3. package/bin/keel-mcp.mjs +9 -0
  4. package/dist/api/api.config.stub +9 -0
  5. package/dist/api/config.d.ts +13 -0
  6. package/dist/api/config.js +14 -0
  7. package/dist/api/index.d.ts +16 -0
  8. package/dist/api/index.js +13 -0
  9. package/dist/api/provider.d.ts +10 -0
  10. package/dist/api/provider.js +17 -0
  11. package/dist/api/query.d.ts +35 -0
  12. package/dist/api/query.js +42 -0
  13. package/dist/api/resource.d.ts +91 -0
  14. package/dist/api/resource.js +188 -0
  15. package/dist/core/application.d.ts +5 -5
  16. package/dist/core/application.js +8 -2
  17. package/dist/core/cache.d.ts +81 -5
  18. package/dist/core/cache.js +188 -23
  19. package/dist/core/cli/stubs.d.ts +26 -0
  20. package/dist/core/cli/stubs.js +225 -0
  21. package/dist/core/console-prompt.d.ts +79 -0
  22. package/dist/core/console-prompt.js +239 -0
  23. package/dist/core/console-ui.d.ts +96 -0
  24. package/dist/core/console-ui.js +187 -0
  25. package/dist/core/console.d.ts +188 -0
  26. package/dist/core/console.js +395 -0
  27. package/dist/core/database.d.ts +70 -1
  28. package/dist/core/database.js +174 -15
  29. package/dist/core/env.d.ts +96 -0
  30. package/dist/core/env.js +140 -0
  31. package/dist/core/events.d.ts +129 -5
  32. package/dist/core/events.js +165 -7
  33. package/dist/core/health.d.ts +141 -0
  34. package/dist/core/health.js +226 -0
  35. package/dist/core/helpers.d.ts +9 -3
  36. package/dist/core/helpers.js +11 -3
  37. package/dist/core/http/kernel.d.ts +2 -0
  38. package/dist/core/http/kernel.js +48 -0
  39. package/dist/core/http/router.d.ts +5 -5
  40. package/dist/core/http/router.js +5 -5
  41. package/dist/core/i18n.d.ts +162 -0
  42. package/dist/core/i18n.js +472 -0
  43. package/dist/core/index.d.ts +39 -13
  44. package/dist/core/index.js +19 -6
  45. package/dist/core/instrumentation.d.ts +113 -0
  46. package/dist/core/instrumentation.js +52 -0
  47. package/dist/core/lock.d.ts +139 -0
  48. package/dist/core/lock.js +215 -0
  49. package/dist/core/logger.d.ts +89 -4
  50. package/dist/core/logger.js +167 -22
  51. package/dist/core/mail.d.ts +128 -7
  52. package/dist/core/mail.js +264 -16
  53. package/dist/core/notification.js +10 -1
  54. package/dist/core/package.d.ts +120 -0
  55. package/dist/core/package.js +169 -0
  56. package/dist/core/pages.d.ts +108 -0
  57. package/dist/core/pages.js +199 -0
  58. package/dist/core/queue.d.ts +134 -9
  59. package/dist/core/queue.js +325 -14
  60. package/dist/core/repl.d.ts +33 -0
  61. package/dist/core/repl.js +88 -0
  62. package/dist/core/scheduler.js +6 -0
  63. package/dist/core/social.d.ts +4 -4
  64. package/dist/core/social.js +4 -4
  65. package/dist/core/storage.d.ts +159 -6
  66. package/dist/core/storage.js +299 -7
  67. package/dist/core/telemetry.d.ts +208 -0
  68. package/dist/core/telemetry.js +383 -0
  69. package/dist/core/template.d.ts +2 -3
  70. package/dist/core/template.js +2 -3
  71. package/dist/core/testing.d.ts +170 -1
  72. package/dist/core/testing.js +504 -2
  73. package/dist/db/d1.js +13 -0
  74. package/dist/db/pg.d.ts +13 -0
  75. package/dist/db/pg.js +46 -4
  76. package/dist/mcp/server.d.ts +19 -0
  77. package/dist/mcp/server.js +355 -0
  78. package/dist/openapi/config.d.ts +28 -0
  79. package/dist/openapi/config.js +25 -0
  80. package/dist/openapi/doc.d.ts +40 -0
  81. package/dist/openapi/doc.js +20 -0
  82. package/dist/openapi/export.d.ts +8 -0
  83. package/dist/openapi/export.js +19 -0
  84. package/dist/openapi/gate.d.ts +15 -0
  85. package/dist/openapi/gate.js +27 -0
  86. package/dist/openapi/index.d.ts +19 -0
  87. package/dist/openapi/index.js +15 -0
  88. package/dist/openapi/openapi.config.stub +29 -0
  89. package/dist/openapi/provider.d.ts +18 -0
  90. package/dist/openapi/provider.js +35 -0
  91. package/dist/openapi/routes.d.ts +9 -0
  92. package/dist/openapi/routes.js +23 -0
  93. package/dist/openapi/spec.d.ts +23 -0
  94. package/dist/openapi/spec.js +132 -0
  95. package/dist/openapi/ui.d.ts +8 -0
  96. package/dist/openapi/ui.js +31 -0
  97. package/dist/openapi/zod.d.ts +12 -0
  98. package/dist/openapi/zod.js +46 -0
  99. package/dist/watch/config.d.ts +33 -0
  100. package/dist/watch/config.js +38 -0
  101. package/dist/watch/entry.d.ts +53 -0
  102. package/dist/watch/entry.js +105 -0
  103. package/dist/watch/gate.d.ts +20 -0
  104. package/dist/watch/gate.js +32 -0
  105. package/dist/watch/index.d.ts +21 -0
  106. package/dist/watch/index.js +17 -0
  107. package/dist/watch/migration.d.ts +7 -0
  108. package/dist/watch/migration.js +20 -0
  109. package/dist/watch/provider.d.ts +22 -0
  110. package/dist/watch/provider.js +58 -0
  111. package/dist/watch/prune.d.ts +11 -0
  112. package/dist/watch/prune.js +20 -0
  113. package/dist/watch/recorder.d.ts +24 -0
  114. package/dist/watch/recorder.js +39 -0
  115. package/dist/watch/routes.d.ts +13 -0
  116. package/dist/watch/routes.js +55 -0
  117. package/dist/watch/store.d.ts +54 -0
  118. package/dist/watch/store.js +158 -0
  119. package/dist/watch/ui/dist/watch.css +1 -0
  120. package/dist/watch/ui/dist/watch.js +555 -0
  121. package/dist/watch/ui-shell.d.ts +12 -0
  122. package/dist/watch/ui-shell.js +24 -0
  123. package/dist/watch/watch.config.stub +47 -0
  124. package/dist/watch/watchers.d.ts +12 -0
  125. package/dist/watch/watchers.js +156 -0
  126. package/docs/ai-manifest.json +3206 -0
  127. package/docs/ai.md +128 -0
  128. package/docs/api-resources.md +118 -0
  129. package/docs/architecture.md +331 -0
  130. package/docs/authentication.md +453 -0
  131. package/docs/authorization.md +167 -0
  132. package/docs/broadcasting.md +137 -0
  133. package/docs/broker.md +500 -0
  134. package/docs/cache.md +558 -0
  135. package/docs/configuration.md +385 -0
  136. package/docs/console.md +536 -0
  137. package/docs/container.md +467 -0
  138. package/docs/controllers.md +265 -0
  139. package/docs/cors.md +51 -0
  140. package/docs/database.md +631 -0
  141. package/docs/debugging.md +129 -0
  142. package/docs/decorators.md +127 -0
  143. package/docs/errors.md +395 -0
  144. package/docs/events.md +496 -0
  145. package/docs/examples/architecture-app.ts +27 -0
  146. package/docs/examples/authentication.ts +61 -0
  147. package/docs/examples/authorization.ts +79 -0
  148. package/docs/examples/broadcasting.ts +60 -0
  149. package/docs/examples/broker-cache-validate.ts +34 -0
  150. package/docs/examples/broker-fault-tolerance.ts +29 -0
  151. package/docs/examples/broker-middleware.ts +27 -0
  152. package/docs/examples/broker.ts +203 -0
  153. package/docs/examples/cache.ts +222 -0
  154. package/docs/examples/configuration.ts +121 -0
  155. package/docs/examples/console.ts +134 -0
  156. package/docs/examples/container.ts +134 -0
  157. package/docs/examples/controllers.ts +86 -0
  158. package/docs/examples/database.ts +208 -0
  159. package/docs/examples/debugging.ts +41 -0
  160. package/docs/examples/decorators.ts +40 -0
  161. package/docs/examples/errors.ts +121 -0
  162. package/docs/examples/events.ts +204 -0
  163. package/docs/examples/factories.ts +84 -0
  164. package/docs/examples/hashing.ts +71 -0
  165. package/docs/examples/health.ts +94 -0
  166. package/docs/examples/helpers.ts +171 -0
  167. package/docs/examples/hooks.ts +54 -0
  168. package/docs/examples/i18n.ts +117 -0
  169. package/docs/examples/inertia.ts +81 -0
  170. package/docs/examples/locks.ts +120 -0
  171. package/docs/examples/logger.ts +166 -0
  172. package/docs/examples/mail.ts +263 -0
  173. package/docs/examples/middleware.ts +119 -0
  174. package/docs/examples/migrations.ts +126 -0
  175. package/docs/examples/models.ts +239 -0
  176. package/docs/examples/notification.ts +124 -0
  177. package/docs/examples/pages.ts +82 -0
  178. package/docs/examples/providers.ts +123 -0
  179. package/docs/examples/queues.ts +254 -0
  180. package/docs/examples/rate-limiting.ts +42 -0
  181. package/docs/examples/redis.ts +99 -0
  182. package/docs/examples/request-response.ts +197 -0
  183. package/docs/examples/routing.ts +186 -0
  184. package/docs/examples/scheduling.ts +62 -0
  185. package/docs/examples/sessions.ts +102 -0
  186. package/docs/examples/static-files.ts +63 -0
  187. package/docs/examples/storage.ts +132 -0
  188. package/docs/examples/telemetry.ts +127 -0
  189. package/docs/examples/templates.ts +58 -0
  190. package/docs/examples/testing.ts +215 -0
  191. package/docs/examples/transformer.ts +141 -0
  192. package/docs/examples/transformers.ts +49 -0
  193. package/docs/examples/url-builder.ts +86 -0
  194. package/docs/examples/validation.ts +102 -0
  195. package/docs/examples/views.tsx +62 -0
  196. package/docs/examples/vite.ts +106 -0
  197. package/docs/factories.md +166 -0
  198. package/docs/getting-started.md +290 -0
  199. package/docs/hashing.md +259 -0
  200. package/docs/health.md +225 -0
  201. package/docs/helpers.md +347 -0
  202. package/docs/hono.md +186 -0
  203. package/docs/hooks.md +118 -0
  204. package/docs/i18n.md +302 -0
  205. package/docs/inertia.md +241 -0
  206. package/docs/locks.md +323 -0
  207. package/docs/logger.md +436 -0
  208. package/docs/mail.md +751 -0
  209. package/docs/middleware.md +425 -0
  210. package/docs/migrations.md +476 -0
  211. package/docs/models.md +810 -0
  212. package/docs/notifications.md +474 -0
  213. package/docs/openapi.md +111 -0
  214. package/docs/packages.md +118 -0
  215. package/docs/pages.md +217 -0
  216. package/docs/providers.md +363 -0
  217. package/docs/queues.md +679 -0
  218. package/docs/rate-limiting.md +155 -0
  219. package/docs/redis.md +178 -0
  220. package/docs/request-response.md +953 -0
  221. package/docs/routing.md +804 -0
  222. package/docs/scheduling.md +110 -0
  223. package/docs/security.md +85 -0
  224. package/docs/sessions.md +354 -0
  225. package/docs/social-auth.md +174 -0
  226. package/docs/static-files.md +211 -0
  227. package/docs/storage.md +452 -0
  228. package/docs/telemetry.md +263 -0
  229. package/docs/templates.md +314 -0
  230. package/docs/testing.md +376 -0
  231. package/docs/transformers.md +381 -0
  232. package/docs/url-builder.md +295 -0
  233. package/docs/validation.md +288 -0
  234. package/docs/views.md +267 -0
  235. package/docs/vite.md +434 -0
  236. package/docs/watch.md +118 -0
  237. package/llms-full.txt +19816 -0
  238. package/llms.txt +127 -0
  239. package/package.json +42 -7
@@ -0,0 +1,476 @@
1
+ # Migrations
2
+
3
+ Version your database schema. A migration is a `{ name, up, down }` object; a
4
+ fluent **schema builder** describes tables, and the **migrator** runs them
5
+ against your [connection](./database.md), tracking what's applied. The SQL is
6
+ dialect-aware (sqlite / mysql / postgres) and the core imports no driver.
7
+
8
+ ## Define migrations
9
+
10
+ ```ts
11
+ import type { Migration } from "@shaferllc/keel/core";
12
+
13
+ export const migrations: Migration[] = [
14
+ {
15
+ name: "01_create_users",
16
+ up: (schema) =>
17
+ schema.createTable("users", (t) => {
18
+ t.id();
19
+ t.string("email").unique();
20
+ t.string("name");
21
+ t.boolean("active").default(true);
22
+ t.timestamps(); // created_at + updated_at
23
+ }),
24
+ down: (schema) => schema.dropTable("users"),
25
+ },
26
+ ];
27
+ ```
28
+
29
+ A migration's `name` is its identity — the migrator records it verbatim in the
30
+ bookkeeping table and skips it on re-runs. Keep names stable and ordered (an
31
+ `NN_` prefix sorts them); the migrator runs the array in the order you give it.
32
+ `up`/`down` may be sync or async (`void | Promise<void>`) — return the
33
+ `schema.createTable(...)` promise, or `await` several statements.
34
+
35
+ ### Column types
36
+
37
+ `t.id()` · `t.string(name, length?)` · `t.text(name)` · `t.integer(name)` ·
38
+ `t.bigInteger(name)` · `t.boolean(name)` · `t.timestamp(name)` · `t.json(name)` ·
39
+ `t.timestamps()`.
40
+
41
+ Every column method except `timestamps()` returns a [`Column`](#column) you can
42
+ chain modifiers on: `.nullable()`, `.unique()`, `.default(value)`. `timestamps()`
43
+ returns `void` — it adds nullable `created_at` and `updated_at` for you, so
44
+ there's nothing to chain.
45
+
46
+ ```ts
47
+ schema.createTable("posts", (t) => {
48
+ t.id();
49
+ t.integer("user_id");
50
+ t.string("slug", 120).unique();
51
+ t.text("body").nullable();
52
+ t.json("meta").nullable();
53
+ t.boolean("published").default(false);
54
+ t.timestamps();
55
+ });
56
+ ```
57
+
58
+ Columns are emitted in the order you declare them. `t.id()` is special: it maps
59
+ to the dialect's auto-increment primary key (`SERIAL PRIMARY KEY`,
60
+ `INT AUTO_INCREMENT PRIMARY KEY`, or `INTEGER PRIMARY KEY AUTOINCREMENT`) and is
61
+ never marked `NOT NULL` — modifiers on it are redundant.
62
+
63
+ ### Defaults and nullability
64
+
65
+ By default every column is `NOT NULL`; `.nullable()` drops that. `.default(v)`
66
+ renders the literal inline: strings are single-quoted, booleans become `1`/`0`
67
+ on sqlite and `true`/`false` elsewhere, numbers pass through. Because the default
68
+ is inlined (not a binding), keep it to dev-authored constants.
69
+
70
+ ```ts
71
+ t.string("role").default("member"); // ... DEFAULT 'member'
72
+ t.boolean("active").default(true); // sqlite: DEFAULT 1, else DEFAULT true
73
+ t.integer("retries").default(0); // ... DEFAULT 0
74
+ ```
75
+
76
+ For anything the builder doesn't cover — indexes, foreign keys, an `ALTER
77
+ TABLE` — `schema.raw(sql, bindings?)` runs arbitrary SQL:
78
+
79
+ ```ts
80
+ up: (schema) =>
81
+ schema.raw("CREATE INDEX idx_posts_user ON posts (user_id)"),
82
+ ```
83
+
84
+ > `raw()` writes through the connection **without** placeholder conversion, so
85
+ > its `?` markers are not rewritten to `$1, $2` on the `postgres` dialect
86
+ > (unlike the migrator's own bookkeeping writes). On Postgres, prefer `$n`
87
+ > placeholders — or no bindings — in `raw()`.
88
+
89
+ ## Run and roll back
90
+
91
+ ```ts
92
+ import { Migrator } from "@shaferllc/keel/core";
93
+
94
+ const migrator = new Migrator(connection, "postgres");
95
+
96
+ await migrator.up(migrations); // runs pending migrations (idempotent)
97
+ await migrator.down(migrations); // rolls back the last batch
98
+ await migrator.ran(); // names already applied
99
+ ```
100
+
101
+ `up()` records each applied migration in a `migrations` table
102
+ (`name` PRIMARY KEY, `batch`), so re-running only applies new ones. Every
103
+ migration applied in a single `up()` call shares one batch number — the previous
104
+ max plus one. `down()` reverses just the most recent batch, in reverse
105
+ declaration order, calling each migration's `down()`.
106
+
107
+ Both `up()` and `down()` return the list of names they touched, so you can report
108
+ progress:
109
+
110
+ ```ts
111
+ const applied = await migrator.up(migrations); // ["02_add_posts"]
112
+ const rolled = await migrator.down(migrations); // ["02_add_posts"]
113
+ ```
114
+
115
+ The bookkeeping table is created on demand — `up()`, `down()`, and `ran()` each
116
+ ensure `migrations` exists before touching it, so a fresh database Just Works.
117
+
118
+ ### Edge cases
119
+
120
+ - **Nothing pending:** `up()` returns `[]` and writes nothing new.
121
+ - **Nothing to roll back:** `down()` returns `[]` when no batch exists.
122
+ - **A recorded migration missing from the array:** `down()` still deletes its
123
+ bookkeeping row but has no `down()` to call, so the schema change is *not*
124
+ reversed — keep old migrations in the array until they're fully retired.
125
+ - **Dialect default:** the `Migrator` constructor defaults to `"sqlite"` if you
126
+ omit the second argument.
127
+
128
+ ## Wiring a console command
129
+
130
+ Migrations are usually driven from your app's console. Load your migration files
131
+ and call the migrator:
132
+
133
+ ```ts
134
+ // bin/console.ts
135
+ program.command("migrate").action(async () => {
136
+ const applied = await new Migrator(connection, dialect).up(migrations);
137
+ console.log(applied.length ? `Ran: ${applied.join(", ")}` : "Nothing to migrate.");
138
+ });
139
+ ```
140
+
141
+ ## Dialect notes
142
+
143
+ The builder emits the right primary-key syntax per dialect —
144
+ `SERIAL`/`INTEGER PRIMARY KEY AUTOINCREMENT`/`INT AUTO_INCREMENT` — and maps
145
+ `boolean`/`timestamp`/`json` to each dialect's types (`BOOLEAN` vs `INTEGER`,
146
+ `TIMESTAMP` vs `DATETIME`, `JSONB` vs `TEXT`). Pass the dialect that matches your
147
+ connection — it must be the same one you gave [`setConnection`](./database.md).
148
+
149
+ ---
150
+
151
+ ## API reference
152
+
153
+ ### `Migrator`
154
+
155
+ Runs migrations against a [`Connection`](./database.md#connection) and tracks
156
+ what's applied in a `migrations` table. You construct it directly.
157
+
158
+ #### `new Migrator(conn, dialect?)`
159
+
160
+ `new Migrator(conn: Connection, dialect?: Dialect)`
161
+
162
+ Creates a migrator bound to a connection and dialect (default `"sqlite"`).
163
+
164
+ ```ts
165
+ const migrator = new Migrator(connection, "postgres");
166
+ ```
167
+
168
+ **Notes:** the dialect drives both the generated DDL and the `?`→`$n` rewrite of
169
+ the migrator's own bookkeeping writes. It should match the connection you
170
+ registered with `setConnection`.
171
+
172
+ #### `up(migrations)`
173
+
174
+ `up(migrations: Migration[]): Promise<string[]>`
175
+
176
+ Runs every migration not yet recorded, in array order, under one new batch;
177
+ returns the names applied.
178
+
179
+ ```ts
180
+ const applied = await migrator.up(migrations);
181
+ ```
182
+
183
+ **Notes:** idempotent — already-run migrations (matched by `name`) are skipped.
184
+ Ensures the `migrations` table exists first. Not wrapped in a transaction: if one
185
+ migration throws, earlier ones in the same call stay applied.
186
+
187
+ #### `down(migrations)`
188
+
189
+ `down(migrations: Migration[]): Promise<string[]>`
190
+
191
+ Rolls back the most recent batch, calling each migration's `down()` in reverse
192
+ order; returns the names rolled back.
193
+
194
+ ```ts
195
+ const rolled = await migrator.down(migrations);
196
+ ```
197
+
198
+ **Notes:** returns `[]` when there's no batch to reverse. A recorded name absent
199
+ from `migrations` has its bookkeeping row deleted but no `down()` invoked, so its
200
+ schema change is not undone.
201
+
202
+ #### `ran()`
203
+
204
+ `ran(): Promise<string[]>`
205
+
206
+ Returns the names of all migrations already applied.
207
+
208
+ ```ts
209
+ const names = await migrator.ran();
210
+ const pending = migrations.filter((m) => !names.includes(m.name));
211
+ ```
212
+
213
+ **Notes:** ensures the `migrations` table exists first, so it's safe to call on a
214
+ brand-new database (returns `[]`).
215
+
216
+ ### `SchemaBuilder`
217
+
218
+ The object passed to a migration's `up`/`down`. **You don't construct it in
219
+ migrations** — the migrator creates one and hands it to your callbacks — though
220
+ it is exported and constructible (`new SchemaBuilder(conn, dialect)`) for
221
+ one-off scripts.
222
+
223
+ #### `createTable(name, build)`
224
+
225
+ `createTable(name: string, build: (table: TableBuilder) => void): Promise<void>`
226
+
227
+ Creates a table, using the `build` callback to describe its columns via a
228
+ [`TableBuilder`](#tablebuilder).
229
+
230
+ ```ts
231
+ await schema.createTable("users", (t) => {
232
+ t.id();
233
+ t.string("email").unique();
234
+ t.timestamps();
235
+ });
236
+ ```
237
+
238
+ **Notes:** emits a single `CREATE TABLE` — it does not add `IF NOT EXISTS`, so
239
+ re-creating an existing table errors at the driver. Columns appear in declaration
240
+ order.
241
+
242
+ #### `dropTable(name)`
243
+
244
+ `dropTable(name: string): Promise<void>`
245
+
246
+ Drops a table if it exists.
247
+
248
+ ```ts
249
+ await schema.dropTable("users");
250
+ ```
251
+
252
+ **Notes:** uses `DROP TABLE IF EXISTS`, so it's safe to run when the table is
253
+ already gone — the typical `down()` for a `createTable`.
254
+
255
+ #### `raw(sql, bindings?)`
256
+
257
+ `raw(sql: string, bindings?: unknown[]): Promise<void>`
258
+
259
+ Runs arbitrary SQL through the connection — the escape hatch for indexes, foreign
260
+ keys, and `ALTER TABLE`.
261
+
262
+ ```ts
263
+ await schema.raw("CREATE INDEX idx_posts_user ON posts (user_id)");
264
+ await schema.raw("UPDATE users SET active = ? WHERE active IS NULL", [true]);
265
+ ```
266
+
267
+ **Notes:** `bindings` defaults to `[]`. Unlike the migrator's bookkeeping writes,
268
+ `raw()` does **not** rewrite `?` to `$n`, so pass `$1, $2, …` yourself on the
269
+ `postgres` dialect.
270
+
271
+ ### `TableBuilder`
272
+
273
+ Describes a table's columns. **You get one from the `createTable` callback** — it
274
+ is not constructed in migrations. Each column method (except `timestamps`) returns
275
+ a [`Column`](#column) for chaining modifiers.
276
+
277
+ #### `id(name?)`
278
+
279
+ `id(name?: string): Column`
280
+
281
+ Adds an auto-increment primary-key column (default name `"id"`).
282
+
283
+ ```ts
284
+ t.id(); // "id"
285
+ t.id("uuid"); // custom name
286
+ ```
287
+
288
+ **Notes:** maps to `SERIAL PRIMARY KEY` (postgres), `INT AUTO_INCREMENT PRIMARY
289
+ KEY` (mysql), or `INTEGER PRIMARY KEY AUTOINCREMENT` (sqlite). Never emitted as
290
+ `NOT NULL`; chaining modifiers on it is redundant.
291
+
292
+ #### `string(name, length?)`
293
+
294
+ `string(name: string, length?: number): Column`
295
+
296
+ Adds a `VARCHAR(length)` column (default length `255`).
297
+
298
+ ```ts
299
+ t.string("email");
300
+ t.string("slug", 120);
301
+ ```
302
+
303
+ #### `text(name)`
304
+
305
+ `text(name: string): Column`
306
+
307
+ Adds a `TEXT` column (unbounded string).
308
+
309
+ ```ts
310
+ t.text("body");
311
+ ```
312
+
313
+ #### `integer(name)` / `bigInteger(name)`
314
+
315
+ `integer(name: string): Column`
316
+ `bigInteger(name: string): Column`
317
+
318
+ Add an `INTEGER` / `BIGINT` column.
319
+
320
+ ```ts
321
+ t.integer("user_id");
322
+ t.bigInteger("view_count");
323
+ ```
324
+
325
+ #### `boolean(name)`
326
+
327
+ `boolean(name: string): Column`
328
+
329
+ Adds a boolean column — `BOOLEAN` on mysql/postgres, `INTEGER` on sqlite.
330
+
331
+ ```ts
332
+ t.boolean("active").default(true);
333
+ ```
334
+
335
+ #### `timestamp(name)`
336
+
337
+ `timestamp(name: string): Column`
338
+
339
+ Adds a timestamp column — `TIMESTAMP` on mysql/postgres, `DATETIME` on sqlite.
340
+
341
+ ```ts
342
+ t.timestamp("published_at").nullable();
343
+ ```
344
+
345
+ #### `json(name)`
346
+
347
+ `json(name: string): Column`
348
+
349
+ Adds a JSON column — `JSONB` on postgres, `TEXT` elsewhere.
350
+
351
+ ```ts
352
+ t.json("meta").nullable();
353
+ ```
354
+
355
+ **Notes:** on sqlite/mysql the value is stored as text; serialize/deserialize in
356
+ your app or [`Model`](./models.md) layer.
357
+
358
+ #### `timestamps()`
359
+
360
+ `timestamps(): void`
361
+
362
+ Adds nullable `created_at` and `updated_at` timestamp columns.
363
+
364
+ ```ts
365
+ t.timestamps();
366
+ ```
367
+
368
+ **Notes:** returns `void`, not a `Column` — there's nothing to chain. Both
369
+ columns are `nullable()`.
370
+
371
+ #### `toCreateSql(table, dialect)`
372
+
373
+ `toCreateSql(table: string, dialect: Dialect): string`
374
+
375
+ Renders the accumulated columns into a `CREATE TABLE` statement. Called
376
+ internally by `SchemaBuilder.createTable`; useful directly only if you're
377
+ generating DDL by hand.
378
+
379
+ ```ts
380
+ const t = new TableBuilder();
381
+ t.id();
382
+ t.string("email");
383
+ t.toCreateSql("users", "postgres");
384
+ // CREATE TABLE users (id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL)
385
+ ```
386
+
387
+ #### `columns`
388
+
389
+ `readonly columns: Column[]`
390
+
391
+ The `Column` instances added so far, in declaration order. Read-only inspection
392
+ seam; you rarely touch it.
393
+
394
+ ### `Column`
395
+
396
+ A single column definition. **You get one from a `TableBuilder` method** (`t.string(...)` etc.) — you don't construct it in migrations. Modifier methods
397
+ return `this`, so they chain.
398
+
399
+ #### `nullable()`
400
+
401
+ `nullable(): this`
402
+
403
+ Marks the column nullable (drops the default `NOT NULL`).
404
+
405
+ ```ts
406
+ t.text("bio").nullable();
407
+ ```
408
+
409
+ #### `unique()`
410
+
411
+ `unique(): this`
412
+
413
+ Adds a `UNIQUE` constraint.
414
+
415
+ ```ts
416
+ t.string("email").unique();
417
+ ```
418
+
419
+ #### `default(value)`
420
+
421
+ `default(value: unknown): this`
422
+
423
+ Sets a default, rendered inline into the DDL.
424
+
425
+ ```ts
426
+ t.boolean("active").default(true);
427
+ t.string("role").default("member");
428
+ ```
429
+
430
+ **Notes:** strings are single-quoted (with no escaping — keep them constant),
431
+ booleans render as `1`/`0` on sqlite and `true`/`false` elsewhere, numbers pass
432
+ through via `String(value)`.
433
+
434
+ #### `toSql(dialect)`
435
+
436
+ `toSql(dialect: Dialect): string`
437
+
438
+ Renders this one column's DDL fragment (`name TYPE [NOT NULL] [UNIQUE] [DEFAULT
439
+ …]`). Called internally by `TableBuilder.toCreateSql`.
440
+
441
+ ```ts
442
+ new Column("email", "string").unique().toSql("sqlite");
443
+ // email VARCHAR(255) NOT NULL UNIQUE
444
+ ```
445
+
446
+ ### Interfaces & types
447
+
448
+ #### `Migration`
449
+
450
+ ```ts
451
+ interface Migration {
452
+ name: string;
453
+ up(schema: SchemaBuilder): void | Promise<void>;
454
+ down(schema: SchemaBuilder): void | Promise<void>;
455
+ }
456
+ ```
457
+
458
+ One schema change and its reversal. `name` is the identity recorded in the
459
+ `migrations` table (make it unique and sortable); `up` applies the change, `down`
460
+ reverses it. Both receive a [`SchemaBuilder`](#schemabuilder) and may be sync or
461
+ async. Implement it as a plain object literal:
462
+
463
+ ```ts
464
+ const m: Migration = {
465
+ name: "03_add_index",
466
+ up: (s) => s.raw("CREATE INDEX idx_users_email ON users (email)"),
467
+ down: (s) => s.raw("DROP INDEX idx_users_email"),
468
+ };
469
+ ```
470
+
471
+ #### `Connection` / `Dialect`
472
+
473
+ Re-used from the [database](./database.md) layer. `Migrator` and `SchemaBuilder`
474
+ take a `Connection` (the driver seam) and a `Dialect`
475
+ (`"sqlite" | "mysql" | "postgres"`). See
476
+ [Database → Interfaces & types](./database.md#interfaces--types).