@catalyst-cloud/schema 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ // @catalyst-cloud/schema — the typed Drizzle SSOT for the Mirror DO store (CTC-13 / ADR-0002).
2
+ //
3
+ // Re-exports every table plus two consumption surfaces:
4
+ // • `mirrorSchema` — all tables, to pass as `drizzle(storage, { schema: mirrorSchema })` in the DO
5
+ // (and `drizzle(bunSqlite, …)` in the host-sync replica, `drizzle(sqliteProxy, …)` in the browser).
6
+ // • `MIRROR_TABLE_META` — per-ENTITY `{ pk, softDelete }` DERIVED from the schema via getTableConfig.
7
+ // This is what packages/replicate's applyDelta consumes to fold a change_log delta into a replica
8
+ // — replacing the hand-maintained `TABLES` map in apps/host-sync/src/apply.ts (the ADR-0002 "4th
9
+ // hand-copy" this schema deletes). Because it is derived, it can never drift from the table defs.
10
+ import { getTableConfig } from "drizzle-orm/sqlite-core";
11
+ import { issues, labels, users, issue_labels, relations, issue_history, projects, cycles, initiatives, project_initiatives, comments, pull_requests, check_runs, commit_statuses, reviews, processed_events, change_log, sync_cursors, } from "./mirror.js";
12
+ export * from "./mirror.js";
13
+ // The committed cross-surface migration bundle + the shared runner (CTC-41). Re-exported here so
14
+ // every consumer imports from the one package entrypoint: `applyMigrations(adapter, MIRROR_MIGRATIONS)`.
15
+ export { MIRROR_MIGRATIONS } from "./migrations.generated.js";
16
+ export { applyMigrations, } from "./migrate.js";
17
+ /** Every table in the Mirror DO store — pass as `drizzle(storage, { schema: mirrorSchema })`. */
18
+ export const mirrorSchema = {
19
+ issues,
20
+ labels,
21
+ users,
22
+ issue_labels,
23
+ relations,
24
+ issue_history,
25
+ projects,
26
+ cycles,
27
+ initiatives,
28
+ project_initiatives,
29
+ comments,
30
+ pull_requests,
31
+ check_runs,
32
+ commit_statuses,
33
+ reviews,
34
+ processed_events,
35
+ change_log,
36
+ sync_cursors,
37
+ };
38
+ /**
39
+ * The domain-entity tables that flow over the change-feed (the keys are the wire `entity` names). The
40
+ * infra tables — processed_events / change_log / sync_cursors — are deliberately excluded: they never
41
+ * ride a delta.
42
+ */
43
+ export const mirrorEntityTables = {
44
+ issues,
45
+ labels,
46
+ users,
47
+ issue_labels,
48
+ relations,
49
+ issue_history,
50
+ projects,
51
+ cycles,
52
+ initiatives,
53
+ project_initiatives,
54
+ comments,
55
+ pull_requests,
56
+ check_runs,
57
+ commit_statuses,
58
+ reviews,
59
+ };
60
+ /** Derive a table's PK columns + soft-delete posture from the Drizzle definition (no hand-maintenance). */
61
+ export function tableMeta(table) {
62
+ const cfg = getTableConfig(table);
63
+ // A single-column PK (`.primaryKey()`) marks the column `.primary`; a composite PK
64
+ // (`primaryKey({ columns })`) instead lands in cfg.primaryKeys. Cover both.
65
+ const singlePk = cfg.columns.filter((c) => c.primary).map((c) => c.name);
66
+ const compositePk = cfg.primaryKeys.flatMap((pk) => pk.columns.map((c) => c.name));
67
+ const pk = singlePk.length > 0 ? singlePk : compositePk;
68
+ const softDelete = cfg.columns.some((c) => c.name === "removed_at");
69
+ return { pk, softDelete };
70
+ }
71
+ /** Schema-derived replication metadata for every change-feed entity, keyed by wire `entity` name. */
72
+ export const MIRROR_TABLE_META = Object.fromEntries(Object.entries(mirrorEntityTables).map(([name, table]) => [name, tableMeta(table)]));
@@ -0,0 +1,36 @@
1
+ /** The minimal native SQLite surface the runner needs — one exec + one row-returning query. */
2
+ export interface MigrationDb {
3
+ /** Execute one or more SQL statements for side effect (no rows returned). */
4
+ exec(sql: string): void;
5
+ /** Run a query and return its rows as plain objects (column name → value). */
6
+ query(sql: string): Array<Record<string, unknown>>;
7
+ }
8
+ /** A journal entry as emitted by drizzle-kit into meta/_journal.json (and our committed bundle). */
9
+ export interface MigrationJournalEntry {
10
+ idx: number;
11
+ version: string;
12
+ when: number;
13
+ tag: string;
14
+ breakpoints: boolean;
15
+ }
16
+ /** The committed migration bundle shape: the drizzle journal + tag → SQL string map. */
17
+ export interface MigrationBundle {
18
+ journal: {
19
+ version: string;
20
+ dialect: string;
21
+ entries: readonly MigrationJournalEntry[];
22
+ };
23
+ migrations: Readonly<Record<string, string>>;
24
+ }
25
+ /**
26
+ * Apply every not-yet-applied migration in `bundle` to `db`, in journal `idx` order. Records each
27
+ * applied tag in `__drizzle_migrations` (the tag is the `hash` value). Pure, synchronous, and
28
+ * runtime-agnostic — every SQLite surface drives it through a thin `MigrationDb` adapter.
29
+ *
30
+ * @param now Optional timestamp (epoch ms) recorded as `created_at`. Defaults to `Date.now()` AT CALL
31
+ * TIME (never at import time), so the module can be imported into a Worker without a clock read.
32
+ * @returns the tags applied during THIS call (empty if the DB was already up to date).
33
+ */
34
+ export declare function applyMigrations(db: MigrationDb, bundle?: MigrationBundle, now?: number): {
35
+ appliedTags: string[];
36
+ };
@@ -22,43 +22,11 @@
22
22
  // 3. Do NOT pre-seed a drizzle-kit-NATIVE `__drizzle_migrations` (which stores SHA256 hashes) — this
