@shapio/local 0.5.9 → 0.5.11

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.
@@ -1,4 +1,4 @@
1
- import { a as mysqlDriverOf, r as sqliteDriverOf } from "./advisoryLocks-ajVNBhfa.js";
1
+ import { a as mysqlDriverOf, r as sqliteDriverOf } from "./advisoryLocks-DGbxw3_E.js";
2
2
  import { sql } from "kysely";
3
3
  import { Migrator } from "kysely/migration";
4
4
  //#region \0rolldown/runtime.js
@@ -15,14 +15,14 @@ var __exportAll = (all, no_symbols) => {
15
15
  //#endregion
16
16
  //#region ../../apps/api/src/db/migrations/20261001120000_create_platform_tables.ts
17
17
  var _20261001120000_create_platform_tables_exports = /* @__PURE__ */ __exportAll({
18
- down: () => down$34,
19
- up: () => up$34
18
+ down: () => down$37,
19
+ up: () => up$37
20
20
  });
21
21
  /**
22
22
  * Foundation tables shared by every package: durable versions, the job queue, the transactional outbox
23
23
  * and the audit log. Statuses are text with CHECK constraints so new states need only a constraint change.
24
24
  */
25
- const up$34 = async (db) => {
25
+ const up$37 = async (db) => {
26
26
  await db.schema.createTable("system_versions").addColumn("id", "boolean", (col) => col.primaryKey().defaultTo(true).check(sql`id`)).addColumn("schema_version", "integer", (col) => col.notNull().defaultTo(0)).addColumn("permissions_version", "integer", (col) => col.notNull().defaultTo(0)).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).execute();
27
27
  await sql`insert into system_versions default values`.execute(db);
28
28
  await db.schema.createTable("jobs").addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`)).addColumn("type", "text", (col) => col.notNull()).addColumn("payload", "jsonb", (col) => col.notNull().defaultTo(sql`'{}'::jsonb`)).addColumn("status", "text", (col) => col.notNull().defaultTo("pending").check(sql`status in ('pending', 'running', 'succeeded', 'dead')`)).addColumn("priority", "integer", (col) => col.notNull().defaultTo(0)).addColumn("run_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("attempts", "integer", (col) => col.notNull().defaultTo(0)).addColumn("max_attempts", "integer", (col) => col.notNull().defaultTo(10).check(sql`max_attempts > 0`)).addColumn("idempotency_key", "text").addColumn("locked_by", "text").addColumn("locked_until", "timestamptz").addColumn("checkpoint", "jsonb").addColumn("result", "jsonb").addColumn("last_error", "text").addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("finished_at", "timestamptz").execute();
@@ -44,7 +44,7 @@ const up$34 = async (db) => {
44
44
  "occurred_at desc"
45
45
  ]).execute();
46
46
  };
47
- const down$34 = async (db) => {
47
+ const down$37 = async (db) => {
48
48
  await db.schema.dropTable("audit_events").execute();
49
49
  await db.schema.dropTable("outbox_events").execute();
50
50
  await db.schema.dropTable("jobs").execute();
@@ -53,8 +53,8 @@ const down$34 = async (db) => {
53
53
  //#endregion
54
54
  //#region ../../apps/api/src/db/migrations/20261001130000_create_admin_identity.ts
55
55
  var _20261001130000_create_admin_identity_exports = /* @__PURE__ */ __exportAll({
56
- down: () => down$33,
57
- up: () => up$33
56
+ down: () => down$36,
57
+ up: () => up$36
58
58
  });
59
59
  /**
60
60
  * Admin identity (package B, ADR 0005): admin users, roles and their permission grants, server-side
@@ -63,7 +63,7 @@ var _20261001130000_create_admin_identity_exports = /* @__PURE__ */ __exportAll(
63
63
  */
64
64
  const withTimestamps$3 = (table) => table.addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`));
65
65
  const uuidPrimaryKey$3 = (table) => table.addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`));
66
- const up$33 = async (db) => {
66
+ const up$36 = async (db) => {
67
67
  await withTimestamps$3(uuidPrimaryKey$3(db.schema.createTable("admin_users")).addColumn("email", "text", (col) => col.notNull().unique()).addColumn("name", "text", (col) => col.notNull().defaultTo("")).addColumn("password_hash", "text", (col) => col.notNull()).addColumn("status", "text", (col) => col.notNull().defaultTo("active").check(sql`status in ('active', 'disabled')`)).addColumn("last_login_at", "timestamptz").addColumn("password_changed_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`))).execute();
68
68
  await withTimestamps$3(uuidPrimaryKey$3(db.schema.createTable("admin_roles")).addColumn("key", "text", (col) => col.notNull().unique().check(sql`key ~ '^[a-z][a-z0-9-]{0,62}$'`)).addColumn("name", "text", (col) => col.notNull()).addColumn("description", "text", (col) => col.notNull().defaultTo("")).addColumn("kind", "text", (col) => col.notNull().defaultTo("admin").check(sql`kind in ('admin', 'delivery')`)).addColumn("is_system", "boolean", (col) => col.notNull().defaultTo(false)).addColumn("version", "integer", (col) => col.notNull().defaultTo(1))).execute();
