@catalyst-cloud/schema 0.1.13 → 0.1.14
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/package.json +1 -1
- package/src/index.ts +6 -0
- package/src/migrations.generated.ts +9 -0
- package/src/mirror.ts +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@catalyst-cloud/schema",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Typed Drizzle schema = single source of truth for the per-tenant Mirror DO SQLite store (CTC-13 / ADR-0002). Shared by the mirror Worker, the host-sync replica, and the browser OPFS replica.",
|
|
6
6
|
"license": "MIT",
|
package/src/index.ts
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
pr_commits,
|
|
42
42
|
pr_events,
|
|
43
43
|
pr_ancillary_backfill,
|
|
44
|
+
push_subscriptions,
|
|
44
45
|
} from "./mirror.js";
|
|
45
46
|
|
|
46
47
|
export * from "./mirror.js";
|
|
@@ -112,6 +113,9 @@ export const mirrorSchema = {
|
|
|
112
113
|
pr_commits,
|
|
113
114
|
pr_events,
|
|
114
115
|
pr_ancillary_backfill,
|
|
116
|
+
// CTC-619: a member's Web Push subscription. Rides the change feed like any other entity — a
|
|
117
|
+
// member-facing settings UI can reflect subscribe/unsubscribe reactively.
|
|
118
|
+
push_subscriptions,
|
|
115
119
|
} as const;
|
|
116
120
|
|
|
117
121
|
/**
|
|
@@ -157,6 +161,8 @@ export const mirrorEntityTables = {
|
|
|
157
161
|
pr_conversation_comments,
|
|
158
162
|
pr_commits,
|
|
159
163
|
pr_events,
|
|
164
|
+
// CTC-619: a member's Web Push subscription.
|
|
165
|
+
push_subscriptions,
|
|
160
166
|
} as const;
|
|
161
167
|
|
|
162
168
|
/** The wire `entity` name of a change-feed-carried table (keys of mirrorEntityTables). */
|
|
@@ -172,6 +172,13 @@ export const MIRROR_MIGRATIONS = {
|
|
|
172
172
|
tag: "0022_chilly_gorgon",
|
|
173
173
|
breakpoints: true,
|
|
174
174
|
},
|
|
175
|
+
{
|
|
176
|
+
idx: 23,
|
|
177
|
+
version: "6",
|
|
178
|
+
when: 1786935258669,
|
|
179
|
+
tag: "0023_ambiguous_micromax",
|
|
180
|
+
breakpoints: true,
|
|
181
|
+
},
|
|
175
182
|
],
|
|
176
183
|
},
|
|
177
184
|
migrations: {
|
|
@@ -219,5 +226,7 @@ export const MIRROR_MIGRATIONS = {
|
|
|
219
226
|
"CREATE TABLE `pr_ancillary_backfill` (\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`backfilled_at` integer NOT NULL,\n\tPRIMARY KEY(`repo_id`, `pr_number`)\n);\n--> statement-breakpoint\nCREATE TABLE `pr_commits` (\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`sha` text NOT NULL,\n\t`message` text,\n\t`author_login` text,\n\t`author_name` text,\n\t`author_email` text,\n\t`authored_at` integer,\n\t`committed_at` integer,\n\tPRIMARY KEY(`repo_id`, `pr_number`, `sha`)\n);\n--> statement-breakpoint\nCREATE TABLE `pr_conversation_comments` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`author_id` text,\n\t`body` text,\n\t`created_at` integer,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_pr_conversation_comments_pr` ON `pr_conversation_comments` (`repo_id`,`pr_number`);--> statement-breakpoint\nCREATE TABLE `pr_events` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`action` text,\n\t`actor_id` text,\n\t`created_at` integer,\n\t`updated_at` integer,\n\t`raw` text\n);\n--> statement-breakpoint\nCREATE INDEX `idx_pr_events_pr` ON `pr_events` (`repo_id`,`pr_number`,`created_at`);--> statement-breakpoint\nCREATE TABLE `pr_review_comments` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`repo_id` text NOT NULL,\n\t`pr_number` integer NOT NULL,\n\t`review_id` text,\n\t`commit_id` text,\n\t`path` text,\n\t`line` integer,\n\t`diff_hunk` text,\n\t`in_reply_to_id` text,\n\t`author_id` text,\n\t`body` text,\n\t`created_at` integer,\n\t`updated_at` integer,\n\t`removed_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_pr_review_comments_pr` ON `pr_review_comments` (`repo_id`,`pr_number`);",
|
|
220
227
|
"0022_chilly_gorgon":
|
|
221
228
|
"CREATE TABLE `workflow_states` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`team_id` text,\n\t`name` text,\n\t`type` text,\n\t`position` real,\n\t`color` text,\n\t`archived_at` integer,\n\t`updated_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_workflow_states_team` ON `workflow_states` (`team_id`);--> statement-breakpoint\nALTER TABLE `issues` ADD `state_type` text;--> statement-breakpoint\nALTER TABLE `issues` ADD `state_position` real;",
|
|
229
|
+
"0023_ambiguous_micromax":
|
|
230
|
+
"CREATE TABLE `push_subscriptions` (\n\t`endpoint` text PRIMARY KEY NOT NULL,\n\t`member_id` text NOT NULL,\n\t`p256dh` text NOT NULL,\n\t`auth` text NOT NULL,\n\t`created_at` integer,\n\t`last_used_at` integer\n);\n--> statement-breakpoint\nCREATE INDEX `idx_push_subscriptions_member` ON `push_subscriptions` (`member_id`);",
|
|
222
231
|
},
|
|
223
232
|
} as const;
|
package/src/mirror.ts
CHANGED
|
@@ -851,3 +851,25 @@ export const pr_ancillary_backfill = sqliteTable(
|
|
|
851
851
|
},
|
|
852
852
|
(t) => [primaryKey({ columns: [t.repo_id, t.pr_number] })],
|
|
853
853
|
);
|
|
854
|
+
|
|
855
|
+
// CTC-619 — a member's Web Push subscription (one browser/device). PK is the subscription `endpoint`
|
|
856
|
+
// itself — a push endpoint URL is unique per browser install by construction, so keying on it is what
|
|
857
|
+
// makes "a duplicate subscribe for the same endpoint does not create a second row" (the ticket's own
|
|
858
|
+
// AC) a plain upsert, no synthetic id needed. `member_id` is the Linear user id (FK-shaped to
|
|
859
|
+
// users.id, same as issues.assignee_id) — the ingest trigger's own correlation key. HARD delete on
|
|
860
|
+
// unsubscribe (no removed_at): a stale/revoked push subscription has no historical value, matching
|
|
861
|
+
// `users`' own "HARD-UPSERT, no soft delete" precedent for similarly overwrite-in-place data.
|
|
862
|
+
export const push_subscriptions = sqliteTable(
|
|
863
|
+
"push_subscriptions",
|
|
864
|
+
{
|
|
865
|
+
endpoint: text("endpoint").primaryKey(),
|
|
866
|
+
member_id: text("member_id").notNull(),
|
|
867
|
+
p256dh: text("p256dh").notNull(),
|
|
868
|
+
auth: text("auth").notNull(),
|
|
869
|
+
created_at: integer("created_at"),
|
|
870
|
+
last_used_at: integer("last_used_at"),
|
|
871
|
+
},
|
|
872
|
+
// The ingest trigger's own read pattern: "every subscription for this member" (member_id, NOT the
|
|
873
|
+
// PK), keyed off issues.assignee_id — the same shape idx_workflow_states_team indexes on team_id.
|
|
874
|
+
(t) => [index("idx_push_subscriptions_member").on(t.member_id)],
|
|
875
|
+
);
|