23
23
  // runner keys on tags, so native-hash rows would be unrecognized and the baseline would re-run
24
24
  // (safe only while the baseline stays IF NOT EXISTS). This runner owns the ledger end to end.
25
-
26
- import { MIRROR_MIGRATIONS } from "./migrations.generated";
27
-
28
- /** The minimal native SQLite surface the runner needs — one exec + one row-returning query. */
29
- export interface MigrationDb {
30
- /** Execute one or more SQL statements for side effect (no rows returned). */
31
- exec(sql: string): void;
32
- /** Run a query and return its rows as plain objects (column name → value). */
33
- query(sql: string): Array<Record<string, unknown>>;
34
- }
35
-
36
- /** A journal entry as emitted by drizzle-kit into meta/_journal.json (and our committed bundle). */
37
- export interface MigrationJournalEntry {
38
- idx: number;
39
- version: string;
40
- when: number;
41
- tag: string;
42
- breakpoints: boolean;
43
- }
44
-
45
- /** The committed migration bundle shape: the drizzle journal + tag → SQL string map. */
46
- export interface MigrationBundle {
47
- journal: {
48
- version: string;
49
- dialect: string;
50
- entries: readonly MigrationJournalEntry[];
51
- };
52
- migrations: Readonly<Record<string, string>>;
53
- }
54
-
25
+ import { MIRROR_MIGRATIONS } from "./migrations.generated.js";
55
26
  /** The breakpoint marker drizzle-kit inserts between statements within one migration file. */
56
27
  const STATEMENT_BREAKPOINT = "--> statement-breakpoint";
57
-
58
- const LEDGER_DDL =
59
- "CREATE TABLE IF NOT EXISTS __drizzle_migrations (" +
60
- "id INTEGER PRIMARY KEY AUTOINCREMENT, hash TEXT NOT NULL, created_at INTEGER)";
61
-
28
+ const LEDGER_DDL = "CREATE TABLE IF NOT EXISTS __drizzle_migrations (" +
29
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, hash TEXT NOT NULL, created_at INTEGER)";
62
30
  /**
63
31
  * Apply every not-yet-applied migration in `bundle` to `db`, in journal `idx` order. Records each
64
32
  * applied tag in `__drizzle_migrations` (the tag is the `hash` value). Pure, synchronous, and
@@ -68,51 +36,37 @@ const LEDGER_DDL =
68
36
  * TIME (never at import time), so the module can be imported into a Worker without a clock read.
69
37
  * @returns the tags applied during THIS call (empty if the DB was already up to date).
70
38
  */