69
69
  await withTimestamps$3(uuidPrimaryKey$3(db.schema.createTable("admin_role_permissions")).addColumn("role_id", "uuid", (col) => col.notNull().references("admin_roles.id").onDelete("cascade")).addColumn("action", "text", (col) => col.notNull()).addColumn("model_id", "text").addColumn("condition", "text", (col) => col.check(sql`condition in ('ownedByPrincipal')`)).addColumn("field_ids", sql`text[]`).addUniqueConstraint("admin_role_permissions_grant_uq", [
@@ -83,7 +83,7 @@ const up$33 = async (db) => {
83
83
  await withTimestamps$3(uuidPrimaryKey$3(db.schema.createTable("api_tokens")).addColumn("name", "text", (col) => col.notNull()).addColumn("token_hash", "text", (col) => col.notNull().unique()).addColumn("token_prefix", "text", (col) => col.notNull()).addColumn("role_id", "uuid", (col) => col.notNull().references("admin_roles.id").onDelete("restrict")).addColumn("created_by", "uuid", (col) => col.references("admin_users.id").onDelete("set null")).addColumn("expires_at", "timestamptz").addColumn("last_used_at", "timestamptz").addColumn("revoked_at", "timestamptz")).execute();
84
84
  await db.schema.createIndex("api_tokens_role_idx").on("api_tokens").column("role_id").execute();
85
85
  };
86
- const down$33 = async (db) => {
86
+ const down$36 = async (db) => {
87
87
  await db.schema.dropTable("api_tokens").execute();
88
88
  await db.schema.dropTable("setup_tokens").execute();
89
89
  await db.schema.dropTable("password_resets").execute();
@@ -97,31 +97,31 @@ const down$33 = async (db) => {
97
97
  //#endregion
98
98
  //#region ../../apps/api/src/db/migrations/20261001130500_create_system_settings.ts
99
99
  var _20261001130500_create_system_settings_exports = /* @__PURE__ */ __exportAll({
100
- down: () => down$32,
101
- up: () => up$32
100
+ down: () => down$35,
101
+ up: () => up$35
102
102
  });
103
103
  /**
104
104
  * Instance-wide key/value settings that must survive restarts and be shared by every instance, e.g. the
105
105
  * generated signing secret. General purpose: later packages add keys, not tables.
106
106
  */
107
- const up$32 = async (db) => {
107
+ const up$35 = async (db) => {
108
108
  await db.schema.createTable("system_settings").addColumn("key", "text", (col) => col.primaryKey()).addColumn("value", "text", (col) => col.notNull()).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).execute();
109
109
  };
110
- const down$32 = async (db) => {
110
+ const down$35 = async (db) => {
111
111
  await db.schema.dropTable("system_settings").execute();
112
112
  };
113
113
  //#endregion
114
114
  //#region ../../apps/api/src/db/migrations/20261001140000_create_schema_tables.ts
115
115
  var _20261001140000_create_schema_tables_exports = /* @__PURE__ */ __exportAll({
116
- down: () => down$31,
117
- up: () => up$31
116
+ down: () => down$34,
117
+ up: () => up$34
118
118
  });
119
119
  /**
120
120
  * Schema registry (package D, ADR 0002): models and components (one table, `kind` discriminator), immutable
121
121
  * schema revisions, the per-model active pointer, schema change jobs, locales and schema settings.
122
122
  * Model definitions are data: creating or changing a model never runs DDL (CONTRIBUTING.md rule 1).
123
123
  */
124
- const up$31 = async (db) => {
124
+ const up$34 = async (db) => {
125
125
  await db.schema.createTable("models").addColumn("id", "uuid", (col) => col.primaryKey()).addColumn("kind", "text", (col) => col.notNull().check(sql`kind in ('collection', 'singleton', 'component')`)).addColumn("api_key", "text", (col) => col.notNull()).addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("deleted_at", "timestamptz").execute();
126
126
  await sql`create unique index models_api_key_uq on models (lower(api_key)) where deleted_at is null`.execute(db);
127
127
  await db.schema.createTable("schema_revisions").addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`)).addColumn("model_id", "uuid", (col) => col.notNull().references("models.id").onDelete("restrict")).addColumn("version", "integer", (col) => col.notNull().check(sql`version > 0`)).addColumn("definition", "jsonb", (col) => col.notNull()).addColumn("hash", "text", (col) => col.notNull()).addColumn("parent_revision_id", "uuid", (col) => col.references("schema_revisions.id")).addColumn("created_by_type", "text", (col) => col.notNull()).addColumn("created_by_id", "text").addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addUniqueConstraint("schema_revisions_model_version_uq", ["model_id", "version"]).execute();
@@ -149,7 +149,7 @@ const up$31 = async (db) => {
149
149
  await db.schema.createTable("schema_settings").addColumn("id", "boolean", (col) => col.primaryKey().defaultTo(true).check(sql`id`)).addColumn("read_only", "boolean", (col) => col.notNull().defaultTo(false)).addColumn("read_only_reason", "text").addColumn("updated_by_type", "text").addColumn("updated_by_id", "text").addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).execute();
150
150
  await sql`insert into schema_settings default values`.execute(db);
151
151
  };
152
- const down$31 = async (db) => {
152
+ const down$34 = async (db) => {
153
153
  await db.schema.dropTable("schema_settings").execute();
154
154
  await db.schema.dropTable("locales").execute();
155
155
  await db.schema.dropTable("schema_change_jobs").execute();
@@ -161,8 +161,8 @@ const down$31 = async (db) => {
161
161
  //#endregion
162
162
  //#region ../../apps/api/src/db/migrations/20261001150000_create_content_tables.ts
163
163
  var _20261001150000_create_content_tables_exports = /* @__PURE__ */ __exportAll({
164
- down: () => down$30,
165
- up: () => up$30
164
+ down: () => down$33,
165
+ up: () => up$33
166
166
  });
167
167
  /**
168
168
  * Content storage (package E, ADR 0001): entries, immutable content revisions, mutable heads (one per
@@ -170,7 +170,7 @@ var _20261001150000_create_content_tables_exports = /* @__PURE__ */ __exportAll(
170
170
  * and the publication log behind `?snapshot=N`. User content models never get tables of their own
171
171
  * (CONTRIBUTING.md rule 1): their values are JSONB keyed by stable field IDs.
172
172
  */
173
- const up$30 = async (db) => {
173
+ const up$33 = async (db) => {
174
174
  await db.schema.createTable("entries").addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`)).addColumn("model_id", "uuid", (col) => col.notNull().references("models.id").onDelete("restrict")).addColumn("owner_app_user_id", "uuid").addColumn("created_by_admin_id", "uuid", (col) => col.references("admin_users.id").onDelete("set null")).addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("updated_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("deleted_at", "timestamptz").execute();
175
175
  await sql`create index entries_model_idx on entries (model_id, created_at) where deleted_at is null`.execute(db);
176
176
  await sql`create index entries_owner_idx on entries (owner_app_user_id) where owner_app_user_id is not null`.execute(db);
@@ -234,7 +234,7 @@ const up$30 = async (db) => {
234
234
  await sql`create unique index publication_log_open_uq on publication_log (entry_id, locale) where to_seq is null`.execute(db);
235
235
  await db.schema.createIndex("publication_log_model_seq_idx").on("publication_log").columns(["model_id", "from_seq"]).execute();
236
236
  };
237
- const down$30 = async (db) => {
237
+ const down$33 = async (db) => {
238
238
  await db.schema.dropTable("publication_log").execute();
239
239
  await db.schema.dropTable("publication_state").execute();
240
240
  await db.schema.dropTable("unique_values").execute();
@@ -247,8 +247,8 @@ const down$30 = async (db) => {
247
247
  //#endregion
248
248
  //#region ../../apps/api/src/db/migrations/20261001160000_create_media_tables.ts
249
249
  var _20261001160000_create_media_tables_exports = /* @__PURE__ */ __exportAll({
250
- down: () => down$29,
251
- up: () => up$29
250
+ down: () => down$32,
251
+ up: () => up$32
252
252
  });
253
253
  /**
254
254
  * Media library (package G): folders, assets, image variants, references from content and upload grants.
@@ -259,7 +259,7 @@ const withTimestamps$2 = (table) => table.addColumn("created_at", "timestamptz",
259
259
  const uuidPrimaryKey$2 = (table) => table.addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`));
260
260
  const STORAGE_DRIVER_CHECK = sql`storage_driver in ('local', 's3')`;
261
261
  const VISIBILITY_CHECK = sql`visibility in ('public', 'private')`;
262
- const up$29 = async (db) => {
262
+ const up$32 = async (db) => {
263
263
  await withTimestamps$2(uuidPrimaryKey$2(db.schema.createTable("media_folders")).addColumn("parent_id", "uuid", (col) => col.references("media_folders.id").onDelete("restrict")).addColumn("name", "text", (col) => col.notNull().check(sql`length(name) between 1 and 255`)).addColumn("created_by", "uuid", (col) => col.references("admin_users.id").onDelete("set null")).addColumn("version", "integer", (col) => col.notNull().defaultTo(1))).execute();
264
264
  await sql`create unique index media_folders_sibling_name_uq on media_folders
265
265
  (coalesce(parent_id, '00000000-0000-0000-0000-000000000000'::uuid), lower(name))`.execute(db);
@@ -288,7 +288,7 @@ const up$29 = async (db) => {
288
288
  ]).execute();
289
289
  await db.schema.createTable("media_upload_grants").addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`)).addColumn("asset_id", "uuid", (col) => col.notNull()).addColumn("kind", "text", (col) => col.notNull().check(sql`kind in ('create', 'replace')`)).addColumn("storage_driver", "text", (col) => col.notNull().check(STORAGE_DRIVER_CHECK)).addColumn("storage_key", "text", (col) => col.notNull().unique()).addColumn("original_filename", "text", (col) => col.notNull()).addColumn("declared_mime_type", "text", (col) => col.notNull()).addColumn("max_size_bytes", "bigint", (col) => col.notNull()).addColumn("folder_id", "uuid").addColumn("visibility", "text", (col) => col.notNull().check(VISIBILITY_CHECK)).addColumn("created_by", "uuid", (col) => col.references("admin_users.id").onDelete("set null")).addColumn("created_by_principal", "text", (col) => col.notNull()).addColumn("status", "text", (col) => col.notNull().defaultTo("pending").check(sql`status in ('pending', 'consumed', 'rejected', 'expired')`)).addColumn("expires_at", "timestamptz", (col) => col.notNull()).addColumn("consumed_at", "timestamptz").addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).execute();
290
290
  };
291
- const down$29 = async (db) => {
291
+ const down$32 = async (db) => {
292
292
  await db.schema.dropTable("media_upload_grants").execute();
293
293
  await db.schema.dropTable("media_references").execute();
294
294
  await db.schema.dropTable("media_variants").execute();
@@ -298,8 +298,8 @@ const down$29 = async (db) => {
298
298
  //#endregion
299
299
  //#region ../../apps/api/src/db/migrations/20261001170000_create_publishing_tables.ts
300
300
  var _20261001170000_create_publishing_tables_exports = /* @__PURE__ */ __exportAll({
301
- down: () => down$28,
302
- up: () => up$28
301
+ down: () => down$31,
302
+ up: () => up$31
303
303
  });
304
304
  /**
305
305
  * Publishing (package H): scheduled publications, releases, webhooks and their delivery log, deployment
@@ -338,13 +338,13 @@ const createPreviewTables = async (db) => {
338
338
  await uuidPrimaryKey$1(db.schema.createTable("preview_tokens")).addColumn("token_hash", "text", (col) => col.notNull().unique()).addColumn("token_prefix", "text", (col) => col.notNull()).addColumn("model_id", "uuid", (col) => col.notNull()).addColumn("entry_id", "uuid", (col) => col.references("entries.id").onDelete("cascade")).addColumn("locale", "text").addColumn("connection_id", "uuid", (col) => col.references("deployment_connections.id").onDelete("set null")).addColumn("delivery_role_id", "uuid", (col) => col.references("admin_roles.id").onDelete("set null")).addColumn("created_by", "uuid", (col) => col.notNull().references("admin_users.id").onDelete("cascade")).addColumn("expires_at", "timestamptz", (col) => col.notNull()).addColumn("revoked_at", "timestamptz").addColumn("last_used_at", "timestamptz").addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).execute();
339
339
  await db.schema.createIndex("preview_tokens_entry_idx").on("preview_tokens").columns(["entry_id", "created_at desc"]).execute();
340
340
  };
341
- const up$28 = async (db) => {
341
+ const up$31 = async (db) => {
342
342
  await createSchedulingTables(db);
343
343
  await createWebhookTables(db);
344
344
  await createDeploymentTables(db);
345
345
  await createPreviewTables(db);
346
346
  };
347
- const down$28 = async (db) => {
347
+ const down$31 = async (db) => {
348
348
  await db.schema.dropTable("preview_tokens").execute();
349
349
  await db.schema.dropTable("deployment_runs").execute();
350
350
  await db.schema.dropTable("deployment_connections").execute();
@@ -357,8 +357,8 @@ const down$28 = async (db) => {
357
357
  //#endregion
358
358
  //#region ../../apps/api/src/db/migrations/20261001180000_create_app_users.ts
359
359
  var _20261001180000_create_app_users_exports = /* @__PURE__ */ __exportAll({
360
- down: () => down$27,
361
- up: () => up$27
360
+ down: () => down$30,
361
+ up: () => up$30
362
362
  });
363
363
  /**
364
364
  * App users (package I, ADR 0005): the end users of sites and apps built on Shapio, with their own roles
@@ -409,7 +409,7 @@ const createCredentials = async (db) => {
409
409
  }
410
410
  await db.schema.createTable("app_login_codes").addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`)).addColumn("app_user_id", "uuid", (col) => col.notNull().references("app_users.id").onDelete("cascade")).addColumn("code_hash", "text", (col) => col.notNull().unique()).addColumn("expires_at", "timestamptz", (col) => col.notNull()).addColumn("used_at", "timestamptz").addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).execute();
411
411
  };
412
- const up$27 = async (db) => {
412
+ const up$30 = async (db) => {
413
413
  await createUsers(db);
414
414
  await createRoles(db);
415
415
  await createCredentials(db);
@@ -419,7 +419,7 @@ const up$27 = async (db) => {
419
419
  foreign key (owner_app_user_id) references app_users (id) on delete set null
420
420
  `.execute(db);
421
421
  };
422
- const down$27 = async (db) => {
422
+ const down$30 = async (db) => {
423
423
  await sql`alter table entries drop constraint if exists entries_owner_app_user_fk`.execute(db);
424
424
  await db.schema.dropTable("app_login_codes").execute();
425
425
  await db.schema.dropTable("app_password_resets").execute();
@@ -434,8 +434,8 @@ const down$27 = async (db) => {
434
434
  //#endregion
435
435
  //#region ../../apps/api/src/db/migrations/20261002120000_create_extension_hook_runs.ts
436
436
  var _20261002120000_create_extension_hook_runs_exports = /* @__PURE__ */ __exportAll({
437
- down: () => down$26,
438
- up: () => up$26
437
+ down: () => down$29,
438
+ up: () => up$29
439
439
  });
440
440
  /**
441
441
  * Extension points (package K, ADR 0009): the ledger of post-commit lifecycle hooks (`afterCreate`,
@@ -443,17 +443,17 @@ var _20261002120000_create_extension_hook_runs_exports = /* @__PURE__ */ __expor
443
443
  * as the hook's own database work, so a hook re-run after a worker crash finds its row and is skipped:
444
444
  * exactly once for everything the hook does through its transaction.
445
445
  */
446
- const up$26 = async (db) => {
446
+ const up$29 = async (db) => {
447
447
  await db.schema.createTable("extension_hook_runs").addColumn("event_id", "uuid", (col) => col.notNull()).addColumn("hook", "text", (col) => col.notNull()).addColumn("job_id", "uuid").addColumn("completed_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addPrimaryKeyConstraint("extension_hook_runs_pkey", ["event_id", "hook"]).execute();
448
448
  };
449
- const down$26 = async (db) => {
449
+ const down$29 = async (db) => {
450
450
  await db.schema.dropTable("extension_hook_runs").execute();
451
451
  };
452
452
  //#endregion
453
453
  //#region ../../apps/api/src/db/migrations/20261002130000_app_auth_token_version_and_login_code_pkce.ts
454
454
  var _20261002130000_app_auth_token_version_and_login_code_pkce_exports = /* @__PURE__ */ __exportAll({
455
- down: () => down$25,
456
- up: () => up$25
455
+ down: () => down$28,
456
+ up: () => up$28
457
457
  });
458
458
  /**
459
459
  * App users (ADR 0005):
@@ -464,20 +464,20 @@ var _20261002130000_app_auth_token_version_and_login_code_pkce_exports = /* @__P
464
464
  * sign-in; the one-time login code is only exchanged with the matching verifier. Codes live a minute, so
465
465
  * any pending ones (issued without a challenge) are dropped rather than given a placeholder.
466
466
  */
467
- const up$25 = async (db) => {
467
+ const up$28 = async (db) => {
468
468
  await db.schema.alterTable("app_users").addColumn("token_version", "integer", (col) => col.notNull().defaultTo(0)).execute();
469
469
  await sql`delete from app_login_codes`.execute(db);
470
470
  await db.schema.alterTable("app_login_codes").addColumn("code_challenge", "text", (col) => col.notNull()).execute();
471
471
  };
472
- const down$25 = async (db) => {
472
+ const down$28 = async (db) => {
473
473
  await db.schema.alterTable("app_login_codes").dropColumn("code_challenge").execute();
474
474
  await db.schema.alterTable("app_users").dropColumn("token_version").execute();
475
475
  };
476
476
  //#endregion
477
477
  //#region ../../apps/api/src/db/migrations/20261002180000_add_publication_log_diff_indexes.ts
478
478
  var _20261002180000_add_publication_log_diff_indexes_exports = /* @__PURE__ */ __exportAll({
479
- down: () => down$24,
480
- up: () => up$24
479
+ down: () => down$27,
480
+ up: () => up$27
481
481
  });
482
482
  /**
483
483
  * The snapshot diff (repositories/snapshotDiff.ts) finds the (entry, locale) pairs whose live period opened
@@ -486,7 +486,7 @@ var _20261002180000_add_publication_log_diff_indexes_exports = /* @__PURE__ */ _
486
486
  * - `(entry_id, locale, from_seq)`: "the row live at seq N" is the latest row starting at or before N.
487
487
  * Periods that opened in the range use the existing `(model_id, from_seq)` index.
488
488
  */
489
- const up$24 = async (db) => {
489
+ const up$27 = async (db) => {
490
490
  await sql`create index publication_log_to_seq_idx on publication_log (to_seq) where to_seq is not null`.execute(db);
491
491
  await db.schema.createIndex("publication_log_entry_locale_from_idx").on("publication_log").columns([
492
492
  "entry_id",
@@ -494,15 +494,15 @@ const up$24 = async (db) => {
494
494
  "from_seq"
495
495
  ]).execute();
496
496
  };
497
- const down$24 = async (db) => {
497
+ const down$27 = async (db) => {
498
498
  await db.schema.dropIndex("publication_log_entry_locale_from_idx").execute();
499
499
  await db.schema.dropIndex("publication_log_to_seq_idx").execute();
500
500
  };
501
501
  //#endregion
502
502
  //#region ../../apps/api/src/db/migrations/20261002180100_create_usage_tables.ts
503
503
  var _20261002180100_create_usage_tables_exports = /* @__PURE__ */ __exportAll({
504
- down: () => down$23,
505
- up: () => up$23
504
+ down: () => down$26,
505
+ up: () => up$26
506
506
  });
507
507
  /**
508
508
  * Field usage from delivery traffic (plan developer-face §5): daily counters written by the in-memory
@@ -510,7 +510,7 @@ var _20261002180100_create_usage_tables_exports = /* @__PURE__ */ __exportAll({
510
510
  * payloads. `principal_key` is `token:<id>`, `app_users` or `anonymous`. Pruned by the retention job
511
511
  * after USAGE_RETENTION_DAYS.
512
512
  */
513
- const up$23 = async (db) => {
513
+ const up$26 = async (db) => {
514
514
  await db.schema.createTable("field_reads").addColumn("day", "date", (col) => col.notNull()).addColumn("model_id", "uuid", (col) => col.notNull()).addColumn("field_path", "text", (col) => col.notNull()).addColumn("principal_key", "text", (col) => col.notNull()).addColumn("selection", "text", (col) => col.notNull().check(sql`selection in ('explicit', 'implicit')`)).addColumn("reads", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("last_read_at", "timestamptz", (col) => col.notNull()).addPrimaryKeyConstraint("field_reads_pkey", [
515
515
  "day",
516
516
  "model_id",
@@ -521,15 +521,15 @@ const up$23 = async (db) => {
521
521
  await db.schema.createIndex("field_reads_model_day_idx").on("field_reads").columns(["model_id", "day"]).execute();
522
522
  await db.schema.createTable("token_reads").addColumn("day", "date", (col) => col.notNull()).addColumn("principal_key", "text", (col) => col.notNull()).addColumn("requests", "bigint", (col) => col.notNull().defaultTo(0)).addColumn("last_snapshot", "bigint").addColumn("last_read_at", "timestamptz", (col) => col.notNull()).addPrimaryKeyConstraint("token_reads_pkey", ["day", "principal_key"]).execute();
523
523
  };
524
- const down$23 = async (db) => {
524
+ const down$26 = async (db) => {
525
525
  await db.schema.dropTable("token_reads").execute();
526
526
  await db.schema.dropTable("field_reads").execute();
527
527
  };
528
528
  //#endregion
529
529
  //#region ../../apps/api/src/db/migrations/20261002180200_create_change_sets.ts
530
530
  var _20261002180200_create_change_sets_exports = /* @__PURE__ */ __exportAll({
531
- down: () => down$22,
532
- up: () => up$22
531
+ down: () => down$25,
532
+ up: () => up$25
533
533
  });
534
534
  /**
535
535
  * Change sets (developer-face plan §5, ADR 0010): schema drafts and entry publications that ship as ONE
@@ -708,7 +708,7 @@ const migrateReleases = async (db) => {
708
708
  await sql`drop table release_items`.execute(db);
709
709
  await sql`drop table releases`.execute(db);
710
710
  };
711
- const up$22 = async (db) => {
711
+ const up$25 = async (db) => {
712
712
  await createTables(db);
713
713
  await linkExecutionRecords(db);
714
714
  await allowConversionRevisions(db);
@@ -780,7 +780,7 @@ const restoreReleases = async (db) => {
780
780
  await sql`update webhooks set events = array_remove(array_remove(events, 'change_set.shipping'),
781
781
  'change_set.discarded')`.execute(db);
782
782
  };
783
- const down$22 = async (db) => {
783
+ const down$25 = async (db) => {
784
784
  await restoreReleases(db);
785
785
  await sql`alter table content_revisions drop constraint content_revisions_reason_check`.execute(db);
786
786
  await sql`alter table content_revisions add constraint content_revisions_reason_check
@@ -801,8 +801,8 @@ const down$22 = async (db) => {
801
801
  //#endregion
802
802
  //#region ../../apps/api/src/db/migrations/20261002190000_create_editor_presence_and_content_health.ts
803
803
  var _20261002190000_create_editor_presence_and_content_health_exports = /* @__PURE__ */ __exportAll({
804
- down: () => down$21,
805
- up: () => up$21
804
+ down: () => down$24,
805
+ up: () => up$24
806
806
  });
807
807
  /**
808
808
  * Editor experience (plan editor-experience §9):
@@ -813,7 +813,7 @@ var _20261002190000_create_editor_presence_and_content_health_exports = /* @__PU
813
813
  * - `content_health_findings`: open and recently resolved findings of the health rules per entry and
814
814
  * locale (`*` for the entry as a whole). An evaluation upserts what it found and resolves the rest.
815
815
  */
816
- const up$21 = async (db) => {
816
+ const up$24 = async (db) => {
817
817
  await sql`
818
818
  create unlogged table editor_presence (
819
819
  entry_id uuid not null,
@@ -850,15 +850,15 @@ const up$21 = async (db) => {
850
850
  await sql`create index content_health_findings_resolved_idx on content_health_findings (resolved_at)
851
851
  where resolved_at is not null`.execute(db);
852
852
  };
853
- const down$21 = async (db) => {
853
+ const down$24 = async (db) => {
854
854
  await sql`drop table content_health_findings`.execute(db);
855
855
  await sql`drop table editor_presence`.execute(db);
856
856
  };
857
857
  //#endregion
858
858
  //#region ../../apps/api/src/db/migrations/20261003120000_add_changes_ship_permission.ts
859
859
  var _20261003120000_add_changes_ship_permission_exports = /* @__PURE__ */ __exportAll({
860
- down: () => down$20,
861
- up: () => up$20
860
+ down: () => down$23,
861
+ up: () => up$23
862
862
  });
863
863
  /**
864
864
  * `changes.ship` (agentic plan §I): shipping a change set (and scheduling a ship) becomes its own global
@@ -866,7 +866,7 @@ var _20261003120000_add_changes_ship_permission_exports = /* @__PURE__ */ __expo
866
866
  * live. Every role that holds `changes.manage` today keeps what it could do: it gets `changes.ship` too.
867
867
  * The permissions version moves only when grants changed, so running instances reload exactly then.
868
868
  */
869
- const up$20 = async (db) => {
869
+ const up$23 = async (db) => {
870
870
  await sql`
871
871
  with granted as (
872
872
  insert into admin_role_permissions (role_id, action, model_id, condition, field_ids)
@@ -880,7 +880,7 @@ const up$20 = async (db) => {
880
880
  where exists (select 1 from granted)
881
881
  `.execute(db);
882
882
  };
883
- const down$20 = async (db) => {
883
+ const down$23 = async (db) => {
884
884
  await sql`
885
885
  with revoked as (
886
886
  delete from admin_role_permissions where action = 'changes.ship' returning 1
@@ -892,8 +892,8 @@ const down$20 = async (db) => {
892
892
  //#endregion
893
893
  //#region ../../apps/api/src/db/migrations/20261003130000_create_sites.ts
894
894
  var _20261003130000_create_sites_exports = /* @__PURE__ */ __exportAll({
895
- down: () => down$19,
896
- up: () => up$19
895
+ down: () => down$22,
896
+ up: () => up$22
897
897
  });
898
898
  /**
899
899
  * Sites (plan agentic-ecosystem §H, ADR 0011): one instance hosts many sites with one schema and one login.
@@ -1081,7 +1081,7 @@ const siteRoleAssignments = async (db) => {
1081
1081
  `.execute(db);
1082
1082
  await sql`alter table admin_invitations drop column role_ids`.execute(db);
1083
1083
  };
1084
- const up$19 = async (db) => {
1084
+ const up$22 = async (db) => {
1085
1085
  await createSites(db);
1086
1086
  await addSiteColumns(db);
1087
1087
  await tieCopiesToEntries(db);
@@ -1094,7 +1094,7 @@ const assertSingleSite = async (db) => {
1094
1094
  const { rows } = await sql`select count(*)::text as count from sites`.execute(db);
1095
1095
  if (Number(rows[0]?.count ?? 0) > 1) throw new Error("Cannot roll back sites while more than one site exists: merging them would merge their snapshot ledgers and uniqueness and widen role assignments. Delete the other sites first.");
1096
1096
  };
1097
- const down$19 = async (db) => {
1097
+ const down$22 = async (db) => {
1098
1098
  await assertSingleSite(db);
1099
1099
  await sql`alter table admin_invitations add column role_ids uuid[] not null default '{}'::uuid[]`.execute(db);
1100
1100
  await sql`
@@ -1165,8 +1165,8 @@ const down$19 = async (db) => {
1165
1165
  //#endregion
1166
1166
  //#region ../../apps/api/src/db/migrations/20261003140200_enqueue_field_index_layout.ts
1167
1167
  var _20261003140200_enqueue_field_index_layout_exports = /* @__PURE__ */ __exportAll({
1168
- down: () => down$18,
1169
- up: () => up$18
1168
+ down: () => down$21,
1169
+ up: () => up$21
1170
1170
  });
1171
1171
  /**
1172
1172
  * Field index layout v2 (sites plan §H): per-field expression indexes on `entry_heads` lead with `site_id`,
@@ -1178,7 +1178,7 @@ var _20261003140200_enqueue_field_index_layout_exports = /* @__PURE__ */ __expor
1178
1178
  */
1179
1179
  const JOB_TYPE$1 = "schema.fieldIndexLayout";
1180
1180
  const IDEMPOTENCY_KEY$1 = "schema.fieldIndexLayout:v2";
1181
- const up$18 = async (db) => {
1181
+ const up$21 = async (db) => {
1182
1182
  await sql`
1183
1183
  insert into jobs (type, payload, max_attempts, idempotency_key)
1184
1184
  select ${JOB_TYPE$1}, '{}'::jsonb, 5, ${IDEMPOTENCY_KEY$1}
@@ -1191,14 +1191,14 @@ const up$18 = async (db) => {
1191
1191
  `.execute(db);
1192
1192
  };
1193
1193
  /** The layout job is idempotent; rolling back only forgets it if it has not run yet. */
1194
- const down$18 = async (db) => {
1194
+ const down$21 = async (db) => {
1195
1195
  await sql`delete from jobs where idempotency_key = ${IDEMPOTENCY_KEY$1} and status = 'pending'`.execute(db);
1196
1196
  };
1197
1197
  //#endregion
1198
1198
  //#region ../../apps/api/src/db/migrations/20261003140500_change_set_items_site_and_preview_entry.ts
1199
1199
  var _20261003140500_change_set_items_site_and_preview_entry_exports = /* @__PURE__ */ __exportAll({
1200
- down: () => down$17,
1201
- up: () => up$17
1200
+ down: () => down$20,
1201
+ up: () => up$20
1202
1202
  });
1203
1203
  /**
1204
1204
  * Sites, publishing (plan agentic-ecosystem §H, package G5).
@@ -1209,7 +1209,7 @@ var _20261003140500_change_set_items_site_and_preview_entry_exports = /* @__PURE
1209
1209
  * - `preview_tokens.entry_id` becomes required: a preview token previews one entry of one site. Model-wide
1210
1210
  * tokens (short-lived by design) are deleted; whoever needs one opens the entry's preview again.
1211
1211
  */
1212
- const up$17 = async (db) => {
1212
+ const up$20 = async (db) => {
1213
1213
  await sql`alter table change_sets add constraint change_sets_id_site_uq unique (id, site_id)`.execute(db);
1214
1214
  await sql`alter table change_set_items add column site_id uuid`.execute(db);
1215
1215
  await sql`
@@ -1225,7 +1225,7 @@ const up$17 = async (db) => {
1225
1225
  await sql`delete from preview_tokens where entry_id is null`.execute(db);
1226
1226
  await sql`alter table preview_tokens alter column entry_id set not null`.execute(db);
1227
1227
  };
1228
- const down$17 = async (db) => {
1228
+ const down$20 = async (db) => {
1229
1229
  await sql`alter table preview_tokens alter column entry_id drop not null`.execute(db);
1230
1230
  await sql`alter table change_set_items drop constraint change_set_items_entry_site_fk`.execute(db);
1231
1231
  await sql`alter table change_set_items drop constraint change_set_items_set_site_fk`.execute(db);
@@ -1235,8 +1235,8 @@ const down$17 = async (db) => {
1235
1235
  //#endregion
1236
1236
  //#region ../../apps/api/src/db/migrations/20261003150000_widen_deployment_providers.ts
1237
1237
  var _20261003150000_widen_deployment_providers_exports = /* @__PURE__ */ __exportAll({
1238
- down: () => down$16,
1239
- up: () => up$16
1238
+ down: () => down$19,
1239
+ up: () => up$19
1240
1240
  });
1241
1241
  /**
1242
1242
  * Deploy adapters (plan agentic-ecosystem §B2): deployment connections may use the Vercel and Netlify
@@ -1251,11 +1251,11 @@ const replaceCheck = async (db, check) => {
1251
1251
  check (${check}) not valid`.execute(db);
1252
1252
  await sql`alter table deployment_connections validate constraint deployment_connections_provider_check`.execute(db);
1253
1253
  };
1254
- const up$16 = async (db) => {
1254
+ const up$19 = async (db) => {
1255
1255
  await replaceCheck(db, WIDENED);
1256
1256
  };
1257
1257
  /** Refuses while Vercel or Netlify connections exist: a down migration never deletes user data. */
1258
- const down$16 = async (db) => {
1258
+ const down$19 = async (db) => {
1259
1259
  const { rows } = await sql`
1260
1260
  select count(*)::text as count from deployment_connections where provider in ('vercel', 'netlify')
1261
1261
  `.execute(db);
@@ -1266,8 +1266,8 @@ const down$16 = async (db) => {
1266
1266
  //#endregion
1267
1267
  //#region ../../apps/api/src/db/migrations/20261003160000_create_assist_runs.ts
1268
1268
  var _20261003160000_create_assist_runs_exports = /* @__PURE__ */ __exportAll({
1269
- down: () => down$15,
1270
- up: () => up$15
1269
+ down: () => down$18,
1270
+ up: () => up$18
1271
1271
  });
1272
1272
  /**
1273
1273
  * Editor assists (plan agentic-ecosystem §A0, §I): one `assist_runs` row per assist request (who, which
@@ -1283,14 +1283,14 @@ const replaceSourceCheck = async (db, check) => {
1283
1283
  await sql`alter table change_sets add constraint change_sets_source_check check (${check}) not valid`.execute(db);
1284
1284
  await sql`alter table change_sets validate constraint change_sets_source_check`.execute(db);
1285
1285
  };
1286
- const up$15 = async (db) => {
1286
+ const up$18 = async (db) => {
1287
1287
  await db.schema.createTable("assist_runs").addColumn("id", "uuid", (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`)).addColumn("site_id", "uuid", (col) => col.notNull().references("sites.id").onDelete("cascade")).addColumn("actor_type", "text", (col) => col.notNull()).addColumn("actor_id", "text", (col) => col.notNull()).addColumn("action", "text", (col) => col.notNull().check(ACTIONS)).addColumn("rule", "text").addColumn("provider", "text", (col) => col.notNull()).addColumn("model", "text", (col) => col.notNull()).addColumn("input_tokens", "integer", (col) => col.notNull().defaultTo(0)).addColumn("output_tokens", "integer", (col) => col.notNull().defaultTo(0)).addColumn("duration_ms", "integer", (col) => col.notNull().defaultTo(0)).addColumn("status", "text", (col) => col.notNull().check(sql`status in ('queued', 'running', 'succeeded', 'failed')`)).addColumn("error_code", "text").addColumn("job_id", "uuid", (col) => col.references("jobs.id").onDelete("set null")).addColumn("created_at", "timestamptz", (col) => col.notNull().defaultTo(sql`now()`)).addColumn("finished_at", "timestamptz").execute();
1288
1288
  await db.schema.createIndex("assist_runs_site_created_idx").on("assist_runs").columns(["site_id", "created_at"]).execute();
1289
1289
  await db.schema.createIndex("assist_runs_created_idx").on("assist_runs").column("created_at").execute();
1290
1290
  await replaceSourceCheck(db, SOURCES_WIDENED);
1291
1291
  };
1292
1292
  /** Refuses while change sets opened by assist exist: a down migration never deletes user data. */
1293
- const down$15 = async (db) => {
1293
+ const down$18 = async (db) => {
1294
1294
  const { rows } = await sql`
1295
1295
  select count(*)::text as count from change_sets where source = 'assist'
1296
1296
  `.execute(db);
@@ -1302,8 +1302,8 @@ const down$15 = async (db) => {
1302
1302
  //#endregion
1303
1303
  //#region ../../apps/api/src/db/migrations/20261003170000_audit_events_seq.ts
1304
1304
  var _20261003170000_audit_events_seq_exports$2 = /* @__PURE__ */ __exportAll({
1305
- down: () => down$14,
1306
- up: () => up$14
1305
+ down: () => down$17,
1306
+ up: () => up$17
1307
1307
  });
1308
1308
  /**
1309
1309
  * `audit_events.seq`: a monotonic tiebreaker after `occurred_at`, so events written in the same instant (one
@@ -1312,17 +1312,17 @@ var _20261003170000_audit_events_seq_exports$2 = /* @__PURE__ */ __exportAll({
1312
1312
  * are numbered in the order the rewrite reads them. No index: the audit queries filter and sort by
1313
1313
  * `occurred_at` first, and `seq` only breaks ties.
1314
1314
  */
1315
- const up$14 = async (db) => {
1315
+ const up$17 = async (db) => {
1316
1316
  await db.schema.alterTable("audit_events").addColumn("seq", "bigint", (col) => col.notNull().generatedAlwaysAsIdentity()).execute();
1317
1317
  };
1318
- const down$14 = async (db) => {
1318
+ const down$17 = async (db) => {
1319
1319
  await db.schema.alterTable("audit_events").dropColumn("seq").execute();
1320
1320
  };
1321
1321
  //#endregion
1322
1322
  //#region ../../apps/api/src/db/migrations/20261004120000_models_site_scope.ts
1323
1323
  var _20261004120000_models_site_scope_exports$2 = /* @__PURE__ */ __exportAll({
1324
- down: () => down$13,
1325
- up: () => up$13
1324
+ down: () => down$16,
1325
+ up: () => up$16
1326
1326
  });
1327
1327
  /**
1328
1328
  * Per-site schema (plan site-schema): a definition belongs to one site (`models.site_id`) or is shared by every
@@ -1335,7 +1335,7 @@ var _20261004120000_models_site_scope_exports$2 = /* @__PURE__ */ __exportAll({
1335
1335
  * over `lower(api_key)` cannot hold. Share or delete them first; then `down` is lossless.
1336
1336
  */
1337
1337
  const NIL_UUID$1 = "00000000-0000-0000-0000-000000000000";
1338
- const up$13 = async (db) => {
1338
+ const up$16 = async (db) => {
1339
1339
  await sql`alter table models add column site_id uuid references sites (id)`.execute(db);
1340
1340
  await sql`create index models_site_idx on models (site_id)`.execute(db);
1341
1341
  await sql`drop index models_api_key_uq`.execute(db);
@@ -1345,7 +1345,7 @@ const up$13 = async (db) => {
1345
1345
  `.execute(db);
1346
1346
  await sql`alter table schema_drafts add column shared boolean not null default false`.execute(db);
1347
1347
  };
1348
- const down$13 = async (db) => {
1348
+ const down$16 = async (db) => {
1349
1349
  const { rows } = await sql`select count(*)::text as count from models where site_id is not null`.execute(db);
1350
1350
  if (Number(rows[0]?.count ?? 0) > 0) throw new Error("Cannot roll back per-site schema while definitions belong to a site: two sites may share an API ID. Share or delete the site definitions first.");
1351
1351
  await sql`alter table schema_drafts drop column shared`.execute(db);
@@ -1357,8 +1357,8 @@ const down$13 = async (db) => {
1357
1357
  //#endregion
1358
1358
  //#region ../../apps/api/src/db/migrations/20261004130000_site_seo_settings.ts
1359
1359
  var _20261004130000_site_seo_settings_exports$2 = /* @__PURE__ */ __exportAll({
1360
- down: () => down$12,
1361
- up: () => up$12
1360
+ down: () => down$15,
1361
+ up: () => up$15
1362
1362
  });
1363
1363
  /**
1364
1364
  * SEO defaults per site (plan seo-fields): `sites.seo_defaults` holds the site's default texts per locale, its
@@ -1369,7 +1369,7 @@ var _20261004130000_site_seo_settings_exports$2 = /* @__PURE__ */ __exportAll({
1369
1369
  * about what a site publishes) gets it; the built-in owner and admin roles get it from `ensureSystemRoles`.
1370
1370
  * The permissions version moves only when grants changed, so running instances reload exactly then.
1371
1371
  */
1372
- const up$12 = async (db) => {
1372
+ const up$15 = async (db) => {
1373
1373
  await sql`alter table sites add column seo_defaults jsonb`.execute(db);
1374
1374
  await sql`
1375
1375
  with granted as (
@@ -1384,7 +1384,7 @@ const up$12 = async (db) => {
1384
1384
  where exists (select 1 from granted)
1385
1385
  `.execute(db);
1386
1386
  };
1387
- const down$12 = async (db) => {
1387
+ const down$15 = async (db) => {
1388
1388
  await sql`
1389
1389
  with revoked as (
1390
1390
  delete from admin_role_permissions where action = 'site.settings' returning 1
@@ -1397,8 +1397,8 @@ const down$12 = async (db) => {
1397
1397
  //#endregion
1398
1398
  //#region ../../apps/api/src/db/migrations/20261005120000_entry_heads_entry_created_at.ts
1399
1399
  var _20261005120000_entry_heads_entry_created_at_exports$2 = /* @__PURE__ */ __exportAll({
1400
- down: () => down$11,
1401
- up: () => up$11
1400
+ down: () => down$14,
1401
+ up: () => up$14
1402
1402
  });
1403
1403
  /**
1404
1404
  * Delivery perf 2 (ADR 0001 amendment): the entry's `created_at` on each head (`entry_created_at`), so a list
@@ -1415,7 +1415,7 @@ const INDEX$2 = "entry_heads_entry_order_idx";
1415
1415
  const JOB_TYPE = "schema.entryOrderIndex";
1416
1416
  const IDEMPOTENCY_KEY = "schema.entryOrderIndex:v1";
1417
1417
  const BATCH$1 = 5e3;
1418
- const up$11 = async (db) => {
1418
+ const up$14 = async (db) => {
1419
1419
  await sql`alter table entry_heads add column entry_created_at timestamptz`.execute(db);
1420
1420
  for (;;) {
1421
1421
  const result = await sql`
@@ -1440,7 +1440,7 @@ const up$11 = async (db) => {
1440
1440
  create index ${sql.id(INDEX$2)} on entry_heads (site_id, model_id, state, entry_created_at desc, entry_id)
1441
1441
  `.execute(db);
1442
1442
  };
1443
- const down$11 = async (db) => {
1443
+ const down$14 = async (db) => {
1444
1444
  await sql`delete from jobs where idempotency_key = ${IDEMPOTENCY_KEY} and status = 'pending'`.execute(db);
1445
1445
  await sql`drop index if exists ${sql.id(INDEX$2)}`.execute(db);
1446
1446
  await sql`alter table entry_heads drop column entry_created_at`.execute(db);
@@ -1449,20 +1449,58 @@ const down$11 = async (db) => {
1449
1449
  //#region ../../apps/api/src/db/migrations/20261006120000_system_versions_release.ts
1450
1450
  var _20261006120000_system_versions_release_exports = /* @__PURE__ */ __exportAll({
1451
1451
  dialectNeutral: () => true,
1452
- down: () => down$10,
1453
- up: () => up$10
1452
+ down: () => down$13,
1453
+ up: () => up$13
1454
1454
  });
1455
- const up$10 = async (db) => {
1455
+ const up$13 = async (db) => {
1456
1456
  await db.schema.alterTable("system_versions").addColumn("release", "text").execute();
1457
1457
  };
1458
- const down$10 = async (db) => {
1458
+ const down$13 = async (db) => {
1459
1459
  await db.schema.alterTable("system_versions").dropColumn("release").execute();
1460
1460
  };
1461
1461
  //#endregion
1462
+ //#region ../../apps/api/src/db/migrations/20261014120000_canceled_status.ts
1463
+ var _20261014120000_canceled_status_exports$2 = /* @__PURE__ */ __exportAll({
1464
+ down: () => down$12,
1465
+ up: () => up$12
1466
+ });
1467
+ /**
1468
+ * The `cancelled` status of schema change jobs and scheduled publications becomes `canceled`. Rows are
1469
+ * rewritten and the check constraints swapped. MySQL has its own twin; SQLite rebuilds the two tables
1470
+ * (`./sqlite/20261014120000_canceled_status.ts`).
1471
+ */
1472
+ const TABLES$4 = [{
1473
+ table: "schema_change_jobs",
1474
+ values: [
1475
+ "pending",
1476
+ "running",
1477
+ "activated",
1478
+ "failed"
1479
+ ]
1480
+ }, {
1481
+ table: "scheduled_publications",
1482
+ values: [
1483
+ "scheduled",
1484
+ "done",
1485
+ "failed"
1486
+ ]
1487
+ }];
1488
+ const swap$1 = async (db, from, to) => {
1489
+ for (const { table, values } of TABLES$4) {
1490
+ const constraint = `${table}_status_check`;
1491
+ await sql`alter table ${sql.table(table)} drop constraint ${sql.id(constraint)}`.execute(db);
1492
+ await sql`update ${sql.table(table)} set status = ${to} where status = ${from}`.execute(db);
1493
+ const allowed = sql.join([...values, to].map((value) => sql.lit(value)));
1494
+ await sql`alter table ${sql.table(table)} add constraint ${sql.id(constraint)} check (status in (${allowed}))`.execute(db);
1495
+ }
1496
+ };
1497
+ const up$12 = (db) => swap$1(db, "cancelled", "canceled");
1498
+ const down$12 = (db) => swap$1(db, "canceled", "cancelled");
1499
+ //#endregion
1462
1500
  //#region ../../apps/api/src/db/migrations/mysql/0001_baseline.ts
1463
1501
  var _0001_baseline_exports$1 = /* @__PURE__ */ __exportAll({
1464
- down: () => down$9,
1465
- up: () => up$9
1502
+ down: () => down$11,
1503
+ up: () => up$11
1466
1504
  });
1467
1505
  /**
1468
1506
  * MySQL baseline: Shapio's whole system schema as of PostgreSQL migration
@@ -2572,7 +2610,7 @@ const STATEMENTS$1 = [
2572
2610
  ('00000000-0000-4000-b000-000000000001', 'public', '00000000-0000-4000-a000-000000000001'),
2573
2611
  ('00000000-0000-4000-b000-000000000001', 'authenticated', '00000000-0000-4000-a000-000000000002')`
2574
2612
  ];
2575
- const TABLES$1 = [
2613
+ const TABLES$3 = [
2576
2614
  "system_versions",
2577
2615
  "jobs",
2578
2616
  "outbox_events",
@@ -2645,13 +2683,13 @@ const withoutForeignKeyChecks = async (db, statements) => db.connection().execut
2645
2683
  await sql`set foreign_key_checks = 1`.execute(connection);
2646
2684
  }
2647
2685
  });
2648
- const up$9 = async (db) => withoutForeignKeyChecks(db, STATEMENTS$1);
2649
- const down$9 = async (db) => withoutForeignKeyChecks(db, [...TABLES$1].reverse().map((table) => `drop table if exists \`${table}\``));
2686
+ const up$11 = async (db) => withoutForeignKeyChecks(db, STATEMENTS$1);
2687
+ const down$11 = async (db) => withoutForeignKeyChecks(db, [...TABLES$3].reverse().map((table) => `drop table if exists \`${table}\``));
2650
2688
  //#endregion
2651
2689
  //#region ../../apps/api/src/db/migrations/mysql/20261003170000_audit_events_seq.ts
2652
2690
  var _20261003170000_audit_events_seq_exports$1 = /* @__PURE__ */ __exportAll({
2653
- down: () => down$8,
2654
- up: () => up$8
2691
+ down: () => down$10,
2692
+ up: () => up$10
2655
2693
  });
2656
2694
  /**
2657
2695
  * MySQL twin of `../20261003170000_audit_events_seq.ts`: `seq` is `AUTO_INCREMENT`, which InnoDB only allows
@@ -2659,26 +2697,26 @@ var _20261003170000_audit_events_seq_exports$1 = /* @__PURE__ */ __exportAll({
2659
2697
  * tiebreaker). Existing rows are numbered in primary-key order. `db/mysql/tables.ts` lists `seq` as the
2660
2698
  * table's identity, so an insert's emulated RETURNING finds its row by `LAST_INSERT_ID()`.
2661
2699
  */
2662
- const up$8 = async (db) => {
2700
+ const up$10 = async (db) => {
2663
2701
  await sql`alter table \`audit_events\`
2664
2702
  add column \`seq\` bigint not null auto_increment,
2665
2703
  add unique key \`audit_events_seq_key\` (\`seq\`)`.execute(db);
2666
2704
  };
2667
- const down$8 = async (db) => {
2705
+ const down$10 = async (db) => {
2668
2706
  await sql`alter table \`audit_events\` drop column \`seq\``.execute(db);
2669
2707
  };
2670
2708
  //#endregion
2671
2709
  //#region ../../apps/api/src/db/migrations/mysql/20261004120000_models_site_scope.ts
2672
2710
  var _20261004120000_models_site_scope_exports$1 = /* @__PURE__ */ __exportAll({
2673
- down: () => down$7,
2674
- up: () => up$7
2711
+ down: () => down$9,
2712
+ up: () => up$9
2675
2713
  });
2676
2714
  /**
2677
2715
  * MySQL twin of `../20261004120000_models_site_scope.ts`. The per-scope API ID key uses functional key parts,
2678
2716
  * like the baseline: `coalesce(site_id, '')` for the scope (MySQL has no `NULLS NOT DISTINCT`) and the
2679
2717
  * case-folded API ID of live rows only (a deleted row's part is NULL, and NULLs never collide).
2680
2718
  */
2681
- const up$7 = async (db) => {
2719
+ const up$9 = async (db) => {
2682
2720
  await sql`alter table \`models\` add column \`site_id\` char(36) character set ascii collate ascii_general_ci`.execute(db);
2683
2721
  await sql`create index \`models_site_idx\` on \`models\` (\`site_id\`)`.execute(db);
2684
2722
  await sql`alter table \`models\` add constraint \`models_site_id_fkey\` foreign key (\`site_id\`) references \`sites\` (\`id\`)`.execute(db);
@@ -2687,7 +2725,7 @@ const up$7 = async (db) => {
2687
2725
  ((coalesce(\`site_id\`, '')), (case when (\`deleted_at\` IS NULL) then lower(\`api_key\`) end))`.execute(db);
2688
2726
  await sql`alter table \`schema_drafts\` add column \`shared\` tinyint(1) not null default 0`.execute(db);
2689
2727
  };
2690
- const down$7 = async (db) => {
2728
+ const down$9 = async (db) => {
2691
2729
  const { rows } = await sql`select count(*) as count from \`models\` where \`site_id\` is not null`.execute(db);
2692
2730
  if (Number(rows[0]?.count ?? 0) > 0) throw new Error("Cannot roll back per-site schema while definitions belong to a site: two sites may share an API ID. Share or delete the site definitions first.");
2693
2731
  await sql`alter table \`schema_drafts\` drop column \`shared\``.execute(db);
@@ -2701,8 +2739,8 @@ const down$7 = async (db) => {
2701
2739
  //#endregion
2702
2740
  //#region ../../apps/api/src/db/migrations/mysql/20261004130000_site_seo_settings.ts
2703
2741
  var _20261004130000_site_seo_settings_exports$1 = /* @__PURE__ */ __exportAll({
2704
- down: () => down$6,
2705
- up: () => up$6
2742
+ down: () => down$8,
2743
+ up: () => up$8
2706
2744
  });
2707
2745
  /**
2708
2746
  * MySQL twin of `../20261004130000_site_seo_settings.ts`. `insert ignore` stands in for `on conflict do
@@ -2710,7 +2748,7 @@ var _20261004130000_site_seo_settings_exports$1 = /* @__PURE__ */ __exportAll({
2710
2748
  */
2711
2749
  const bumpPermissionsVersion$1 = (db) => sql`update \`system_versions\` set \`permissions_version\` = \`permissions_version\` + 1,
2712
2750
  \`updated_at\` = current_timestamp(6)`.execute(db);
2713
- const up$6 = async (db) => {
2751
+ const up$8 = async (db) => {
2714
2752
  await sql`alter table \`sites\` add column \`seo_defaults\` json`.execute(db);
2715
2753
  const granted = await sql`
2716
2754
  insert ignore into \`admin_role_permissions\` (\`id\`, \`role_id\`, \`action\`, \`model_id\`, \`condition\`, \`field_ids\`)
@@ -2720,7 +2758,7 @@ const up$6 = async (db) => {
2720
2758
  `.execute(db);
2721
2759
  if (Number(granted.numAffectedRows ?? 0) > 0) await bumpPermissionsVersion$1(db);
2722
2760
  };
2723
- const down$6 = async (db) => {
2761
+ const down$8 = async (db) => {
2724
2762
  const revoked = await sql`delete from \`admin_role_permissions\` where \`action\` = 'site.settings'`.execute(db);
2725
2763
  if (Number(revoked.numAffectedRows ?? 0) > 0) await bumpPermissionsVersion$1(db);
2726
2764
  await sql`alter table \`sites\` drop column \`seo_defaults\``.execute(db);
@@ -2728,8 +2766,8 @@ const down$6 = async (db) => {
2728
2766
  //#endregion
2729
2767
  //#region ../../apps/api/src/db/migrations/mysql/20261005120000_entry_heads_entry_created_at.ts
2730
2768
  var _20261005120000_entry_heads_entry_created_at_exports$1 = /* @__PURE__ */ __exportAll({
2731
- down: () => down$5,
2732
- up: () => up$5
2769
+ down: () => down$7,
2770
+ up: () => up$7
2733
2771
  });
2734
2772
  /**
2735
2773
  * MySQL twin of `../20261005120000_entry_heads_entry_created_at.ts`. The column is added `ALGORITHM=INSTANT`
@@ -2738,7 +2776,7 @@ var _20261005120000_entry_heads_entry_created_at_exports$1 = /* @__PURE__ */ __e
2738
2776
  */
2739
2777
  const INDEX$1 = "entry_heads_entry_order_idx";
2740
2778
  const BATCH = 5e3;
2741
- const up$5 = async (db) => {
2779
+ const up$7 = async (db) => {
2742
2780
  await sql`alter table \`entry_heads\` add column \`entry_created_at\` datetime(6), algorithm=instant`.execute(db);
2743
2781
  for (;;) {
2744
2782
  const result = await sql`update \`entry_heads\` set \`entry_created_at\` = (
@@ -2749,11 +2787,48 @@ const up$5 = async (db) => {
2749
2787
  await sql`create index ${sql.id(INDEX$1)} on \`entry_heads\`
2750
2788
  (\`site_id\`, \`model_id\`, \`state\`, \`entry_created_at\` desc, \`entry_id\`) algorithm=inplace lock=none`.execute(db);
2751
2789
  };
2752
- const down$5 = async (db) => {
2790
+ const down$7 = async (db) => {
2753
2791
  await sql`drop index ${sql.id(INDEX$1)} on \`entry_heads\``.execute(db);
2754
2792
  await sql`alter table \`entry_heads\` drop column \`entry_created_at\``.execute(db);
2755
2793
  };
2756
2794
  //#endregion
2795
+ //#region ../../apps/api/src/db/migrations/mysql/20261014120000_canceled_status.ts
2796
+ var _20261014120000_canceled_status_exports$1 = /* @__PURE__ */ __exportAll({
2797
+ down: () => down$6,
2798
+ up: () => up$6
2799
+ });
2800
+ /**
2801
+ * MySQL twin of `../20261014120000_canceled_status.ts`: MySQL 8.4 drops a check constraint with
2802
+ * `drop check`, not `drop constraint`.
2803
+ */
2804
+ const TABLES$2 = [{
2805
+ table: "schema_change_jobs",
2806
+ values: [
2807
+ "pending",
2808
+ "running",
2809
+ "activated",
2810
+ "failed"
2811
+ ]
2812
+ }, {
2813
+ table: "scheduled_publications",
2814
+ values: [
2815
+ "scheduled",
2816
+ "done",
2817
+ "failed"
2818
+ ]
2819
+ }];
2820
+ const swap = async (db, from, to) => {
2821
+ for (const { table, values } of TABLES$2) {
2822
+ const constraint = `${table}_status_check`;
2823
+ await sql`alter table ${sql.table(table)} drop check ${sql.id(constraint)}`.execute(db);
2824
+ await sql`update ${sql.table(table)} set status = ${to} where status = ${from}`.execute(db);
2825
+ const allowed = sql.join([...values, to].map((value) => sql.lit(value)));
2826
+ await sql`alter table ${sql.table(table)} add constraint ${sql.id(constraint)} check (status in (${allowed}))`.execute(db);
2827
+ }
2828
+ };
2829
+ const up$6 = (db) => swap(db, "cancelled", "canceled");
2830
+ const down$6 = (db) => swap(db, "canceled", "cancelled");
2831
+ //#endregion
2757
2832
  //#region ../../apps/api/src/db/migrations/mysql/index.ts
2758
2833
  const MYSQL_MIGRATIONS = {
2759
2834
  "0001_baseline": _0001_baseline_exports$1,
@@ -2761,13 +2836,14 @@ const MYSQL_MIGRATIONS = {
2761
2836
  "20261004120000_models_site_scope": _20261004120000_models_site_scope_exports$1,
2762
2837
  "20261004130000_site_seo_settings": _20261004130000_site_seo_settings_exports$1,
2763
2838
  "20261005120000_entry_heads_entry_created_at": _20261005120000_entry_heads_entry_created_at_exports$1,
2764
- "20261006120000_system_versions_release": _20261006120000_system_versions_release_exports
2839
+ "20261006120000_system_versions_release": _20261006120000_system_versions_release_exports,
2840
+ "20261014120000_canceled_status": _20261014120000_canceled_status_exports$1
2765
2841
  };
2766
2842
  //#endregion
2767
2843
  //#region ../../apps/api/src/db/migrations/sqlite/0001_baseline.ts
2768
2844
  var _0001_baseline_exports = /* @__PURE__ */ __exportAll({
2769
- down: () => down$4,
2770
- up: () => up$4
2845
+ down: () => down$5,
2846
+ up: () => up$5
2771
2847
  });
2772
2848
  /**
2773
2849
  * SQLite baseline: Shapio's whole system schema as of PostgreSQL migration
@@ -3850,7 +3926,7 @@ const STATEMENTS = [
3850
3926
  ('00000000-0000-4000-b000-000000000001', 'public', '00000000-0000-4000-a000-000000000001'),
3851
3927
  ('00000000-0000-4000-b000-000000000001', 'authenticated', '00000000-0000-4000-a000-000000000002')`
3852
3928
  ];
3853
- const TABLES = [
3929
+ const TABLES$1 = [
3854
3930
  "system_versions",
3855
3931
  "jobs",
3856
3932
  "outbox_events",
@@ -3912,18 +3988,18 @@ const TABLES = [
3912
3988
  "assist_runs",
3913
3989
  "sequences"
3914
3990
  ];
3915
- const up$4 = async (db) => {
3991
+ const up$5 = async (db) => {
3916
3992
  for (const statement of STATEMENTS) await sql.raw(statement).execute(db);
3917
3993
  };
3918
- const down$4 = async (db) => {
3994
+ const down$5 = async (db) => {
3919
3995
  await sql`pragma defer_foreign_keys = on`.execute(db);
3920
- for (const table of [...TABLES].reverse()) await sql.raw(`drop table if exists "${table}"`).execute(db);
3996
+ for (const table of [...TABLES$1].reverse()) await sql.raw(`drop table if exists "${table}"`).execute(db);
3921
3997
  };
3922
3998
  //#endregion
3923
3999
  //#region ../../apps/api/src/db/migrations/sqlite/20261003170000_audit_events_seq.ts
3924
4000
  var _20261003170000_audit_events_seq_exports = /* @__PURE__ */ __exportAll({
3925
- down: () => down$3,
3926
- up: () => up$3
4001
+ down: () => down$4,
4002
+ up: () => up$4
3927
4003
  });
3928
4004
  /**
3929
4005
  * SQLite twin of `../20261003170000_audit_events_seq.ts`. SQLite cannot add a column whose default calls a
@@ -3950,7 +4026,7 @@ const INDEXES = [
3950
4026
  `create index "audit_events_occurred_at_idx" on "audit_events" (occurred_at DESC)`,
3951
4027
  `create index "audit_events_target_idx" on "audit_events" (target_type, target_id, occurred_at DESC)`
3952
4028
  ];
3953
- const up$3 = async (db) => {
4029
+ const up$4 = async (db) => {
3954
4030
  await sql`insert into "sequences" (name, value) values ('audit_events_seq', 0)`.execute(db);
3955
4031
  await sql`alter table "audit_events" rename to "audit_events_before_seq"`.execute(db);
3956
4032
  await sql`create table "audit_events" (
@@ -3978,15 +4054,15 @@ const up$3 = async (db) => {
3978
4054
  await sql`drop table "audit_events_before_seq"`.execute(db);
3979
4055
  for (const statement of INDEXES) await sql.raw(statement).execute(db);
3980
4056
  };
3981
- const down$3 = async (db) => {
4057
+ const down$4 = async (db) => {
3982
4058
  await sql`alter table "audit_events" drop column "seq"`.execute(db);
3983
4059
  await sql`delete from "sequences" where name = 'audit_events_seq'`.execute(db);
3984
4060
  };
3985
4061
  //#endregion
3986
4062
  //#region ../../apps/api/src/db/migrations/sqlite/20261004120000_models_site_scope.ts
3987
4063
  var _20261004120000_models_site_scope_exports = /* @__PURE__ */ __exportAll({
3988
- down: () => down$2,
3989
- up: () => up$2
4064
+ down: () => down$3,
4065
+ up: () => up$3
3990
4066
  });
3991
4067
  /**
3992
4068
  * SQLite twin of `../20261004120000_models_site_scope.ts`. `down` rebuilds `models` without `site_id`
@@ -3996,7 +4072,7 @@ var _20261004120000_models_site_scope_exports = /* @__PURE__ */ __exportAll({
3996
4072
  * deletes nothing they reference.
3997
4073
  */
3998
4074
  const NIL_UUID = "00000000-0000-0000-0000-000000000000";
3999
- const up$2 = async (db) => {
4075
+ const up$3 = async (db) => {
4000
4076
  await sql`alter table "models" add column "site_id" text_uuid references sites (id)`.execute(db);
4001
4077
  await sql`create index "models_site_idx" on "models" (site_id)`.execute(db);
4002
4078
  await sql`drop index "models_api_key_uq"`.execute(db);
@@ -4006,7 +4082,7 @@ const up$2 = async (db) => {
4006
4082
  `.execute(db);
4007
4083
  await sql`alter table "schema_drafts" add column "shared" integer_boolean not null default 0`.execute(db);
4008
4084
  };
4009
- const down$2 = async (db) => {
4085
+ const down$3 = async (db) => {
4010
4086
  const { rows } = await sql`select count(*) as count from "models" where site_id is not null`.execute(db);
4011
4087
  if (Number(rows[0]?.count ?? 0) > 0) throw new Error("Cannot roll back per-site schema while definitions belong to a site: two sites may share an API ID. Share or delete the site definitions first.");
4012
4088
  await sql`alter table "schema_drafts" drop column "shared"`.execute(db);
@@ -4031,15 +4107,15 @@ const down$2 = async (db) => {
4031
4107
  //#endregion
4032
4108
  //#region ../../apps/api/src/db/migrations/sqlite/20261004130000_site_seo_settings.ts
4033
4109
  var _20261004130000_site_seo_settings_exports = /* @__PURE__ */ __exportAll({
4034
- down: () => down$1,
4035
- up: () => up$1
4110
+ down: () => down$2,
4111
+ up: () => up$2
4036
4112
  });
4037
4113
  /**
4038
4114
  * SQLite twin of `../20261004130000_site_seo_settings.ts`. `insert or ignore` stands in for `on conflict do
4039
4115
  * nothing` (the grant's unique index); the permissions version moves only when a grant was added or removed.
4040
4116
  */
4041
4117
  const bumpPermissionsVersion = (db) => sql`update "system_versions" set permissions_version = permissions_version + 1, updated_at = shapio_now()`.execute(db);
4042
- const up$1 = async (db) => {
4118
+ const up$2 = async (db) => {
4043
4119
  await sql`alter table "sites" add column "seo_defaults" text_jsonb`.execute(db);
4044
4120
  const granted = await sql`
4045
4121
  insert or ignore into "admin_role_permissions" (role_id, action, model_id, condition, field_ids)
@@ -4049,7 +4125,7 @@ const up$1 = async (db) => {
4049
4125
  `.execute(db);
4050
4126
  if (Number(granted.numAffectedRows ?? 0) > 0) await bumpPermissionsVersion(db);
4051
4127
  };
4052
- const down$1 = async (db) => {
4128
+ const down$2 = async (db) => {
4053
4129
  const revoked = await sql`delete from "admin_role_permissions" where action = 'site.settings'`.execute(db);
4054
4130
  if (Number(revoked.numAffectedRows ?? 0) > 0) await bumpPermissionsVersion(db);
4055
4131
  await sql`alter table "sites" drop column "seo_defaults"`.execute(db);
@@ -4057,8 +4133,8 @@ const down$1 = async (db) => {
4057
4133
  //#endregion
4058
4134
  //#region ../../apps/api/src/db/migrations/sqlite/20261005120000_entry_heads_entry_created_at.ts
4059
4135
  var _20261005120000_entry_heads_entry_created_at_exports = /* @__PURE__ */ __exportAll({
4060
- down: () => down,
4061
- up: () => up
4136
+ down: () => down$1,
4137
+ up: () => up$1
4062
4138
  });
4063
4139
  /**
4064
4140
  * SQLite twin of `../20261005120000_entry_heads_entry_created_at.ts`. One process holds the write lock, so
@@ -4066,18 +4142,61 @@ var _20261005120000_entry_heads_entry_created_at_exports = /* @__PURE__ */ __exp
4066
4142
  * documented single-process limitation of ADR 0001, "D2: as built").
4067
4143
  */
4068
4144
  const INDEX = "entry_heads_entry_order_idx";
4069
- const up = async (db) => {
4145
+ const up$1 = async (db) => {
4070
4146
  await sql`alter table "entry_heads" add column "entry_created_at" text_timestamptz`.execute(db);
4071
4147
  await sql`update "entry_heads" set entry_created_at = (
4072
4148
  select e.created_at from "entries" e where e.id = "entry_heads".entry_id
4073
4149
  ) where entry_created_at is null`.execute(db);
4074
4150
  await sql`create index ${sql.id(INDEX)} on "entry_heads" (site_id, model_id, state, entry_created_at desc, entry_id)`.execute(db);
4075
4151
  };
4076
- const down = async (db) => {
4152
+ const down$1 = async (db) => {
4077
4153
  await sql`drop index if exists ${sql.id(INDEX)}`.execute(db);
4078
4154
  await sql`alter table "entry_heads" drop column "entry_created_at"`.execute(db);
4079
4155
  };
4080
4156
  //#endregion
4157
+ //#region ../../apps/api/src/db/migrations/sqlite/20261014120000_canceled_status.ts
4158
+ var _20261014120000_canceled_status_exports = /* @__PURE__ */ __exportAll({
4159
+ down: () => down,
4160
+ up: () => up
4161
+ });
4162
+ /**
4163
+ * SQLite twin of `../20261014120000_canceled_status.ts`. SQLite cannot change a check constraint, so each
4164
+ * table is rebuilt from its own stored `create table` statement with the one value swapped: renamed aside
4165
+ * (with `legacy_alter_table` on, so references to the name keep pointing at it), recreated, refilled with the
4166
+ * status rewritten, and its indexes recreated from `sqlite_master`. Nothing references either table.
4167
+ */
4168
+ const TABLES = ["schema_change_jobs", "scheduled_publications"];
4169
+ const rebuild = async (db, table, from, to) => {
4170
+ const { rows: created } = await sql`
4171
+ select sql from sqlite_master where type = 'table' and name = ${table}
4172
+ `.execute(db);
4173
+ const { rows: indexes } = await sql`
4174
+ select sql from sqlite_master where type = 'index' and tbl_name = ${table} and sql is not null
4175
+ `.execute(db);
4176
+ const definition = created[0]?.sql;
4177
+ if (!definition || !definition.includes(`'${from}'`)) throw new Error(`${table}: expected a status check allowing '${from}'`);
4178
+ const repaired = definition.replace(/references\s+("?)(\w+?)_before_\w+\1/gi, (_, quote, base) => `references ${quote}${base}${quote}`);
4179
+ const aside = `${table}_before_${to}`;
4180
+ await sql`pragma legacy_alter_table = on`.execute(db);
4181
+ await sql`alter table ${sql.table(table)} rename to ${sql.table(aside)}`.execute(db);
4182
+ await sql.raw(repaired.replace(`'${from}'`, `'${to}'`)).execute(db);
4183
+ const { rows: columns } = await sql`
4184
+ select name from pragma_table_info(${aside}) order by cid
4185
+ `.execute(db);
4186
+ const names = columns.map(({ name }) => sql.id(name));
4187
+ const values = columns.map(({ name }) => name === "status" ? sql`case when status = ${from} then ${to} else status end` : sql.id(name));
4188
+ await sql`insert into ${sql.table(table)} (${sql.join(names)}) select ${sql.join(values)} from ${sql.table(aside)}`.execute(db);
4189
+ await sql`drop table ${sql.table(aside)}`.execute(db);
4190
+ await sql`pragma legacy_alter_table = off`.execute(db);
4191
+ for (const { sql: index } of indexes) await sql.raw(index).execute(db);
4192
+ };
4193
+ const up = async (db) => {
4194
+ for (const table of TABLES) await rebuild(db, table, "cancelled", "canceled");
4195
+ };
4196
+ const down = async (db) => {
4197
+ for (const table of TABLES) await rebuild(db, table, "canceled", "cancelled");
4198
+ };
4199
+ //#endregion
4081
4200
  //#region ../../apps/api/src/db/migrations/sqlite/index.ts
4082
4201
  const SQLITE_MIGRATIONS = {
4083
4202
  "0001_baseline": _0001_baseline_exports,
@@ -4085,7 +4204,8 @@ const SQLITE_MIGRATIONS = {
4085
4204
  "20261004120000_models_site_scope": _20261004120000_models_site_scope_exports,
4086
4205
  "20261004130000_site_seo_settings": _20261004130000_site_seo_settings_exports,
4087
4206
  "20261005120000_entry_heads_entry_created_at": _20261005120000_entry_heads_entry_created_at_exports,
4088
- "20261006120000_system_versions_release": _20261006120000_system_versions_release_exports
4207
+ "20261006120000_system_versions_release": _20261006120000_system_versions_release_exports,
4208
+ "20261014120000_canceled_status": _20261014120000_canceled_status_exports
4089
4209
  };
4090
4210
  //#endregion
4091
4211
  //#region ../../apps/api/src/db/migrations/index.ts
@@ -4119,7 +4239,8 @@ const MIGRATIONS = {
4119
4239
  "20261004120000_models_site_scope": _20261004120000_models_site_scope_exports$2,
4120
4240
  "20261004130000_site_seo_settings": _20261004130000_site_seo_settings_exports$2,
4121
4241
  "20261005120000_entry_heads_entry_created_at": _20261005120000_entry_heads_entry_created_at_exports$2,
4122
- "20261006120000_system_versions_release": _20261006120000_system_versions_release_exports
4242
+ "20261006120000_system_versions_release": _20261006120000_system_versions_release_exports,
4243
+ "20261014120000_canceled_status": _20261014120000_canceled_status_exports$2
4123
4244
  };
4124
4245
  const PROVIDERS = {
4125
4246
  postgres: { getMigrations: () => Promise.resolve({ ...MIGRATIONS }) },
@@ -4149,4 +4270,4 @@ const getPendingMigrations = async (db) => {
4149
4270
  //#endregion
4150
4271
  export { getPendingMigrations };
4151
4272
 
4152
- //# sourceMappingURL=migrator-CO5sXosL.js.map
4273
+ //# sourceMappingURL=migrator-BfVtncOo.js.map