71
- export function applyMigrations(
72
- db: MigrationDb,
73
- bundle: MigrationBundle = MIRROR_MIGRATIONS,
74
- now: number = Date.now(),
75
- ): { appliedTags: string[] } {
76
- // 1) Ensure the ledger exists.
77
- db.exec(LEDGER_DDL);
78
-
79
- // 2) Read already-applied tags (stored in the `hash` column).
80
- const appliedRows = db.query("SELECT hash FROM __drizzle_migrations");
81
- const applied = new Set<string>(
82
- appliedRows.map((r) => String(r.hash)).filter((h) => h.length > 0),
83
- );
84
-
85
- // 3) Apply each journal entry not yet recorded, in idx order.
86
- const entries = [...bundle.journal.entries].sort((a, b) => a.idx - b.idx);
87
- const appliedTags: string[] = [];
88
-
89
- for (const entry of entries) {
90
- if (applied.has(entry.tag)) continue;
91
-
92
- const sql = bundle.migrations[entry.tag];
93
- if (sql === undefined) {
94
- throw new Error(`applyMigrations: journal tag "${entry.tag}" has no SQL in the bundle`);
39
+ export function applyMigrations(db, bundle = MIRROR_MIGRATIONS, now = Date.now()) {
40
+ // 1) Ensure the ledger exists.
41
+ db.exec(LEDGER_DDL);
42
+ // 2) Read already-applied tags (stored in the `hash` column).
43
+ const appliedRows = db.query("SELECT hash FROM __drizzle_migrations");
44
+ const applied = new Set(appliedRows.map((r) => String(r.hash)).filter((h) => h.length > 0));
45
+ // 3) Apply each journal entry not yet recorded, in idx order.
46
+ const entries = [...bundle.journal.entries].sort((a, b) => a.idx - b.idx);
47
+ const appliedTags = [];
48
+ for (const entry of entries) {
49
+ if (applied.has(entry.tag))
50
+ continue;
51
+ const sql = bundle.migrations[entry.tag];
52
+ if (sql === undefined) {
53
+ throw new Error(`applyMigrations: journal tag "${entry.tag}" has no SQL in the bundle`);
54
+ }
55
+ // Split on the breakpoint marker and exec each non-empty statement individually. (The DO's
56
+ // ctx.storage.sql.exec and bun:sqlite both accept multi-statement strings, but splitting keeps
57
+ // the runner portable to surfaces that don't, and matches drizzle-kit's own migrator.)
58
+ for (const raw of sql.split(STATEMENT_BREAKPOINT)) {
59
+ const stmt = raw.trim();
60
+ if (stmt.length === 0)
61
+ continue;
62
+ execReplaySafe(db, stmt);
63
+ }
64
+ // Record the tag (as the hash). A parameterless INSERT keeps the adapter surface to exec-only.
65
+ db.exec(`INSERT INTO __drizzle_migrations (hash, created_at) VALUES ('${escapeSqlLiteral(entry.tag)}', ${now})`);
66
+ appliedTags.push(entry.tag);
95
67
  }
96
-
97
- // Split on the breakpoint marker and exec each non-empty statement individually. (The DO's
98
- // ctx.storage.sql.exec and bun:sqlite both accept multi-statement strings, but splitting keeps
99
- // the runner portable to surfaces that don't, and matches drizzle-kit's own migrator.)
100
- for (const raw of sql.split(STATEMENT_BREAKPOINT)) {
101
- const stmt = raw.trim();
102
- if (stmt.length === 0) continue;
103
- execReplaySafe(db, stmt);
104
- }
105
-
106
- // Record the tag (as the hash). A parameterless INSERT keeps the adapter surface to exec-only.
107
- db.exec(
108
- `INSERT INTO __drizzle_migrations (hash, created_at) VALUES ('${escapeSqlLiteral(entry.tag)}', ${now})`,
109
- );
110
- appliedTags.push(entry.tag);
111
- }
112
-
113
- return { appliedTags };
68
+ return { appliedTags };
114
69
  }
115
-
116
70
  /**
117
71
  * Execute one migration statement, tolerating the three errors that make an additive migration
118
72
  * non-replay-safe when the run-once ledger guard is bypassed — e.g. a crash between a statement
@@ -129,19 +83,22 @@ export function applyMigrations(
129
83
  * tables were created from a newer `schema.sql` likewise adopts these additive tags as no-ops rather
130
84
  * than throwing. Only these idempotent cases are swallowed; any other SQL error still propagates.
131
85
  */
132
- function execReplaySafe(db: MigrationDb, stmt: string): void {
133
- try {
134
- db.exec(stmt);
135
- } catch (err) {
136
- const msg = err instanceof Error ? err.message : String(err);
137
- if (/duplicate column name/i.test(msg) && /\bADD\b/i.test(stmt)) return;
138
- if (/already exists/i.test(msg) && /\bCREATE\s+INDEX\b/i.test(stmt)) return;
139
- if (/already exists/i.test(msg) && /\bCREATE\s+TABLE\b/i.test(stmt)) return;
140
- throw err;
141
- }
86
+ function execReplaySafe(db, stmt) {
87
+ try {
88
+ db.exec(stmt);
89
+ }
90
+ catch (err) {
91
+ const msg = err instanceof Error ? err.message : String(err);
92
+ if (/duplicate column name/i.test(msg) && /\bADD\b/i.test(stmt))
93
+ return;
94
+ if (/already exists/i.test(msg) && /\bCREATE\s+INDEX\b/i.test(stmt))
95
+ return;
96
+ if (/already exists/i.test(msg) && /\bCREATE\s+TABLE\b/i.test(stmt))
97
+ return;
98
+ throw err;
99
+ }
142
100
  }
143
-
144
101
  /** Escape a string for use inside a single-quoted SQL literal (double any embedded single quote). */
145
- function escapeSqlLiteral(value: string): string {
146
- return value.replace(/'/g, "''");
102
+ function escapeSqlLiteral(value) {
103
+ return value.replace(/'/g, "''");
147
104
  }
@@ -0,0 +1,65 @@
1
+ export declare const MIRROR_MIGRATIONS: {
2
+ readonly journal: {
3
+ readonly version: "7";
4
+ readonly dialect: "sqlite";
5
+ readonly entries: readonly [{
6
+ readonly idx: 0;
7
+ readonly version: "6";
8
+ readonly when: 1782051267561;
9
+ readonly tag: "0000_baseline";
10
+ readonly breakpoints: true;
11
+ }, {
12
+ readonly idx: 1;
13
+ readonly version: "6";
14
+ readonly when: 1782110588498;
15
+ readonly tag: "0001_short_glorian";
16
+ readonly breakpoints: true;
17
+ }, {
18
+ readonly idx: 2;
19
+ readonly version: "6";
20
+ readonly when: 1782179798312;
21
+ readonly tag: "0002_many_captain_marvel";
22
+ readonly breakpoints: true;
23
+ }, {
24
+ readonly idx: 3;
25
+ readonly version: "6";
26
+ readonly when: 1782182056315;
27
+ readonly tag: "0003_brainy_silver_samurai";
28
+ readonly breakpoints: true;
29
+ }, {
30
+ readonly idx: 4;
31
+ readonly version: "6";
32
+ readonly when: 1782183082087;
33
+ readonly tag: "0004_fat_mindworm";
34
+ readonly breakpoints: true;
35
+ }, {
36
+ readonly idx: 5;
37
+ readonly version: "6";
38
+ readonly when: 1782184123941;
39
+ readonly tag: "0005_blue_black_queen";
40
+ readonly breakpoints: true;
41
+ }, {
42
+ readonly idx: 6;
43
+ readonly version: "6";
44
+ readonly when: 1782186590417;
45
+ readonly tag: "0006_lively_vector";
46
+ readonly breakpoints: true;
47
+ }, {
48
+ readonly idx: 7;
49
+ readonly version: "6";
50
+ readonly when: 1782229820186;
51
+ readonly tag: "0007_rapid_logan";
52
+ readonly breakpoints: true;
53
+ }];
54
+ };
55
+ readonly migrations: {
56
+ readonly "0000_baseline": "CREATE TABLE IF NOT EXISTS `change_log` (\n\t`seq` integer PRIMARY KEY AUTOINCREMENT NOT NULL,\n\t`entity` text,\n\t`entity_id` text,\n\t`op` text,\n\t`payload` text,\n\t`ts` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `check_runs` (\n\t`repo_id` text NOT NULL,\n\t`check_run_id` text PRIMARY KEY NOT NULL,\n\t`head_sha` text,\n\t`name` text,\n\t`status` text,\n\t`conclusion` text,\n\t`check_suite_id` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX IF NOT EXISTS `idx_check_runs_sha` ON `check_runs` (`head_sha`);--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `comments` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`issue_id` text,\n\t`body` text,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `commit_statuses` (\n\t`repo_id` text NOT NULL,\n\t`sha` text NOT NULL,\n\t`context` text NOT NULL,\n\t`state` text,\n\t`target_url` text,\n\t`updated_at` integer,\n\tPRIMARY KEY(`repo_id`, `sha`, `context`)\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `cycles` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`number` integer,\n\t`starts_at` integer,\n\t`ends_at` integer,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `issue_labels` (\n\t`issue_id` text NOT NULL,\n\t`label_id` text NOT NULL,\n\tPRIMARY KEY(`issue_id`, `label_id`)\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `issues` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`identifier` text,\n\t`title` text,\n\t`state` text,\n\t`assignee` text,\n\t`priority` integer,\n\t`estimate` real,\n\t`project_id` text,\n\t`cycle_id` text,\n\t`team_id` text,\n\t`updated_at` integer,\n\t`archived_at` integer,\n\t`removed_at` integer,\n\t`raw` text\n);\n--> statement-breakpoint\nCREATE INDEX IF NOT EXISTS `idx_issues_team` ON `issues` (`team_id`);--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `labels` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `processed_events` (\n\t`delivery_id` text PRIMARY KEY NOT NULL,\n\t`source` text,\n\t`event_type` text,\n\t`received_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `projects` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`state` text,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `pull_requests` (\n\t`repo_id` text NOT NULL,\n\t`number` integer NOT NULL,\n\t`node_id` text,\n\t`state` text,\n\t`draft` integer,\n\t`merged` integer,\n\t`merged_at` integer,\n\t`head_sha` text,\n\t`base_ref` text,\n\t`mergeable` integer,\n\t`mergeable_state` text,\n\t`auto_merge` integer,\n\t`updated_at` integer,\n\t`synced_at` integer,\n\tPRIMARY KEY(`repo_id`, `number`)\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `relations` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`type` text,\n\t`issue_identifier` text,\n\t`related_identifier` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX IF NOT EXISTS `idx_relations_issue` ON `relations` (`issue_identifier`);--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `reviews` (\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`review_id` text PRIMARY KEY NOT NULL,\n\t`user_id` text,\n\t`state` text,\n\t`submitted_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `sync_cursors` (\n\t`source` text NOT NULL,\n\t`entity` text NOT NULL,\n\t`cursor` text,\n\t`last_run_at` integer,\n\tPRIMARY KEY(`source`, `entity`)\n);\n";
57
+ readonly "0001_short_glorian": "ALTER TABLE `comments` ADD `author_id` text;--> statement-breakpoint\nALTER TABLE `comments` ADD `author_name` text;--> statement-breakpoint\nALTER TABLE `comments` ADD `author_avatar_url` text;--> statement-breakpoint\nALTER TABLE `comments` ADD `is_bot` integer;--> statement-breakpoint\nALTER TABLE `comments` ADD `parent_id` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `description` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `delegate_id` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `delegate_name` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `bot_actor_name` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `bot_actor_type` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `bot_actor_sub_type` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `parent_id` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `parent_identifier` text;--> statement-breakpoint\nALTER TABLE `labels` ADD `color` text;";
58
+ readonly "0002_many_captain_marvel": "CREATE INDEX `idx_comments_issue` ON `comments` (`issue_id`,`removed_at`,`updated_at`);--> statement-breakpoint\nCREATE INDEX `idx_issues_updated` ON `issues` (`removed_at`,`updated_at`);--> statement-breakpoint\nCREATE INDEX `idx_issues_identifier` ON `issues` (`identifier`);--> statement-breakpoint\nCREATE INDEX `idx_pulls_updated` ON `pull_requests` (`updated_at`);";
59
+ readonly "0003_brainy_silver_samurai": "ALTER TABLE `pull_requests` ADD `title` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `body` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `author_login` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `author_avatar_url` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `created_at` integer;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `closed_at` integer;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `comment_count` integer;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `milestone_title` text;";
60
+ readonly "0004_fat_mindworm": "ALTER TABLE `comments` ADD `created_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `started_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `completed_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `canceled_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `created_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `due_date` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `snoozed_until_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `url` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `priority_label` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `sort_order` real;--> statement-breakpoint\nALTER TABLE `issues` ADD `branch_name` text;--> statement-breakpoint\nCREATE INDEX `idx_issues_sort_order` ON `issues` (`sort_order`);";
61
+ readonly "0005_blue_black_queen": "CREATE TABLE `users` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`display_name` text,\n\t`avatar_url` text,\n\t`type` text,\n\t`source` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nALTER TABLE `issues` ADD `assignee_id` text;";
62
+ readonly "0006_lively_vector": "CREATE TABLE `initiatives` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`description` text,\n\t`status` text,\n\t`target_date` text,\n\t`owner_id` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE `project_initiatives` (\n\t`project_id` text NOT NULL,\n\t`initiative_id` text NOT NULL,\n\tPRIMARY KEY(`project_id`, `initiative_id`)\n);\n--> statement-breakpoint\nALTER TABLE `cycles` ADD `name` text;--> statement-breakpoint\nALTER TABLE `cycles` ADD `progress` real;--> statement-breakpoint\nALTER TABLE `cycles` ADD `completed_scope` real;--> statement-breakpoint\nALTER TABLE `cycles` ADD `scope` real;--> statement-breakpoint\nALTER TABLE `cycles` ADD `completed_issue_count` integer;--> statement-breakpoint\nALTER TABLE `cycles` ADD `issue_count` integer;--> statement-breakpoint\nALTER TABLE `projects` ADD `description` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `lead_id` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `target_date` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `start_date` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `progress` real;--> statement-breakpoint\nALTER TABLE `projects` ADD `health` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `icon` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `color` text;";
63
+ readonly "0007_rapid_logan": "CREATE TABLE `issue_history` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`issue_id` text NOT NULL,\n\t`actor_id` text,\n\t`created_at` integer,\n\t`updated_at` integer,\n\t`from_state` text,\n\t`to_state` text,\n\t`from_assignee_id` text,\n\t`to_assignee_id` text,\n\t`from_priority` integer,\n\t`to_priority` integer,\n\t`from_estimate` real,\n\t`to_estimate` real,\n\t`from_title` text,\n\t`to_title` text,\n\t`from_cycle_id` text,\n\t`to_cycle_id` text,\n\t`from_project_id` text,\n\t`to_project_id` text,\n\t`from_parent_id` text,\n\t`to_parent_id` text,\n\t`from_team_id` text,\n\t`to_team_id` text,\n\t`from_due_date` text,\n\t`to_due_date` text,\n\t`added_label_ids` text,\n\t`removed_label_ids` text,\n\t`updated_description` integer,\n\t`archived` integer,\n\t`auto_archived` integer,\n\t`auto_closed` integer,\n\t`trashed` integer,\n\t`raw` text\n);\n--> statement-breakpoint\nCREATE INDEX `idx_issue_history_issue_created` ON `issue_history` (`issue_id`,`created_at`);";
64
+ };
65
+ };
@@ -0,0 +1,81 @@
1
+ // AUTO-GENERATED by scripts/build-bundle.ts — DO NOT EDIT BY HAND.
2
+ //
3
+ // The committed Mirror migration bundle (CTC-41): the drizzle-kit journal + every migration SQL as a
4
+ // string literal (NO `.sql`-as-import), so the SAME module imports cleanly in the DO (Workers), the
5
+ // bun daemon, node tests, and the browser. Regenerate via `bun run --cwd packages/schema build:bundle`
6
+ // (or the root `migration:generate`). The CI drift gate (`migration:check`) fails if this file is
7
+ // stale vs drizzle/.
8
+ export const MIRROR_MIGRATIONS = {
9
+ journal: {
10
+ version: "7",
11
+ dialect: "sqlite",
12
+ entries: [
13
+ {
14
+ idx: 0,
15
+ version: "6",
16
+ when: 1782051267561,
17
+ tag: "0000_baseline",
18
+ breakpoints: true,
19
+ },
20
+ {
21
+ idx: 1,
22
+ version: "6",
23
+ when: 1782110588498,
24
+ tag: "0001_short_glorian",
25
+ breakpoints: true,
26
+ },
27
+ {
28
+ idx: 2,
29
+ version: "6",
30
+ when: 1782179798312,
31
+ tag: "0002_many_captain_marvel",
32
+ breakpoints: true,
33
+ },
34
+ {
35
+ idx: 3,
36
+ version: "6",
37
+ when: 1782182056315,
38
+ tag: "0003_brainy_silver_samurai",
39
+ breakpoints: true,
40
+ },
41
+ {
42
+ idx: 4,
43
+ version: "6",
44
+ when: 1782183082087,
45
+ tag: "0004_fat_mindworm",
46
+ breakpoints: true,
47
+ },
48
+ {
49
+ idx: 5,
50
+ version: "6",
51
+ when: 1782184123941,
52
+ tag: "0005_blue_black_queen",
53
+ breakpoints: true,
54
+ },
55
+ {
56
+ idx: 6,
57
+ version: "6",
58
+ when: 1782186590417,
59
+ tag: "0006_lively_vector",
60
+ breakpoints: true,
61
+ },
62
+ {
63
+ idx: 7,
64
+ version: "6",
65
+ when: 1782229820186,
66
+ tag: "0007_rapid_logan",
67
+ breakpoints: true,
68
+ },
69
+ ],
70
+ },
71
+ migrations: {
72
+ "0000_baseline": "CREATE TABLE IF NOT EXISTS `change_log` (\n\t`seq` integer PRIMARY KEY AUTOINCREMENT NOT NULL,\n\t`entity` text,\n\t`entity_id` text,\n\t`op` text,\n\t`payload` text,\n\t`ts` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `check_runs` (\n\t`repo_id` text NOT NULL,\n\t`check_run_id` text PRIMARY KEY NOT NULL,\n\t`head_sha` text,\n\t`name` text,\n\t`status` text,\n\t`conclusion` text,\n\t`check_suite_id` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX IF NOT EXISTS `idx_check_runs_sha` ON `check_runs` (`head_sha`);--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `comments` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`issue_id` text,\n\t`body` text,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `commit_statuses` (\n\t`repo_id` text NOT NULL,\n\t`sha` text NOT NULL,\n\t`context` text NOT NULL,\n\t`state` text,\n\t`target_url` text,\n\t`updated_at` integer,\n\tPRIMARY KEY(`repo_id`, `sha`, `context`)\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `cycles` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`number` integer,\n\t`starts_at` integer,\n\t`ends_at` integer,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `issue_labels` (\n\t`issue_id` text NOT NULL,\n\t`label_id` text NOT NULL,\n\tPRIMARY KEY(`issue_id`, `label_id`)\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `issues` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`identifier` text,\n\t`title` text,\n\t`state` text,\n\t`assignee` text,\n\t`priority` integer,\n\t`estimate` real,\n\t`project_id` text,\n\t`cycle_id` text,\n\t`team_id` text,\n\t`updated_at` integer,\n\t`archived_at` integer,\n\t`removed_at` integer,\n\t`raw` text\n);\n--> statement-breakpoint\nCREATE INDEX IF NOT EXISTS `idx_issues_team` ON `issues` (`team_id`);--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `labels` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `processed_events` (\n\t`delivery_id` text PRIMARY KEY NOT NULL,\n\t`source` text,\n\t`event_type` text,\n\t`received_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `projects` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`state` text,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `pull_requests` (\n\t`repo_id` text NOT NULL,\n\t`number` integer NOT NULL,\n\t`node_id` text,\n\t`state` text,\n\t`draft` integer,\n\t`merged` integer,\n\t`merged_at` integer,\n\t`head_sha` text,\n\t`base_ref` text,\n\t`mergeable` integer,\n\t`mergeable_state` text,\n\t`auto_merge` integer,\n\t`updated_at` integer,\n\t`synced_at` integer,\n\tPRIMARY KEY(`repo_id`, `number`)\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `relations` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`type` text,\n\t`issue_identifier` text,\n\t`related_identifier` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX IF NOT EXISTS `idx_relations_issue` ON `relations` (`issue_identifier`);--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `reviews` (\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`review_id` text PRIMARY KEY NOT NULL,\n\t`user_id` text,\n\t`state` text,\n\t`submitted_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE IF NOT EXISTS `sync_cursors` (\n\t`source` text NOT NULL,\n\t`entity` text NOT NULL,\n\t`cursor` text,\n\t`last_run_at` integer,\n\tPRIMARY KEY(`source`, `entity`)\n);\n",
73
+ "0001_short_glorian": "ALTER TABLE `comments` ADD `author_id` text;--> statement-breakpoint\nALTER TABLE `comments` ADD `author_name` text;--> statement-breakpoint\nALTER TABLE `comments` ADD `author_avatar_url` text;--> statement-breakpoint\nALTER TABLE `comments` ADD `is_bot` integer;--> statement-breakpoint\nALTER TABLE `comments` ADD `parent_id` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `description` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `delegate_id` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `delegate_name` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `bot_actor_name` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `bot_actor_type` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `bot_actor_sub_type` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `parent_id` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `parent_identifier` text;--> statement-breakpoint\nALTER TABLE `labels` ADD `color` text;",
74
+ "0002_many_captain_marvel": "CREATE INDEX `idx_comments_issue` ON `comments` (`issue_id`,`removed_at`,`updated_at`);--> statement-breakpoint\nCREATE INDEX `idx_issues_updated` ON `issues` (`removed_at`,`updated_at`);--> statement-breakpoint\nCREATE INDEX `idx_issues_identifier` ON `issues` (`identifier`);--> statement-breakpoint\nCREATE INDEX `idx_pulls_updated` ON `pull_requests` (`updated_at`);",
75
+ "0003_brainy_silver_samurai": "ALTER TABLE `pull_requests` ADD `title` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `body` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `author_login` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `author_avatar_url` text;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `created_at` integer;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `closed_at` integer;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `comment_count` integer;--> statement-breakpoint\nALTER TABLE `pull_requests` ADD `milestone_title` text;",
76
+ "0004_fat_mindworm": "ALTER TABLE `comments` ADD `created_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `started_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `completed_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `canceled_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `created_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `due_date` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `snoozed_until_at` integer;--> statement-breakpoint\nALTER TABLE `issues` ADD `url` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `priority_label` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `sort_order` real;--> statement-breakpoint\nALTER TABLE `issues` ADD `branch_name` text;--> statement-breakpoint\nCREATE INDEX `idx_issues_sort_order` ON `issues` (`sort_order`);",
77
+ "0005_blue_black_queen": "CREATE TABLE `users` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`display_name` text,\n\t`avatar_url` text,\n\t`type` text,\n\t`source` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nALTER TABLE `issues` ADD `assignee_id` text;",
78
+ "0006_lively_vector": "CREATE TABLE `initiatives` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`name` text,\n\t`description` text,\n\t`status` text,\n\t`target_date` text,\n\t`owner_id` text,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE TABLE `project_initiatives` (\n\t`project_id` text NOT NULL,\n\t`initiative_id` text NOT NULL,\n\tPRIMARY KEY(`project_id`, `initiative_id`)\n);\n--> statement-breakpoint\nALTER TABLE `cycles` ADD `name` text;--> statement-breakpoint\nALTER TABLE `cycles` ADD `progress` real;--> statement-breakpoint\nALTER TABLE `cycles` ADD `completed_scope` real;--> statement-breakpoint\nALTER TABLE `cycles` ADD `scope` real;--> statement-breakpoint\nALTER TABLE `cycles` ADD `completed_issue_count` integer;--> statement-breakpoint\nALTER TABLE `cycles` ADD `issue_count` integer;--> statement-breakpoint\nALTER TABLE `projects` ADD `description` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `lead_id` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `target_date` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `start_date` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `progress` real;--> statement-breakpoint\nALTER TABLE `projects` ADD `health` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `icon` text;--> statement-breakpoint\nALTER TABLE `projects` ADD `color` text;",
79
+ "0007_rapid_logan": "CREATE TABLE `issue_history` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`issue_id` text NOT NULL,\n\t`actor_id` text,\n\t`created_at` integer,\n\t`updated_at` integer,\n\t`from_state` text,\n\t`to_state` text,\n\t`from_assignee_id` text,\n\t`to_assignee_id` text,\n\t`from_priority` integer,\n\t`to_priority` integer,\n\t`from_estimate` real,\n\t`to_estimate` real,\n\t`from_title` text,\n\t`to_title` text,\n\t`from_cycle_id` text,\n\t`to_cycle_id` text,\n\t`from_project_id` text,\n\t`to_project_id` text,\n\t`from_parent_id` text,\n\t`to_parent_id` text,\n\t`from_team_id` text,\n\t`to_team_id` text,\n\t`from_due_date` text,\n\t`to_due_date` text,\n\t`added_label_ids` text,\n\t`removed_label_ids` text,\n\t`updated_description` integer,\n\t`archived` integer,\n\t`auto_archived` integer,\n\t`auto_closed` integer,\n\t`trashed` integer,\n\t`raw` text\n);\n--> statement-breakpoint\nCREATE INDEX `idx_issue_history_issue_created` ON `issue_history` (`issue_id`,`created_at`);",
80
+ },
81
+ };