@storyshelf/db-postgres 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +56 -0
  2. package/dist/ddl.d.mts +1 -1
  3. package/dist/ddl.mjs +209 -13
  4. package/dist/ddl.mjs.map +1 -1
  5. package/dist/index.mjs +1 -1
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/migrate.mjs +83 -3
  8. package/dist/migrate.mjs.map +1 -1
  9. package/dist/neon-http.mjs +1 -1
  10. package/dist/neon-http.mjs.map +1 -1
  11. package/dist/neon.mjs +1 -1
  12. package/dist/neon.mjs.map +1 -1
  13. package/dist/pg.mjs +1 -1
  14. package/dist/pg.mjs.map +1 -1
  15. package/dist/pglite.mjs +2 -2
  16. package/dist/pglite.mjs.map +1 -1
  17. package/dist/schema/baseline.d.mts +54 -0
  18. package/dist/schema/baseline.mjs +4 -1
  19. package/dist/schema/baseline.mjs.map +1 -1
  20. package/dist/schema/{status-config.d.mts → build-component.d.mts} +42 -35
  21. package/dist/schema/build-component.mjs +25 -0
  22. package/dist/schema/build-component.mjs.map +1 -0
  23. package/dist/schema/build-review.d.mts +118 -0
  24. package/dist/schema/build-review.mjs +23 -0
  25. package/dist/schema/build-review.mjs.map +1 -0
  26. package/dist/schema/build.d.mts +38 -2
  27. package/dist/schema/build.mjs +3 -0
  28. package/dist/schema/build.mjs.map +1 -1
  29. package/dist/schema/capture-job.d.mts +330 -0
  30. package/dist/schema/capture-job.mjs +56 -0
  31. package/dist/schema/capture-job.mjs.map +1 -0
  32. package/dist/schema/capture-shard.d.mts +257 -0
  33. package/dist/schema/capture-shard.mjs +40 -0
  34. package/dist/schema/capture-shard.mjs.map +1 -0
  35. package/dist/schema/comment.d.mts +18 -0
  36. package/dist/schema/comment.mjs +3 -2
  37. package/dist/schema/comment.mjs.map +1 -1
  38. package/dist/schema/connection.d.mts +173 -0
  39. package/dist/schema/connection.mjs +35 -0
  40. package/dist/schema/connection.mjs.map +1 -0
  41. package/dist/schema/design.d.mts +589 -0
  42. package/dist/schema/design.mjs +73 -0
  43. package/dist/schema/design.mjs.map +1 -0
  44. package/dist/schema/insight.d.mts +633 -0
  45. package/dist/schema/insight.mjs +68 -0
  46. package/dist/schema/insight.mjs.map +1 -0
  47. package/dist/schema/notification.d.mts +36 -0
  48. package/dist/schema/notification.mjs +5 -0
  49. package/dist/schema/notification.mjs.map +1 -1
  50. package/dist/schema/project.d.mts +126 -0
  51. package/dist/schema/project.mjs +8 -1
  52. package/dist/schema/project.mjs.map +1 -1
  53. package/dist/schema/site-setting.d.mts +99 -0
  54. package/dist/schema/site-setting.mjs +23 -0
  55. package/dist/schema/site-setting.mjs.map +1 -0
  56. package/dist/schema/snapshot.d.mts +108 -0
  57. package/dist/schema/snapshot.mjs +11 -1
  58. package/dist/schema/snapshot.mjs.map +1 -1
  59. package/dist/schema/usage.d.mts +267 -0
  60. package/dist/schema/usage.mjs +36 -0
  61. package/dist/schema/usage.mjs.map +1 -0
  62. package/dist/schema.d.mts +24 -3
  63. package/dist/schema.mjs +25 -4
  64. package/dist/schema.mjs.map +1 -1
  65. package/dist/vercel.mjs +1 -1
  66. package/dist/vercel.mjs.map +1 -1
  67. package/package.json +5 -5
  68. package/dist/schema/status-config.mjs +0 -26
  69. package/dist/schema/status-config.mjs.map +0 -1
package/dist/migrate.mjs CHANGED
@@ -13,23 +13,42 @@ import { DDL } from "./ddl.mjs";
13
13
  const STORYBOOK_META_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS storybook_meta TEXT";
14
14
  const EXECUTE_PLAY_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS execute_play BOOLEAN NOT NULL DEFAULT false";
15
15
  const PLAY_TIMEOUT_MS_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS play_timeout_ms INTEGER NOT NULL DEFAULT 10000";
16
- const RUN_A11Y_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS run_a11y BOOLEAN NOT NULL DEFAULT false";
16
+ const RUN_A11Y_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS run_a11y BOOLEAN NOT NULL DEFAULT true";
17
+ const RUN_A11Y_DEFAULT_ALTER = "ALTER TABLE projects ALTER COLUMN run_a11y SET DEFAULT true";
17
18
  const PROJECT_BROWSER_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS browser TEXT NOT NULL DEFAULT 'chromium'";
18
19
  const PROJECT_VIEWPORTS_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS viewports TEXT";
19
20
  const PROJECT_AUTOMIGRATE_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS automigrate BOOLEAN NOT NULL DEFAULT false";
21
+ const PROJECT_AI_PROFILE_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS ai_profile TEXT";
22
+ const PROJECT_REVIEW_ENABLED_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS review_enabled BOOLEAN NOT NULL DEFAULT true";
23
+ const PROJECT_REVIEW_APPROVALS_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS review_approvals INTEGER NOT NULL DEFAULT 1";
24
+ const PROJECT_STORYBOOK_URL_TTL_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS storybook_url_ttl_seconds INTEGER";
20
25
  const SNAPSHOT_INFRA_HASH_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS infra_hash TEXT";
21
26
  const SNAPSHOT_INHERITED_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS inherited BOOLEAN NOT NULL DEFAULT false";
22
27
  const SNAPSHOT_BASELINE_ID_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS baseline_id TEXT";
23
28
  const SNAPSHOT_BASELINE_VERSION_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS baseline_version TEXT";
29
+ const SNAPSHOT_ENV_CHANGE_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS env_change TEXT";
30
+ const SNAPSHOT_DESIGN_URL_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS design_url TEXT";
31
+ const SNAPSHOT_DURATION_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS duration_ms INTEGER";
32
+ const SNAPSHOT_A11Y_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS a11y_violations TEXT";
33
+ const DESIGN_LINKS_UNIQUE_INDEX = "CREATE UNIQUE INDEX IF NOT EXISTS design_links_project_import_path_idx ON design_links (project_id, import_path)";
34
+ /** Pre-adapter Figma tables (replaced by design_nodes / design_credentials; no data is carried over). */
35
+ const LEGACY_DESIGN_DROPS = ["DROP TABLE IF EXISTS figma_nodes", "DROP TABLE IF EXISTS design_tokens"];
36
+ const BASELINE_FINGERPRINT_ALTER = "ALTER TABLE baselines ADD COLUMN IF NOT EXISTS fingerprint TEXT";
24
37
  const BASELINE_INFRA_HASH_ALTER = "ALTER TABLE baselines ADD COLUMN IF NOT EXISTS infra_hash TEXT";
25
38
  const BUILD_AFFECTED_ONLY_ALTER = "ALTER TABLE builds ADD COLUMN IF NOT EXISTS affected_only BOOLEAN NOT NULL DEFAULT true";
26
39
  const BUILD_BASELINE_SHA_ALTER = "ALTER TABLE builds ADD COLUMN IF NOT EXISTS baseline_sha TEXT";
27
40
  const BUILD_CHANGED_FILES_ALTER = "ALTER TABLE builds ADD COLUMN IF NOT EXISTS changed_files TEXT";
28
41
  const BUILD_AFFECTED_PATHS_ALTER = "ALTER TABLE builds ADD COLUMN IF NOT EXISTS affected_import_paths TEXT";
42
+ const BUILD_INHERITED_COUNT_ALTER = "ALTER TABLE builds ADD COLUMN IF NOT EXISTS inherited_count INTEGER NOT NULL DEFAULT 0";
43
+ const BUILD_TEST_RESULTS_ALTER = "ALTER TABLE builds ADD COLUMN IF NOT EXISTS test_results TEXT";
44
+ const RUN_TESTS_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS run_tests BOOLEAN NOT NULL DEFAULT false";
29
45
  const WEBHOOK_SECRET_ALTER = "ALTER TABLE webhooks ADD COLUMN IF NOT EXISTS secret_encrypted TEXT NOT NULL DEFAULT ''";
30
46
  const WEBHOOK_SECRET_DROP = "ALTER TABLE webhooks DROP COLUMN IF EXISTS secret";
31
47
  const TOKEN_USER_ALTER = "ALTER TABLE tokens ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES users(id) ON DELETE CASCADE";
32
48
  const MEMBER_SOURCE_ALTER = "ALTER TABLE project_members ADD COLUMN IF NOT EXISTS source TEXT NOT NULL DEFAULT 'manual'";
49
+ const COMMENT_STORY_ID_ALTER = "ALTER TABLE comments ADD COLUMN IF NOT EXISTS story_id TEXT";
50
+ const NOTIFICATION_LAST_ERROR_ALTER = "ALTER TABLE notification_channels ADD COLUMN IF NOT EXISTS last_error TEXT";
51
+ const NOTIFICATION_LAST_ERROR_AT_ALTER = "ALTER TABLE notification_channels ADD COLUMN IF NOT EXISTS last_error_at TIMESTAMPTZ";
33
52
  /**
34
53
  * Re-runs share `(project_id, git_sha)` by design (ULID build ids), so the
35
54
  * lookup index must not be unique. Existing databases created it UNIQUE —
@@ -37,33 +56,86 @@ const MEMBER_SOURCE_ALTER = "ALTER TABLE project_members ADD COLUMN IF NOT EXIST
37
56
  */
38
57
  const BUILDS_GITSHA_DEDUP = "DROP INDEX IF EXISTS builds_project_gitsha_idx";
39
58
  const BUILDS_GITSHA_INDEX = "CREATE INDEX IF NOT EXISTS builds_project_gitsha_idx ON builds (project_id, git_sha)";
59
+ const PROJECT_BROWSERS_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS browsers TEXT";
60
+ const PROJECT_MODES_ALLOWLIST_ALTER = "ALTER TABLE projects ADD COLUMN IF NOT EXISTS modes_allowlist TEXT";
61
+ const SNAPSHOT_MODE_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS mode TEXT";
62
+ const SNAPSHOT_BROWSER_ALTER = "ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS browser TEXT NOT NULL DEFAULT 'chromium'";
63
+ const BASELINE_MODE_ALTER = "ALTER TABLE baselines ADD COLUMN IF NOT EXISTS mode TEXT";
64
+ const BASELINE_BROWSER_ALTER = "ALTER TABLE baselines ADD COLUMN IF NOT EXISTS browser TEXT NOT NULL DEFAULT 'chromium'";
65
+ /** Swap the viewport-only unique indexes for the browser-aware ones (rows default to chromium). */
66
+ const IDENTITY_STATEMENTS = [
67
+ "DROP INDEX IF EXISTS snapshots_build_story_viewport_idx",
68
+ "DROP INDEX IF EXISTS baselines_project_story_viewport_branch_idx",
69
+ "CREATE UNIQUE INDEX IF NOT EXISTS snapshots_build_story_mode_browser_idx ON snapshots (build_id, story_id, viewport_name, browser)",
70
+ "CREATE UNIQUE INDEX IF NOT EXISTS baselines_project_story_mode_browser_branch_idx ON baselines (project_id, story_id, viewport_name, browser, branch)"
71
+ ];
40
72
  async function migrateSnapshotColumns(run) {
41
73
  await execIgnore(run, SNAPSHOT_INFRA_HASH_ALTER);
42
74
  await execIgnore(run, SNAPSHOT_INHERITED_ALTER);
43
75
  await execIgnore(run, SNAPSHOT_BASELINE_ID_ALTER);
44
76
  await execIgnore(run, SNAPSHOT_BASELINE_VERSION_ALTER);
77
+ await execIgnore(run, SNAPSHOT_DESIGN_URL_ALTER);
78
+ await execIgnore(run, SNAPSHOT_ENV_CHANGE_ALTER);
79
+ await execIgnore(run, SNAPSHOT_DURATION_ALTER);
80
+ await execIgnore(run, SNAPSHOT_A11Y_ALTER);
81
+ await migrateCaptureIdentityColumns(run);
82
+ }
83
+ async function migrateCaptureIdentityColumns(run) {
84
+ await execIgnore(run, SNAPSHOT_MODE_ALTER);
85
+ await execIgnore(run, SNAPSHOT_BROWSER_ALTER);
86
+ await execIgnore(run, BASELINE_MODE_ALTER);
87
+ await execIgnore(run, BASELINE_BROWSER_ALTER);
88
+ await execIgnore(run, PROJECT_BROWSERS_ALTER);
89
+ await execIgnore(run, PROJECT_MODES_ALLOWLIST_ALTER);
90
+ await execIgnore(run, DESIGN_LINKS_UNIQUE_INDEX);
91
+ await Promise.all(LEGACY_DESIGN_DROPS.map(async (statement) => {
92
+ await execIgnore(run, statement);
93
+ }));
94
+ }
95
+ async function migrateBaselineColumns(run) {
96
+ await execIgnore(run, BASELINE_INFRA_HASH_ALTER);
97
+ await execIgnore(run, BASELINE_FINGERPRINT_ALTER);
45
98
  }
46
99
  async function migrateProjectExtras(run) {
47
100
  await execIgnore(run, EXECUTE_PLAY_ALTER);
48
101
  await execIgnore(run, PLAY_TIMEOUT_MS_ALTER);
49
102
  await execIgnore(run, PROJECT_AUTOMIGRATE_ALTER);
103
+ await execIgnore(run, PROJECT_AI_PROFILE_ALTER);
104
+ await migrateProjectReviewColumns(run);
50
105
  await migrateSnapshotColumns(run);
51
- await execIgnore(run, BASELINE_INFRA_HASH_ALTER);
106
+ await migrateBaselineColumns(run);
107
+ await migrateBuildColumns(run);
108
+ await execIgnore(run, RUN_TESTS_ALTER);
109
+ }
110
+ async function migrateProjectReviewColumns(run) {
111
+ await execIgnore(run, PROJECT_REVIEW_ENABLED_ALTER);
112
+ await execIgnore(run, PROJECT_REVIEW_APPROVALS_ALTER);
113
+ await execIgnore(run, PROJECT_STORYBOOK_URL_TTL_ALTER);
114
+ }
115
+ async function migrateBuildColumns(run) {
52
116
  await execIgnore(run, BUILD_AFFECTED_ONLY_ALTER);
53
117
  await execIgnore(run, BUILD_BASELINE_SHA_ALTER);
54
118
  await execIgnore(run, BUILD_CHANGED_FILES_ALTER);
55
119
  await execIgnore(run, BUILD_AFFECTED_PATHS_ALTER);
120
+ await execIgnore(run, BUILD_INHERITED_COUNT_ALTER);
121
+ await execIgnore(run, BUILD_TEST_RESULTS_ALTER);
56
122
  }
57
123
  /** Run the full migration set through any row-query runner. */
58
124
  async function runMigrations(run) {
59
125
  await run(DDL);
60
126
  await migrateCoreColumns(run);
61
127
  await migrateProjectExtras(run);
128
+ await applyIdentityStatements(run);
62
129
  await migrateCommentsTable(run);
130
+ await migrateNotificationColumns(run);
131
+ }
132
+ async function migrateRunA11yDefault(run) {
133
+ await execIgnore(run, RUN_A11Y_ALTER);
134
+ await execIgnore(run, RUN_A11Y_DEFAULT_ALTER);
63
135
  }
64
136
  async function migrateCoreColumns(run) {
65
137
  await execIgnore(run, STORYBOOK_META_ALTER);
66
- await execIgnore(run, RUN_A11Y_ALTER);
138
+ await migrateRunA11yDefault(run);
67
139
  await execIgnore(run, PROJECT_BROWSER_ALTER);
68
140
  await execIgnore(run, PROJECT_VIEWPORTS_ALTER);
69
141
  await execIgnore(run, WEBHOOK_SECRET_ALTER);
@@ -73,12 +145,20 @@ async function migrateCoreColumns(run) {
73
145
  await execIgnore(run, BUILDS_GITSHA_DEDUP);
74
146
  await execIgnore(run, BUILDS_GITSHA_INDEX);
75
147
  }
148
+ async function applyIdentityStatements(run) {
149
+ for (const statement of IDENTITY_STATEMENTS) await execIgnore(run, statement);
150
+ }
76
151
  async function execIgnore(run, sql) {
77
152
  try {
78
153
  await run(sql);
79
154
  } catch {}
80
155
  }
156
+ async function migrateNotificationColumns(run) {
157
+ await execIgnore(run, NOTIFICATION_LAST_ERROR_ALTER);
158
+ await execIgnore(run, NOTIFICATION_LAST_ERROR_AT_ALTER);
159
+ }
81
160
  async function migrateCommentsTable(run) {
161
+ await execIgnore(run, COMMENT_STORY_ID_ALTER);
82
162
  try {
83
163
  const isNullable = (await run("SELECT is_nullable FROM information_schema.columns WHERE table_name='comments' AND column_name='user_id'"))[0]?.is_nullable;
84
164
  if (isNullable === "YES" || isNullable === void 0) return;
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.mjs","names":[],"sources":["../src/migrate.ts"],"sourcesContent":["/**\n * Shared Postgres migrations for every `db-postgres` preset.\n *\n * The DDL plus idempotent follow-up ALTERs run through a minimal row-query\n * runner so all drivers (`postgres.js`, `node-postgres`, Neon, …) share one\n * migration path instead of drifting per preset.\n */\nimport { DDL } from \"./ddl.ts\";\n\n/** Minimal row-query surface a migration runner needs. */\nexport type MigrationRunner = (sql: string) => Promise<unknown[]>;\n\nconst STORYBOOK_META_ALTER = \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS storybook_meta TEXT\";\nconst EXECUTE_PLAY_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS execute_play BOOLEAN NOT NULL DEFAULT false\";\nconst PLAY_TIMEOUT_MS_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS play_timeout_ms INTEGER NOT NULL DEFAULT 10000\";\nconst RUN_A11Y_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS run_a11y BOOLEAN NOT NULL DEFAULT false\";\nconst PROJECT_BROWSER_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS browser TEXT NOT NULL DEFAULT 'chromium'\";\nconst PROJECT_VIEWPORTS_ALTER = \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS viewports TEXT\";\nconst PROJECT_AUTOMIGRATE_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS automigrate BOOLEAN NOT NULL DEFAULT false\";\nconst SNAPSHOT_INFRA_HASH_ALTER = \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS infra_hash TEXT\";\nconst SNAPSHOT_INHERITED_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS inherited BOOLEAN NOT NULL DEFAULT false\";\nconst SNAPSHOT_BASELINE_ID_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS baseline_id TEXT\";\nconst SNAPSHOT_BASELINE_VERSION_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS baseline_version TEXT\";\nconst BASELINE_INFRA_HASH_ALTER = \"ALTER TABLE baselines ADD COLUMN IF NOT EXISTS infra_hash TEXT\";\nconst BUILD_AFFECTED_ONLY_ALTER =\n \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS affected_only BOOLEAN NOT NULL DEFAULT true\";\nconst BUILD_BASELINE_SHA_ALTER = \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS baseline_sha TEXT\";\nconst BUILD_CHANGED_FILES_ALTER = \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS changed_files TEXT\";\nconst BUILD_AFFECTED_PATHS_ALTER =\n \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS affected_import_paths TEXT\";\nconst WEBHOOK_SECRET_ALTER =\n \"ALTER TABLE webhooks ADD COLUMN IF NOT EXISTS secret_encrypted TEXT NOT NULL DEFAULT ''\";\nconst WEBHOOK_SECRET_DROP = \"ALTER TABLE webhooks DROP COLUMN IF EXISTS secret\";\nconst TOKEN_USER_ALTER =\n \"ALTER TABLE tokens ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES users(id) ON DELETE CASCADE\";\nconst MEMBER_SOURCE_ALTER =\n \"ALTER TABLE project_members ADD COLUMN IF NOT EXISTS source TEXT NOT NULL DEFAULT 'manual'\";\n/**\n * Re-runs share `(project_id, git_sha)` by design (ULID build ids), so the\n * lookup index must not be unique. Existing databases created it UNIQUE —\n * drop and recreate it plain.\n */\nconst BUILDS_GITSHA_DEDUP = \"DROP INDEX IF EXISTS builds_project_gitsha_idx\";\nconst BUILDS_GITSHA_INDEX =\n \"CREATE INDEX IF NOT EXISTS builds_project_gitsha_idx ON builds (project_id, git_sha)\";\n\nasync function migrateSnapshotColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, SNAPSHOT_INFRA_HASH_ALTER);\n await execIgnore(run, SNAPSHOT_INHERITED_ALTER);\n await execIgnore(run, SNAPSHOT_BASELINE_ID_ALTER);\n await execIgnore(run, SNAPSHOT_BASELINE_VERSION_ALTER);\n}\n\nasync function migrateProjectExtras(run: MigrationRunner): Promise<void> {\n await execIgnore(run, EXECUTE_PLAY_ALTER);\n await execIgnore(run, PLAY_TIMEOUT_MS_ALTER);\n await execIgnore(run, PROJECT_AUTOMIGRATE_ALTER);\n await migrateSnapshotColumns(run);\n await execIgnore(run, BASELINE_INFRA_HASH_ALTER);\n await execIgnore(run, BUILD_AFFECTED_ONLY_ALTER);\n await execIgnore(run, BUILD_BASELINE_SHA_ALTER);\n await execIgnore(run, BUILD_CHANGED_FILES_ALTER);\n await execIgnore(run, BUILD_AFFECTED_PATHS_ALTER);\n}\n\n/** Run the full migration set through any row-query runner. */\nexport async function runMigrations(run: MigrationRunner): Promise<void> {\n await run(DDL);\n await migrateCoreColumns(run);\n await migrateProjectExtras(run);\n await migrateCommentsTable(run);\n}\n\nasync function migrateCoreColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, STORYBOOK_META_ALTER);\n await execIgnore(run, RUN_A11Y_ALTER);\n await execIgnore(run, PROJECT_BROWSER_ALTER);\n await execIgnore(run, PROJECT_VIEWPORTS_ALTER);\n await execIgnore(run, WEBHOOK_SECRET_ALTER);\n await execIgnore(run, WEBHOOK_SECRET_DROP);\n await execIgnore(run, TOKEN_USER_ALTER);\n await execIgnore(run, MEMBER_SOURCE_ALTER);\n await execIgnore(run, BUILDS_GITSHA_DEDUP);\n await execIgnore(run, BUILDS_GITSHA_INDEX);\n}\n\nasync function execIgnore(run: MigrationRunner, sql: string): Promise<void> {\n try {\n await run(sql);\n } catch {\n // idempotent — already migrated\n }\n}\n\nasync function migrateCommentsTable(run: MigrationRunner): Promise<void> {\n try {\n const rows = (await run(\n \"SELECT is_nullable FROM information_schema.columns WHERE table_name='comments' AND column_name='user_id'\",\n )) as { is_nullable: string }[];\n const isNullable = rows[0]?.is_nullable;\n if (isNullable === \"YES\" || isNullable === undefined) {\n return;\n }\n await run(\"ALTER TABLE comments ALTER COLUMN user_id DROP NOT NULL\");\n } catch {\n // already nullable or table missing — ignore\n }\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,uBAAuB;AAC7B,MAAM,qBACJ;AACF,MAAM,wBACJ;AACF,MAAM,iBACJ;AACF,MAAM,wBACJ;AACF,MAAM,0BAA0B;AAChC,MAAM,4BACJ;AACF,MAAM,4BAA4B;AAClC,MAAM,2BACJ;AACF,MAAM,6BACJ;AACF,MAAM,kCACJ;AACF,MAAM,4BAA4B;AAClC,MAAM,4BACJ;AACF,MAAM,2BAA2B;AACjC,MAAM,4BAA4B;AAClC,MAAM,6BACJ;AACF,MAAM,uBACJ;AACF,MAAM,sBAAsB;AAC5B,MAAM,mBACJ;AACF,MAAM,sBACJ;;;;;;AAMF,MAAM,sBAAsB;AAC5B,MAAM,sBACJ;AAEF,eAAe,uBAAuB,KAAqC;CACzE,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,wBAAwB;CAC9C,MAAM,WAAW,KAAK,0BAA0B;CAChD,MAAM,WAAW,KAAK,+BAA+B;AACvD;AAEA,eAAe,qBAAqB,KAAqC;CACvE,MAAM,WAAW,KAAK,kBAAkB;CACxC,MAAM,WAAW,KAAK,qBAAqB;CAC3C,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,uBAAuB,GAAG;CAChC,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,wBAAwB;CAC9C,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,0BAA0B;AAClD;;AAGA,eAAsB,cAAc,KAAqC;CACvE,MAAM,IAAI,GAAG;CACb,MAAM,mBAAmB,GAAG;CAC5B,MAAM,qBAAqB,GAAG;CAC9B,MAAM,qBAAqB,GAAG;AAChC;AAEA,eAAe,mBAAmB,KAAqC;CACrE,MAAM,WAAW,KAAK,oBAAoB;CAC1C,MAAM,WAAW,KAAK,cAAc;CACpC,MAAM,WAAW,KAAK,qBAAqB;CAC3C,MAAM,WAAW,KAAK,uBAAuB;CAC7C,MAAM,WAAW,KAAK,oBAAoB;CAC1C,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,gBAAgB;CACtC,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,mBAAmB;AAC3C;AAEA,eAAe,WAAW,KAAsB,KAA4B;CAC1E,IAAI;EACF,MAAM,IAAI,GAAG;CACf,QAAQ,CAER;AACF;AAEA,eAAe,qBAAqB,KAAqC;CACvE,IAAI;EAIF,MAAM,cAAa,MAHC,IAClB,0GACF,EAAA,CACwB,EAAE,EAAE;EAC5B,IAAI,eAAe,SAAS,eAAe,KAAA,GACzC;EAEF,MAAM,IAAI,yDAAyD;CACrE,QAAQ,CAER;AACF"}
1
+ {"version":3,"file":"migrate.mjs","names":[],"sources":["../src/migrate.ts"],"sourcesContent":["/**\n * Shared Postgres migrations for every `db-postgres` preset.\n *\n * The DDL plus idempotent follow-up ALTERs run through a minimal row-query\n * runner so all drivers (`postgres.js`, `node-postgres`, Neon, …) share one\n * migration path instead of drifting per preset.\n */\nimport { DDL } from \"./ddl.ts\";\n\n/** Minimal row-query surface a migration runner needs. */\nexport type MigrationRunner = (sql: string) => Promise<unknown[]>;\n\nconst STORYBOOK_META_ALTER = \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS storybook_meta TEXT\";\nconst EXECUTE_PLAY_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS execute_play BOOLEAN NOT NULL DEFAULT false\";\nconst PLAY_TIMEOUT_MS_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS play_timeout_ms INTEGER NOT NULL DEFAULT 10000\";\nconst RUN_A11Y_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS run_a11y BOOLEAN NOT NULL DEFAULT true\";\nconst RUN_A11Y_DEFAULT_ALTER = \"ALTER TABLE projects ALTER COLUMN run_a11y SET DEFAULT true\";\nconst PROJECT_BROWSER_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS browser TEXT NOT NULL DEFAULT 'chromium'\";\nconst PROJECT_VIEWPORTS_ALTER = \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS viewports TEXT\";\nconst PROJECT_AUTOMIGRATE_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS automigrate BOOLEAN NOT NULL DEFAULT false\";\nconst PROJECT_AI_PROFILE_ALTER = \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS ai_profile TEXT\";\nconst PROJECT_REVIEW_ENABLED_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS review_enabled BOOLEAN NOT NULL DEFAULT true\";\nconst PROJECT_REVIEW_APPROVALS_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS review_approvals INTEGER NOT NULL DEFAULT 1\";\nconst PROJECT_STORYBOOK_URL_TTL_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS storybook_url_ttl_seconds INTEGER\";\nconst SNAPSHOT_INFRA_HASH_ALTER = \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS infra_hash TEXT\";\nconst SNAPSHOT_INHERITED_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS inherited BOOLEAN NOT NULL DEFAULT false\";\nconst SNAPSHOT_BASELINE_ID_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS baseline_id TEXT\";\nconst SNAPSHOT_BASELINE_VERSION_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS baseline_version TEXT\";\nconst SNAPSHOT_ENV_CHANGE_ALTER = \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS env_change TEXT\";\nconst SNAPSHOT_DESIGN_URL_ALTER = \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS design_url TEXT\";\nconst SNAPSHOT_DURATION_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS duration_ms INTEGER\";\nconst SNAPSHOT_A11Y_ALTER = \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS a11y_violations TEXT\";\nconst DESIGN_LINKS_UNIQUE_INDEX =\n \"CREATE UNIQUE INDEX IF NOT EXISTS design_links_project_import_path_idx ON design_links (project_id, import_path)\";\n/** Pre-adapter Figma tables (replaced by design_nodes / design_credentials; no data is carried over). */\nconst LEGACY_DESIGN_DROPS = [\n \"DROP TABLE IF EXISTS figma_nodes\",\n \"DROP TABLE IF EXISTS design_tokens\",\n];\nconst BASELINE_FINGERPRINT_ALTER =\n \"ALTER TABLE baselines ADD COLUMN IF NOT EXISTS fingerprint TEXT\";\nconst BASELINE_INFRA_HASH_ALTER = \"ALTER TABLE baselines ADD COLUMN IF NOT EXISTS infra_hash TEXT\";\nconst BUILD_AFFECTED_ONLY_ALTER =\n \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS affected_only BOOLEAN NOT NULL DEFAULT true\";\nconst BUILD_BASELINE_SHA_ALTER = \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS baseline_sha TEXT\";\nconst BUILD_CHANGED_FILES_ALTER = \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS changed_files TEXT\";\nconst BUILD_AFFECTED_PATHS_ALTER =\n \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS affected_import_paths TEXT\";\nconst BUILD_INHERITED_COUNT_ALTER =\n \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS inherited_count INTEGER NOT NULL DEFAULT 0\";\nconst BUILD_TEST_RESULTS_ALTER = \"ALTER TABLE builds ADD COLUMN IF NOT EXISTS test_results TEXT\";\nconst RUN_TESTS_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS run_tests BOOLEAN NOT NULL DEFAULT false\";\nconst WEBHOOK_SECRET_ALTER =\n \"ALTER TABLE webhooks ADD COLUMN IF NOT EXISTS secret_encrypted TEXT NOT NULL DEFAULT ''\";\nconst WEBHOOK_SECRET_DROP = \"ALTER TABLE webhooks DROP COLUMN IF EXISTS secret\";\nconst TOKEN_USER_ALTER =\n \"ALTER TABLE tokens ADD COLUMN IF NOT EXISTS user_id TEXT REFERENCES users(id) ON DELETE CASCADE\";\nconst MEMBER_SOURCE_ALTER =\n \"ALTER TABLE project_members ADD COLUMN IF NOT EXISTS source TEXT NOT NULL DEFAULT 'manual'\";\nconst COMMENT_STORY_ID_ALTER = \"ALTER TABLE comments ADD COLUMN IF NOT EXISTS story_id TEXT\";\nconst NOTIFICATION_LAST_ERROR_ALTER =\n \"ALTER TABLE notification_channels ADD COLUMN IF NOT EXISTS last_error TEXT\";\nconst NOTIFICATION_LAST_ERROR_AT_ALTER =\n \"ALTER TABLE notification_channels ADD COLUMN IF NOT EXISTS last_error_at TIMESTAMPTZ\";\n/**\n * Re-runs share `(project_id, git_sha)` by design (ULID build ids), so the\n * lookup index must not be unique. Existing databases created it UNIQUE —\n * drop and recreate it plain.\n */\nconst BUILDS_GITSHA_DEDUP = \"DROP INDEX IF EXISTS builds_project_gitsha_idx\";\nconst BUILDS_GITSHA_INDEX =\n \"CREATE INDEX IF NOT EXISTS builds_project_gitsha_idx ON builds (project_id, git_sha)\";\n\nconst PROJECT_BROWSERS_ALTER = \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS browsers TEXT\";\nconst PROJECT_MODES_ALLOWLIST_ALTER =\n \"ALTER TABLE projects ADD COLUMN IF NOT EXISTS modes_allowlist TEXT\";\nconst SNAPSHOT_MODE_ALTER = \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS mode TEXT\";\nconst SNAPSHOT_BROWSER_ALTER =\n \"ALTER TABLE snapshots ADD COLUMN IF NOT EXISTS browser TEXT NOT NULL DEFAULT 'chromium'\";\nconst BASELINE_MODE_ALTER = \"ALTER TABLE baselines ADD COLUMN IF NOT EXISTS mode TEXT\";\nconst BASELINE_BROWSER_ALTER =\n \"ALTER TABLE baselines ADD COLUMN IF NOT EXISTS browser TEXT NOT NULL DEFAULT 'chromium'\";\n/** Swap the viewport-only unique indexes for the browser-aware ones (rows default to chromium). */\nconst IDENTITY_STATEMENTS = [\n \"DROP INDEX IF EXISTS snapshots_build_story_viewport_idx\",\n \"DROP INDEX IF EXISTS baselines_project_story_viewport_branch_idx\",\n \"CREATE UNIQUE INDEX IF NOT EXISTS snapshots_build_story_mode_browser_idx ON snapshots (build_id, story_id, viewport_name, browser)\",\n \"CREATE UNIQUE INDEX IF NOT EXISTS baselines_project_story_mode_browser_branch_idx ON baselines (project_id, story_id, viewport_name, browser, branch)\",\n];\n\nasync function migrateSnapshotColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, SNAPSHOT_INFRA_HASH_ALTER);\n await execIgnore(run, SNAPSHOT_INHERITED_ALTER);\n await execIgnore(run, SNAPSHOT_BASELINE_ID_ALTER);\n await execIgnore(run, SNAPSHOT_BASELINE_VERSION_ALTER);\n await execIgnore(run, SNAPSHOT_DESIGN_URL_ALTER);\n await execIgnore(run, SNAPSHOT_ENV_CHANGE_ALTER);\n await execIgnore(run, SNAPSHOT_DURATION_ALTER);\n await execIgnore(run, SNAPSHOT_A11Y_ALTER);\n await migrateCaptureIdentityColumns(run);\n}\n\nasync function migrateCaptureIdentityColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, SNAPSHOT_MODE_ALTER);\n await execIgnore(run, SNAPSHOT_BROWSER_ALTER);\n await execIgnore(run, BASELINE_MODE_ALTER);\n await execIgnore(run, BASELINE_BROWSER_ALTER);\n await execIgnore(run, PROJECT_BROWSERS_ALTER);\n await execIgnore(run, PROJECT_MODES_ALLOWLIST_ALTER);\n await execIgnore(run, DESIGN_LINKS_UNIQUE_INDEX);\n await Promise.all(\n LEGACY_DESIGN_DROPS.map(async (statement) => {\n await execIgnore(run, statement);\n }),\n );\n}\n\nasync function migrateBaselineColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, BASELINE_INFRA_HASH_ALTER);\n await execIgnore(run, BASELINE_FINGERPRINT_ALTER);\n}\n\nasync function migrateProjectExtras(run: MigrationRunner): Promise<void> {\n await execIgnore(run, EXECUTE_PLAY_ALTER);\n await execIgnore(run, PLAY_TIMEOUT_MS_ALTER);\n await execIgnore(run, PROJECT_AUTOMIGRATE_ALTER);\n await execIgnore(run, PROJECT_AI_PROFILE_ALTER);\n await migrateProjectReviewColumns(run);\n await migrateSnapshotColumns(run);\n await migrateBaselineColumns(run);\n await migrateBuildColumns(run);\n await execIgnore(run, RUN_TESTS_ALTER);\n}\n\nasync function migrateProjectReviewColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, PROJECT_REVIEW_ENABLED_ALTER);\n await execIgnore(run, PROJECT_REVIEW_APPROVALS_ALTER);\n await execIgnore(run, PROJECT_STORYBOOK_URL_TTL_ALTER);\n}\n\nasync function migrateBuildColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, BUILD_AFFECTED_ONLY_ALTER);\n await execIgnore(run, BUILD_BASELINE_SHA_ALTER);\n await execIgnore(run, BUILD_CHANGED_FILES_ALTER);\n await execIgnore(run, BUILD_AFFECTED_PATHS_ALTER);\n await execIgnore(run, BUILD_INHERITED_COUNT_ALTER);\n await execIgnore(run, BUILD_TEST_RESULTS_ALTER);\n}\n\n/** Run the full migration set through any row-query runner. */\nexport async function runMigrations(run: MigrationRunner): Promise<void> {\n await run(DDL);\n await migrateCoreColumns(run);\n await migrateProjectExtras(run);\n await applyIdentityStatements(run);\n await migrateCommentsTable(run);\n await migrateNotificationColumns(run);\n}\n\nasync function migrateRunA11yDefault(run: MigrationRunner): Promise<void> {\n await execIgnore(run, RUN_A11Y_ALTER);\n await execIgnore(run, RUN_A11Y_DEFAULT_ALTER);\n}\n\nasync function migrateCoreColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, STORYBOOK_META_ALTER);\n await migrateRunA11yDefault(run);\n await execIgnore(run, PROJECT_BROWSER_ALTER);\n await execIgnore(run, PROJECT_VIEWPORTS_ALTER);\n await execIgnore(run, WEBHOOK_SECRET_ALTER);\n await execIgnore(run, WEBHOOK_SECRET_DROP);\n await execIgnore(run, TOKEN_USER_ALTER);\n await execIgnore(run, MEMBER_SOURCE_ALTER);\n await execIgnore(run, BUILDS_GITSHA_DEDUP);\n await execIgnore(run, BUILDS_GITSHA_INDEX);\n}\n\nasync function applyIdentityStatements(run: MigrationRunner): Promise<void> {\n for (const statement of IDENTITY_STATEMENTS) {\n // oxlint-disable-next-line no-await-in-loop -- ordered: drop old indexes, then create new\n await execIgnore(run, statement);\n }\n}\n\nasync function execIgnore(run: MigrationRunner, sql: string): Promise<void> {\n try {\n await run(sql);\n } catch {\n // idempotent — already migrated\n }\n}\n\nasync function migrateNotificationColumns(run: MigrationRunner): Promise<void> {\n await execIgnore(run, NOTIFICATION_LAST_ERROR_ALTER);\n await execIgnore(run, NOTIFICATION_LAST_ERROR_AT_ALTER);\n}\n\nasync function migrateCommentsTable(run: MigrationRunner): Promise<void> {\n await execIgnore(run, COMMENT_STORY_ID_ALTER);\n try {\n const rows = (await run(\n \"SELECT is_nullable FROM information_schema.columns WHERE table_name='comments' AND column_name='user_id'\",\n )) as { is_nullable: string }[];\n const isNullable = rows[0]?.is_nullable;\n if (isNullable === \"YES\" || isNullable === undefined) {\n return;\n }\n await run(\"ALTER TABLE comments ALTER COLUMN user_id DROP NOT NULL\");\n } catch {\n // already nullable or table missing — ignore\n }\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,uBAAuB;AAC7B,MAAM,qBACJ;AACF,MAAM,wBACJ;AACF,MAAM,iBACJ;AACF,MAAM,yBAAyB;AAC/B,MAAM,wBACJ;AACF,MAAM,0BAA0B;AAChC,MAAM,4BACJ;AACF,MAAM,2BAA2B;AACjC,MAAM,+BACJ;AACF,MAAM,iCACJ;AACF,MAAM,kCACJ;AACF,MAAM,4BAA4B;AAClC,MAAM,2BACJ;AACF,MAAM,6BACJ;AACF,MAAM,kCACJ;AACF,MAAM,4BAA4B;AAClC,MAAM,4BAA4B;AAClC,MAAM,0BACJ;AACF,MAAM,sBAAsB;AAC5B,MAAM,4BACJ;;AAEF,MAAM,sBAAsB,CAC1B,oCACA,oCACF;AACA,MAAM,6BACJ;AACF,MAAM,4BAA4B;AAClC,MAAM,4BACJ;AACF,MAAM,2BAA2B;AACjC,MAAM,4BAA4B;AAClC,MAAM,6BACJ;AACF,MAAM,8BACJ;AACF,MAAM,2BAA2B;AACjC,MAAM,kBACJ;AACF,MAAM,uBACJ;AACF,MAAM,sBAAsB;AAC5B,MAAM,mBACJ;AACF,MAAM,sBACJ;AACF,MAAM,yBAAyB;AAC/B,MAAM,gCACJ;AACF,MAAM,mCACJ;;;;;;AAMF,MAAM,sBAAsB;AAC5B,MAAM,sBACJ;AAEF,MAAM,yBAAyB;AAC/B,MAAM,gCACJ;AACF,MAAM,sBAAsB;AAC5B,MAAM,yBACJ;AACF,MAAM,sBAAsB;AAC5B,MAAM,yBACJ;;AAEF,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;AACF;AAEA,eAAe,uBAAuB,KAAqC;CACzE,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,wBAAwB;CAC9C,MAAM,WAAW,KAAK,0BAA0B;CAChD,MAAM,WAAW,KAAK,+BAA+B;CACrD,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,uBAAuB;CAC7C,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,8BAA8B,GAAG;AACzC;AAEA,eAAe,8BAA8B,KAAqC;CAChF,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,sBAAsB;CAC5C,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,sBAAsB;CAC5C,MAAM,WAAW,KAAK,sBAAsB;CAC5C,MAAM,WAAW,KAAK,6BAA6B;CACnD,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,QAAQ,IACZ,oBAAoB,IAAI,OAAO,cAAc;EAC3C,MAAM,WAAW,KAAK,SAAS;CACjC,CAAC,CACH;AACF;AAEA,eAAe,uBAAuB,KAAqC;CACzE,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,0BAA0B;AAClD;AAEA,eAAe,qBAAqB,KAAqC;CACvE,MAAM,WAAW,KAAK,kBAAkB;CACxC,MAAM,WAAW,KAAK,qBAAqB;CAC3C,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,wBAAwB;CAC9C,MAAM,4BAA4B,GAAG;CACrC,MAAM,uBAAuB,GAAG;CAChC,MAAM,uBAAuB,GAAG;CAChC,MAAM,oBAAoB,GAAG;CAC7B,MAAM,WAAW,KAAK,eAAe;AACvC;AAEA,eAAe,4BAA4B,KAAqC;CAC9E,MAAM,WAAW,KAAK,4BAA4B;CAClD,MAAM,WAAW,KAAK,8BAA8B;CACpD,MAAM,WAAW,KAAK,+BAA+B;AACvD;AAEA,eAAe,oBAAoB,KAAqC;CACtE,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,wBAAwB;CAC9C,MAAM,WAAW,KAAK,yBAAyB;CAC/C,MAAM,WAAW,KAAK,0BAA0B;CAChD,MAAM,WAAW,KAAK,2BAA2B;CACjD,MAAM,WAAW,KAAK,wBAAwB;AAChD;;AAGA,eAAsB,cAAc,KAAqC;CACvE,MAAM,IAAI,GAAG;CACb,MAAM,mBAAmB,GAAG;CAC5B,MAAM,qBAAqB,GAAG;CAC9B,MAAM,wBAAwB,GAAG;CACjC,MAAM,qBAAqB,GAAG;CAC9B,MAAM,2BAA2B,GAAG;AACtC;AAEA,eAAe,sBAAsB,KAAqC;CACxE,MAAM,WAAW,KAAK,cAAc;CACpC,MAAM,WAAW,KAAK,sBAAsB;AAC9C;AAEA,eAAe,mBAAmB,KAAqC;CACrE,MAAM,WAAW,KAAK,oBAAoB;CAC1C,MAAM,sBAAsB,GAAG;CAC/B,MAAM,WAAW,KAAK,qBAAqB;CAC3C,MAAM,WAAW,KAAK,uBAAuB;CAC7C,MAAM,WAAW,KAAK,oBAAoB;CAC1C,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,gBAAgB;CACtC,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,mBAAmB;CACzC,MAAM,WAAW,KAAK,mBAAmB;AAC3C;AAEA,eAAe,wBAAwB,KAAqC;CAC1E,KAAK,MAAM,aAAa,qBAEtB,MAAM,WAAW,KAAK,SAAS;AAEnC;AAEA,eAAe,WAAW,KAAsB,KAA4B;CAC1E,IAAI;EACF,MAAM,IAAI,GAAG;CACf,QAAQ,CAER;AACF;AAEA,eAAe,2BAA2B,KAAqC;CAC7E,MAAM,WAAW,KAAK,6BAA6B;CACnD,MAAM,WAAW,KAAK,gCAAgC;AACxD;AAEA,eAAe,qBAAqB,KAAqC;CACvE,MAAM,WAAW,KAAK,sBAAsB;CAC5C,IAAI;EAIF,MAAM,cAAa,MAHC,IAClB,0GACF,EAAA,CACwB,EAAE,EAAE;EAC5B,IAAI,eAAe,SAAS,eAAe,KAAA,GACzC;EAEF,MAAM,IAAI,yDAAyD;CACrE,QAAQ,CAER;AACF"}
@@ -32,7 +32,7 @@ function createNeonHttpDatabase(options) {
32
32
  return createDrizzlePgAdapter(db, {
33
33
  metadata: {
34
34
  name: "Neon HTTP",
35
- version: globalThis.__PKG_VERSION__ ?? "0.0.0",
35
+ version: "0.7.0",
36
36
  description: "Neon Postgres database adapter (HTTP driver + Drizzle)",
37
37
  kind: "neon-http",
38
38
  category: "database"
@@ -1 +1 @@
1
- {"version":3,"file":"neon-http.mjs","names":[],"sources":["../src/neon-http.ts"],"sourcesContent":["/**\n * Neon HTTP preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default, but\n * over Neon's fetch-based HTTP driver — no sockets, so it runs in hard\n * serverless and edge runtimes (Cloudflare Workers, Vercel Edge) where\n * WebSockets are unavailable. Requires the optional\n * `@neondatabase/serverless` peer (`nub add @neondatabase/serverless`).\n *\n * Note: HTTP has no interactive transactions; drizzle emulates `transact`\n * sequentially per call. Concurrent writers should prefer `./neon`.\n */\nimport { neon, type NeonQueryFunction } from \"@neondatabase/serverless\";\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/neon-http\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a Neon-HTTP-backed DatabaseAdapter.\n *\n * When `client` (a `neon()` query function) is supplied, `url` is ignored\n * and the caller owns the lifecycle of the client (teardown is a no-op).\n */\nexport interface NeonHttpDatabaseOptions {\n url?: string;\n connectionString?: string;\n client?: NeonQueryFunction<false, false>;\n}\n\n/**\n * Create a Neon-HTTP-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a connection `url` or a preconfigured `neon()`\n * query function.\n * @returns A DatabaseAdapter backed by the Neon database.\n */\nexport function createNeonHttpDatabase(options: NeonHttpDatabaseOptions): DatabaseAdapter {\n const { sql } = resolveClient(options);\n const db = drizzle(sql, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Neon HTTP\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"Neon Postgres database adapter (HTTP driver + Drizzle)\",\n kind: \"neon-http\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n await runMigrations(async (statement) => await sql.query(statement));\n },\n close: () => {\n // no-op: fetch-based queries hold no connections (owned or not)\n },\n ping: async () => {\n await sql.query(\"SELECT 1\");\n },\n });\n}\n\n/** Resolve the query function, distinguishing caller-owned from owned. */\nfunction resolveClient(options: NeonHttpDatabaseOptions): {\n sql: NeonQueryFunction<false, false>;\n owned: boolean;\n} {\n if (options.client) {\n return { sql: options.client, owned: false };\n }\n const connectionString = options.connectionString ?? options.url;\n if (!connectionString) {\n throw new Error(\n \"createNeonHttpDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n return { sql: neon(connectionString), owned: true };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,SAAgB,uBAAuB,SAAmD;CACxF,MAAM,EAAE,QAAQ,cAAc,OAAO;CACrC,MAAM,KAAK,QAAQ,KAAK,EAAE,OAAO,CAAC;CAElC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAU,WAAuD,mBAAmB;GACpF,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GACnB,MAAM,cAAc,OAAO,cAAc,MAAM,IAAI,MAAM,SAAS,CAAC;EACrE;EACA,aAAa,CAEb;EACA,MAAM,YAAY;GAChB,MAAM,IAAI,MAAM,UAAU;EAC5B;CACF,CAAC;AACH;;AAGA,SAAS,cAAc,SAGrB;CACA,IAAI,QAAQ,QACV,OAAO;EAAE,KAAK,QAAQ;EAAQ,OAAO;CAAM;CAE7C,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,kBACH,MAAM,IAAI,MACR,2FACF;CAEF,OAAO;EAAE,KAAK,KAAK,gBAAgB;EAAG,OAAO;CAAK;AACpD"}
1
+ {"version":3,"file":"neon-http.mjs","names":[],"sources":["../src/neon-http.ts"],"sourcesContent":["/**\n * Neon HTTP preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default, but\n * over Neon's fetch-based HTTP driver — no sockets, so it runs in hard\n * serverless and edge runtimes (Cloudflare Workers, Vercel Edge) where\n * WebSockets are unavailable. Requires the optional\n * `@neondatabase/serverless` peer (`nub add @neondatabase/serverless`).\n *\n * Note: HTTP has no interactive transactions; drizzle emulates `transact`\n * sequentially per call. Concurrent writers should prefer `./neon`.\n */\nimport { neon, type NeonQueryFunction } from \"@neondatabase/serverless\";\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/neon-http\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a Neon-HTTP-backed DatabaseAdapter.\n *\n * When `client` (a `neon()` query function) is supplied, `url` is ignored\n * and the caller owns the lifecycle of the client (teardown is a no-op).\n */\nexport interface NeonHttpDatabaseOptions {\n url?: string;\n connectionString?: string;\n client?: NeonQueryFunction<false, false>;\n}\n\n/**\n * Create a Neon-HTTP-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a connection `url` or a preconfigured `neon()`\n * query function.\n * @returns A DatabaseAdapter backed by the Neon database.\n */\nexport function createNeonHttpDatabase(options: NeonHttpDatabaseOptions): DatabaseAdapter {\n const { sql } = resolveClient(options);\n const db = drizzle(sql, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Neon HTTP\",\n version: typeof __PKG_VERSION__ === \"string\" ? __PKG_VERSION__ : \"0.0.0\",\n description: \"Neon Postgres database adapter (HTTP driver + Drizzle)\",\n kind: \"neon-http\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n await runMigrations(async (statement) => await sql.query(statement));\n },\n close: () => {\n // no-op: fetch-based queries hold no connections (owned or not)\n },\n ping: async () => {\n await sql.query(\"SELECT 1\");\n },\n });\n}\n\n/** Resolve the query function, distinguishing caller-owned from owned. */\nfunction resolveClient(options: NeonHttpDatabaseOptions): {\n sql: NeonQueryFunction<false, false>;\n owned: boolean;\n} {\n if (options.client) {\n return { sql: options.client, owned: false };\n }\n const connectionString = options.connectionString ?? options.url;\n if (!connectionString) {\n throw new Error(\n \"createNeonHttpDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n return { sql: neon(connectionString), owned: true };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,SAAgB,uBAAuB,SAAmD;CACxF,MAAM,EAAE,QAAQ,cAAc,OAAO;CACrC,MAAM,KAAK,QAAQ,KAAK,EAAE,OAAO,CAAC;CAElC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAA;GACA,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GACnB,MAAM,cAAc,OAAO,cAAc,MAAM,IAAI,MAAM,SAAS,CAAC;EACrE;EACA,aAAa,CAEb;EACA,MAAM,YAAY;GAChB,MAAM,IAAI,MAAM,UAAU;EAC5B;CACF,CAAC;AACH;;AAGA,SAAS,cAAc,SAGrB;CACA,IAAI,QAAQ,QACV,OAAO;EAAE,KAAK,QAAQ;EAAQ,OAAO;CAAM;CAE7C,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,kBACH,MAAM,IAAI,MACR,2FACF;CAEF,OAAO;EAAE,KAAK,KAAK,gBAAgB;EAAG,OAAO;CAAK;AACpD"}
package/dist/neon.mjs CHANGED
@@ -31,7 +31,7 @@ function createNeonDatabase(options) {
31
31
  return createDrizzlePgAdapter(db, {
32
32
  metadata: {
33
33
  name: "Neon",
34
- version: globalThis.__PKG_VERSION__ ?? "0.0.0",
34
+ version: "0.7.0",
35
35
  description: "Neon Postgres database adapter (serverless driver + Drizzle)",
36
36
  kind: "neon",
37
37
  category: "database"
package/dist/neon.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"neon.mjs","names":[],"sources":["../src/neon.ts"],"sourcesContent":["/**\n * Neon (WebSocket pool) preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default; only\n * the driver differs (`@neondatabase/serverless` pooled connections work on\n * Node and edge runtimes with a WebSocket constructor). Requires the\n * optional `@neondatabase/serverless` peer (`nub add @neondatabase/serverless`).\n */\nimport { Pool, type PoolClient } from \"@neondatabase/serverless\";\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/neon-serverless\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a Neon-backed DatabaseAdapter.\n *\n * When `client` (a `Pool` or `PoolClient`) is supplied, all other\n * connection options are ignored and the caller owns the lifecycle of the\n * client (teardown is a no-op). This is the hook for custom WebSocket\n * constructors and hermetic tests.\n */\nexport interface NeonDatabaseOptions {\n url?: string;\n connectionString?: string;\n client?: Pool | PoolClient;\n}\n\n/**\n * Create a Neon-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a connection `url` or a preconfigured Neon\n * `client`.\n * @returns A DatabaseAdapter backed by the Neon database.\n */\nexport function createNeonDatabase(options: NeonDatabaseOptions): DatabaseAdapter {\n const connectionString = options.connectionString ?? options.url;\n if (!options.client && !connectionString) {\n throw new Error(\n \"createNeonDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n\n const owned = !options.client;\n const pool = options.client ?? new Pool({ connectionString });\n const db = drizzle(pool, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Neon\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"Neon Postgres database adapter (serverless driver + Drizzle)\",\n kind: \"neon\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n await runMigrations(async (sql) => (await pool.query(sql)).rows as unknown[]);\n },\n close: async () => {\n if (owned) {\n await endClient(pool);\n }\n },\n ping: async () => {\n await pool.query(\"SELECT 1\");\n },\n });\n}\n\n/** Close an owned client: pools end, checked-out clients release. */\nasync function endClient(pool: Pool | PoolClient): Promise<void> {\n if (\"end\" in pool && typeof pool.end === \"function\") {\n await pool.end();\n } else if (\"release\" in pool && typeof pool.release === \"function\") {\n pool.release();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,mBAAmB,SAA+C;CAChF,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,QAAQ,UAAU,CAAC,kBACtB,MAAM,IAAI,MACR,uFACF;CAGF,MAAM,QAAQ,CAAC,QAAQ;CACvB,MAAM,OAAO,QAAQ,UAAU,IAAI,KAAK,EAAE,iBAAiB,CAAC;CAC5D,MAAM,KAAK,QAAQ,MAAM,EAAE,OAAO,CAAC;CAEnC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAU,WAAuD,mBAAmB;GACpF,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GACnB,MAAM,cAAc,OAAO,SAAS,MAAM,KAAK,MAAM,GAAG,EAAA,CAAG,IAAiB;EAC9E;EACA,OAAO,YAAY;GACjB,IAAI,OACF,MAAM,UAAU,IAAI;EAExB;EACA,MAAM,YAAY;GAChB,MAAM,KAAK,MAAM,UAAU;EAC7B;CACF,CAAC;AACH;;AAGA,eAAe,UAAU,MAAwC;CAC/D,IAAI,SAAS,QAAQ,OAAO,KAAK,QAAQ,YACvC,MAAM,KAAK,IAAI;MACV,IAAI,aAAa,QAAQ,OAAO,KAAK,YAAY,YACtD,KAAK,QAAQ;AAEjB"}
1
+ {"version":3,"file":"neon.mjs","names":[],"sources":["../src/neon.ts"],"sourcesContent":["/**\n * Neon (WebSocket pool) preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default; only\n * the driver differs (`@neondatabase/serverless` pooled connections work on\n * Node and edge runtimes with a WebSocket constructor). Requires the\n * optional `@neondatabase/serverless` peer (`nub add @neondatabase/serverless`).\n */\nimport { Pool, type PoolClient } from \"@neondatabase/serverless\";\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/neon-serverless\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a Neon-backed DatabaseAdapter.\n *\n * When `client` (a `Pool` or `PoolClient`) is supplied, all other\n * connection options are ignored and the caller owns the lifecycle of the\n * client (teardown is a no-op). This is the hook for custom WebSocket\n * constructors and hermetic tests.\n */\nexport interface NeonDatabaseOptions {\n url?: string;\n connectionString?: string;\n client?: Pool | PoolClient;\n}\n\n/**\n * Create a Neon-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a connection `url` or a preconfigured Neon\n * `client`.\n * @returns A DatabaseAdapter backed by the Neon database.\n */\nexport function createNeonDatabase(options: NeonDatabaseOptions): DatabaseAdapter {\n const connectionString = options.connectionString ?? options.url;\n if (!options.client && !connectionString) {\n throw new Error(\n \"createNeonDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n\n const owned = !options.client;\n const pool = options.client ?? new Pool({ connectionString });\n const db = drizzle(pool, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Neon\",\n version: typeof __PKG_VERSION__ === \"string\" ? __PKG_VERSION__ : \"0.0.0\",\n description: \"Neon Postgres database adapter (serverless driver + Drizzle)\",\n kind: \"neon\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n await runMigrations(async (sql) => (await pool.query(sql)).rows as unknown[]);\n },\n close: async () => {\n if (owned) {\n await endClient(pool);\n }\n },\n ping: async () => {\n await pool.query(\"SELECT 1\");\n },\n });\n}\n\n/** Close an owned client: pools end, checked-out clients release. */\nasync function endClient(pool: Pool | PoolClient): Promise<void> {\n if (\"end\" in pool && typeof pool.end === \"function\") {\n await pool.end();\n } else if (\"release\" in pool && typeof pool.release === \"function\") {\n pool.release();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,mBAAmB,SAA+C;CAChF,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,QAAQ,UAAU,CAAC,kBACtB,MAAM,IAAI,MACR,uFACF;CAGF,MAAM,QAAQ,CAAC,QAAQ;CACvB,MAAM,OAAO,QAAQ,UAAU,IAAI,KAAK,EAAE,iBAAiB,CAAC;CAC5D,MAAM,KAAK,QAAQ,MAAM,EAAE,OAAO,CAAC;CAEnC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAA;GACA,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GACnB,MAAM,cAAc,OAAO,SAAS,MAAM,KAAK,MAAM,GAAG,EAAA,CAAG,IAAiB;EAC9E;EACA,OAAO,YAAY;GACjB,IAAI,OACF,MAAM,UAAU,IAAI;EAExB;EACA,MAAM,YAAY;GAChB,MAAM,KAAK,MAAM,UAAU;EAC7B;CACF,CAAC;AACH;;AAGA,eAAe,UAAU,MAAwC;CAC/D,IAAI,SAAS,QAAQ,OAAO,KAAK,QAAQ,YACvC,MAAM,KAAK,IAAI;MACV,IAAI,aAAa,QAAQ,OAAO,KAAK,YAAY,YACtD,KAAK,QAAQ;AAEjB"}
package/dist/pg.mjs CHANGED
@@ -29,7 +29,7 @@ function createPgDatabase(options) {
29
29
  return createDrizzlePgAdapter(db, {
30
30
  metadata: {
31
31
  name: "Postgres (pg)",
32
- version: globalThis.__PKG_VERSION__ ?? "0.0.0",
32
+ version: "0.7.0",
33
33
  description: "Postgres database adapter (node-postgres + Drizzle)",
34
34
  kind: "pg",
35
35
  category: "database"
package/dist/pg.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pg.mjs","names":[],"sources":["../src/pg.ts"],"sourcesContent":["/**\n * node-postgres preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default; only\n * the driver differs. `node-postgres` uses unnamed portals, so it works\n * behind transaction-mode poolers (PgBouncer, Supavisor, Neon pooled)\n * without `prepare: false`, and it plugs into IAM flows (RDS token\n * password, Cloud SQL connector) that hand out `pg`-shaped clients.\n * Requires the optional `pg` peer (`nub add pg`).\n */\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { Pool, type Client, type PoolClient } from \"pg\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a node-postgres-backed DatabaseAdapter.\n *\n * When `client` (a `Pool`, `Client`, or `PoolClient`) is supplied, all other\n * connection options are ignored and the caller owns the lifecycle of the\n * client (teardown is a no-op). This is the hook for IAM token refresh,\n * Cloud SQL connectors, and hermetic tests.\n */\nexport interface PgDatabaseOptions {\n url?: string;\n connectionString?: string;\n ssl?: unknown;\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n client?: Pool | Client | PoolClient;\n}\n\n/**\n * Create a node-postgres-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a connection `url` (plus pooling/TLS options) or\n * a preconfigured `pg` `client`.\n * @returns A DatabaseAdapter backed by Postgres.\n */\nexport function createPgDatabase(options: PgDatabaseOptions): DatabaseAdapter {\n const connectionString = options.connectionString ?? options.url;\n if (!options.client && !connectionString) {\n throw new Error(\n \"createPgDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n\n const owned = !options.client;\n const pool =\n options.client ??\n new Pool({\n connectionString,\n ssl: options.ssl,\n max: options.max,\n idleTimeoutMillis: options.idleTimeoutMillis,\n connectionTimeoutMillis: options.connectionTimeoutMillis,\n });\n const db = drizzle(pool, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Postgres (pg)\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"Postgres database adapter (node-postgres + Drizzle)\",\n kind: \"pg\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n await runMigrations(async (sql) => (await pool.query(sql)).rows);\n },\n close: async () => {\n if (owned) {\n await endClient(pool);\n }\n },\n ping: async () => {\n await pool.query(\"SELECT 1\");\n },\n });\n}\n\n/** Close an owned client: pools end, bare clients disconnect. */\nasync function endClient(pool: Pool | Client | PoolClient): Promise<void> {\n if (\"end\" in pool && typeof pool.end === \"function\") {\n await (pool as Pool).end();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA4CA,SAAgB,iBAAiB,SAA6C;CAC5E,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,QAAQ,UAAU,CAAC,kBACtB,MAAM,IAAI,MACR,qFACF;CAGF,MAAM,QAAQ,CAAC,QAAQ;CACvB,MAAM,OACJ,QAAQ,UACR,IAAI,KAAK;EACP;EACA,KAAK,QAAQ;EACb,KAAK,QAAQ;EACb,mBAAmB,QAAQ;EAC3B,yBAAyB,QAAQ;CACnC,CAAC;CACH,MAAM,KAAK,QAAQ,MAAM,EAAE,OAAO,CAAC;CAEnC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAU,WAAuD,mBAAmB;GACpF,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GACnB,MAAM,cAAc,OAAO,SAAS,MAAM,KAAK,MAAM,GAAG,EAAA,CAAG,IAAI;EACjE;EACA,OAAO,YAAY;GACjB,IAAI,OACF,MAAM,UAAU,IAAI;EAExB;EACA,MAAM,YAAY;GAChB,MAAM,KAAK,MAAM,UAAU;EAC7B;CACF,CAAC;AACH;;AAGA,eAAe,UAAU,MAAiD;CACxE,IAAI,SAAS,QAAQ,OAAO,KAAK,QAAQ,YACvC,MAAO,KAAc,IAAI;AAE7B"}
1
+ {"version":3,"file":"pg.mjs","names":[],"sources":["../src/pg.ts"],"sourcesContent":["/**\n * node-postgres preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default; only\n * the driver differs. `node-postgres` uses unnamed portals, so it works\n * behind transaction-mode poolers (PgBouncer, Supavisor, Neon pooled)\n * without `prepare: false`, and it plugs into IAM flows (RDS token\n * password, Cloud SQL connector) that hand out `pg`-shaped clients.\n * Requires the optional `pg` peer (`nub add pg`).\n */\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { Pool, type Client, type PoolClient } from \"pg\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a node-postgres-backed DatabaseAdapter.\n *\n * When `client` (a `Pool`, `Client`, or `PoolClient`) is supplied, all other\n * connection options are ignored and the caller owns the lifecycle of the\n * client (teardown is a no-op). This is the hook for IAM token refresh,\n * Cloud SQL connectors, and hermetic tests.\n */\nexport interface PgDatabaseOptions {\n url?: string;\n connectionString?: string;\n ssl?: unknown;\n max?: number;\n idleTimeoutMillis?: number;\n connectionTimeoutMillis?: number;\n client?: Pool | Client | PoolClient;\n}\n\n/**\n * Create a node-postgres-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a connection `url` (plus pooling/TLS options) or\n * a preconfigured `pg` `client`.\n * @returns A DatabaseAdapter backed by Postgres.\n */\nexport function createPgDatabase(options: PgDatabaseOptions): DatabaseAdapter {\n const connectionString = options.connectionString ?? options.url;\n if (!options.client && !connectionString) {\n throw new Error(\n \"createPgDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n\n const owned = !options.client;\n const pool =\n options.client ??\n new Pool({\n connectionString,\n ssl: options.ssl,\n max: options.max,\n idleTimeoutMillis: options.idleTimeoutMillis,\n connectionTimeoutMillis: options.connectionTimeoutMillis,\n });\n const db = drizzle(pool, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Postgres (pg)\",\n version: typeof __PKG_VERSION__ === \"string\" ? __PKG_VERSION__ : \"0.0.0\",\n description: \"Postgres database adapter (node-postgres + Drizzle)\",\n kind: \"pg\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n await runMigrations(async (sql) => (await pool.query(sql)).rows);\n },\n close: async () => {\n if (owned) {\n await endClient(pool);\n }\n },\n ping: async () => {\n await pool.query(\"SELECT 1\");\n },\n });\n}\n\n/** Close an owned client: pools end, bare clients disconnect. */\nasync function endClient(pool: Pool | Client | PoolClient): Promise<void> {\n if (\"end\" in pool && typeof pool.end === \"function\") {\n await (pool as Pool).end();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA4CA,SAAgB,iBAAiB,SAA6C;CAC5E,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,QAAQ,UAAU,CAAC,kBACtB,MAAM,IAAI,MACR,qFACF;CAGF,MAAM,QAAQ,CAAC,QAAQ;CACvB,MAAM,OACJ,QAAQ,UACR,IAAI,KAAK;EACP;EACA,KAAK,QAAQ;EACb,KAAK,QAAQ;EACb,mBAAmB,QAAQ;EAC3B,yBAAyB,QAAQ;CACnC,CAAC;CACH,MAAM,KAAK,QAAQ,MAAM,EAAE,OAAO,CAAC;CAEnC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAA;GACA,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GACnB,MAAM,cAAc,OAAO,SAAS,MAAM,KAAK,MAAM,GAAG,EAAA,CAAG,IAAI;EACjE;EACA,OAAO,YAAY;GACjB,IAAI,OACF,MAAM,UAAU,IAAI;EAExB;EACA,MAAM,YAAY;GAChB,MAAM,KAAK,MAAM,UAAU;EAC7B;CACF,CAAC;AACH;;AAGA,eAAe,UAAU,MAAiD;CACxE,IAAI,SAAS,QAAQ,OAAO,KAAK,QAAQ,YACvC,MAAO,KAAc,IAAI;AAE7B"}
package/dist/pglite.mjs CHANGED
@@ -29,7 +29,7 @@ function createPgliteDatabase(options = {}) {
29
29
  return createDrizzlePgAdapter(db, {
30
30
  metadata: {
31
31
  name: "PGlite",
32
- version: globalThis.__PKG_VERSION__ ?? "0.0.0",
32
+ version: "0.7.0",
33
33
  description: "PGlite database adapter (embedded Postgres/WASM + Drizzle)",
34
34
  kind: "pglite",
35
35
  category: "database"
@@ -37,7 +37,7 @@ function createPgliteDatabase(options = {}) {
37
37
  tables: schema,
38
38
  migrate: async () => {
39
39
  await runMigrations(async (sql) => {
40
- return (await client.query(sql)).rows;
40
+ return (await client.exec(sql)).flatMap((result) => result.rows);
41
41
  });
42
42
  },
43
43
  close: async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"pglite.mjs","names":[],"sources":["../src/pglite.ts"],"sourcesContent":["/**\n * PGlite (embedded Postgres/WASM) preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default; only\n * the driver differs (in-memory or `memory://` WASM Postgres, no server or\n * sockets). Useful for hermetic tests and zero-infra local dev. Requires\n * the optional `@electric-sql/pglite` peer (`nub add @electric-sql/pglite`).\n */\nimport { PGlite } from \"@electric-sql/pglite\";\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/pglite\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a PGlite-backed DatabaseAdapter.\n *\n * When `client` (a `PGlite` instance) is supplied, `dataDir` is ignored and\n * the caller owns the lifecycle of the client (teardown is a no-op). This is\n * the hook for shared instances and for waiting on `client.waitReady` in\n * tests. With no options, an ephemeral in-memory database is created.\n */\nexport interface PgliteDatabaseOptions {\n dataDir?: string;\n client?: PGlite;\n}\n\n/**\n * Create a PGlite-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a `dataDir` (use `\"memory://\"` for an ephemeral\n * in-memory database, the default) or a preconfigured `PGlite` `client`.\n * @returns A DatabaseAdapter backed by the embedded Postgres instance.\n */\nexport function createPgliteDatabase(options: PgliteDatabaseOptions = {}): DatabaseAdapter {\n const owned = !options.client;\n const client = options.client ?? new PGlite(options.dataDir ?? \"memory://\");\n const db = drizzle(client, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"PGlite\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"PGlite database adapter (embedded Postgres/WASM + Drizzle)\",\n kind: \"pglite\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n await runMigrations(async (sql) => {\n const result = await client.query(sql);\n // oxlint-disable-next-line typescript/no-unnecessary-type-assertion -- PGlite Row[] vs unknown[]\n return result.rows as unknown as unknown[];\n });\n },\n close: async () => {\n if (owned) {\n await client.close();\n }\n },\n ping: async () => {\n await client.query(\"SELECT 1\");\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,qBAAqB,UAAiC,CAAC,GAAoB;CACzF,MAAM,QAAQ,CAAC,QAAQ;CACvB,MAAM,SAAS,QAAQ,UAAU,IAAI,OAAO,QAAQ,WAAW,WAAW;CAC1E,MAAM,KAAK,QAAQ,QAAQ,EAAE,OAAO,CAAC;CAErC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAU,WAAuD,mBAAmB;GACpF,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GACnB,MAAM,cAAc,OAAO,QAAQ;IAGjC,QAAO,MAFc,OAAO,MAAM,GAAG,EAAA,CAEvB;GAChB,CAAC;EACH;EACA,OAAO,YAAY;GACjB,IAAI,OACF,MAAM,OAAO,MAAM;EAEvB;EACA,MAAM,YAAY;GAChB,MAAM,OAAO,MAAM,UAAU;EAC/B;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"pglite.mjs","names":[],"sources":["../src/pglite.ts"],"sourcesContent":["/**\n * PGlite (embedded Postgres/WASM) preset for the Postgres database adapter.\n *\n * Same schema, DDL, and Drizzle factory as the `postgres.js` default; only\n * the driver differs (in-memory or `memory://` WASM Postgres, no server or\n * sockets). Useful for hermetic tests and zero-infra local dev. Requires\n * the optional `@electric-sql/pglite` peer (`nub add @electric-sql/pglite`).\n */\nimport { PGlite } from \"@electric-sql/pglite\";\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/pglite\";\nimport { createDrizzlePgAdapter } from \"./drizzle-factory-pg.ts\";\nimport { runMigrations } from \"./migrate.ts\";\nimport { schema } from \"./schema/index.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/**\n * Options for creating a PGlite-backed DatabaseAdapter.\n *\n * When `client` (a `PGlite` instance) is supplied, `dataDir` is ignored and\n * the caller owns the lifecycle of the client (teardown is a no-op). This is\n * the hook for shared instances and for waiting on `client.waitReady` in\n * tests. With no options, an ephemeral in-memory database is created.\n */\nexport interface PgliteDatabaseOptions {\n dataDir?: string;\n client?: PGlite;\n}\n\n/**\n * Create a PGlite-backed DatabaseAdapter using Drizzle ORM.\n *\n * @param options - Either a `dataDir` (use `\"memory://\"` for an ephemeral\n * in-memory database, the default) or a preconfigured `PGlite` `client`.\n * @returns A DatabaseAdapter backed by the embedded Postgres instance.\n */\nexport function createPgliteDatabase(options: PgliteDatabaseOptions = {}): DatabaseAdapter {\n const owned = !options.client;\n const client = options.client ?? new PGlite(options.dataDir ?? \"memory://\");\n const db = drizzle(client, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"PGlite\",\n version: typeof __PKG_VERSION__ === \"string\" ? __PKG_VERSION__ : \"0.0.0\",\n description: \"PGlite database adapter (embedded Postgres/WASM + Drizzle)\",\n kind: \"pglite\",\n category: \"database\",\n },\n tables: schema,\n migrate: async () => {\n // `exec`, not `query`: the DDL is many statements, which PGlite's prepared `query` rejects.\n await runMigrations(async (sql) => {\n const results = await client.exec(sql);\n return results.flatMap((result) => result.rows as unknown[]);\n });\n },\n close: async () => {\n if (owned) {\n await client.close();\n }\n },\n ping: async () => {\n await client.query(\"SELECT 1\");\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,qBAAqB,UAAiC,CAAC,GAAoB;CACzF,MAAM,QAAQ,CAAC,QAAQ;CACvB,MAAM,SAAS,QAAQ,UAAU,IAAI,OAAO,QAAQ,WAAW,WAAW;CAC1E,MAAM,KAAK,QAAQ,QAAQ,EAAE,OAAO,CAAC;CAErC,OAAO,uBAAuB,IAAI;EAChC,UAAU;GACR,MAAM;GACN,SAAA;GACA,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,QAAQ;EACR,SAAS,YAAY;GAEnB,MAAM,cAAc,OAAO,QAAQ;IAEjC,QAAO,MADe,OAAO,KAAK,GAAG,EAAA,CACtB,SAAS,WAAW,OAAO,IAAiB;GAC7D,CAAC;EACH;EACA,OAAO,YAAY;GACjB,IAAI,OACF,MAAM,OAAO,MAAM;EAEvB;EACA,MAAM,YAAY;GAChB,MAAM,OAAO,MAAM,UAAU;EAC/B;CACF,CAAC;AACH"}
@@ -142,6 +142,57 @@ declare const baselines: import("drizzle-orm/pg-core").PgTableWithColumns<{
142
142
  identity: undefined;
143
143
  generated: undefined;
144
144
  }, {}, {}>;
145
+ fingerprint: import("drizzle-orm/pg-core").PgColumn<{
146
+ name: "fingerprint";
147
+ tableName: "baselines";
148
+ dataType: "string";
149
+ columnType: "PgText";
150
+ data: string;
151
+ driverParam: string;
152
+ notNull: false;
153
+ hasDefault: false;
154
+ isPrimaryKey: false;
155
+ isAutoincrement: false;
156
+ hasRuntimeDefault: false;
157
+ enumValues: [string, ...string[]];
158
+ baseColumn: never;
159
+ identity: undefined;
160
+ generated: undefined;
161
+ }, {}, {}>;
162
+ mode: import("drizzle-orm/pg-core").PgColumn<{
163
+ name: "mode";
164
+ tableName: "baselines";
165
+ dataType: "string";
166
+ columnType: "PgText";
167
+ data: string;
168
+ driverParam: string;
169
+ notNull: false;
170
+ hasDefault: false;
171
+ isPrimaryKey: false;
172
+ isAutoincrement: false;
173
+ hasRuntimeDefault: false;
174
+ enumValues: [string, ...string[]];
175
+ baseColumn: never;
176
+ identity: undefined;
177
+ generated: undefined;
178
+ }, {}, {}>;
179
+ browser: import("drizzle-orm/pg-core").PgColumn<{
180
+ name: "browser";
181
+ tableName: "baselines";
182
+ dataType: "string";
183
+ columnType: "PgText";
184
+ data: string;
185
+ driverParam: string;
186
+ notNull: true;
187
+ hasDefault: true;
188
+ isPrimaryKey: false;
189
+ isAutoincrement: false;
190
+ hasRuntimeDefault: false;
191
+ enumValues: [string, ...string[]];
192
+ baseColumn: never;
193
+ identity: undefined;
194
+ generated: undefined;
195
+ }, {}, {}>;
145
196
  createdAt: import("drizzle-orm/pg-core").PgColumn<{
146
197
  name: "created_at";
147
198
  tableName: "baselines";
@@ -189,6 +240,9 @@ interface Baseline {
189
240
  snapshotId: string | null;
190
241
  screenshotPath: string;
191
242
  infraHash: string | null;
243
+ fingerprint: string | null;
244
+ mode?: string | null;
245
+ browser?: string;
192
246
  createdAt: string;
193
247
  updatedAt: string;
194
248
  }
@@ -14,6 +14,9 @@ const baselines = pgTable("baselines", {
14
14
  snapshotId: text("snapshot_id"),
15
15
  screenshotPath: text("screenshot_path").notNull(),
16
16
  infraHash: text("infra_hash"),
17
+ fingerprint: text("fingerprint"),
18
+ mode: text("mode"),
19
+ browser: text("browser").notNull().default("chromium"),
17
20
  createdAt: timestamp("created_at", {
18
21
  withTimezone: true,
19
22
  mode: "string"
@@ -22,7 +25,7 @@ const baselines = pgTable("baselines", {
22
25
  withTimezone: true,
23
26
  mode: "string"
24
27
  }).notNull()
25
- }, (t) => [uniqueIndex("baselines_project_story_viewport_branch_idx").on(t.projectId, t.storyId, t.viewportName, t.branch), index("baselines_project_story_idx").on(t.projectId, t.storyId)]);
28
+ }, (t) => [uniqueIndex("baselines_project_story_mode_browser_branch_idx").on(t.projectId, t.storyId, t.viewportName, t.browser, t.branch), index("baselines_project_story_idx").on(t.projectId, t.storyId)]);
26
29
  //#endregion
27
30
  export { baselines };
28
31
 
@@ -1 +1 @@
1
- {"version":3,"file":"baseline.mjs","names":[],"sources":["../../src/schema/baseline.ts"],"sourcesContent":["import { index, pgTable, text, timestamp, uniqueIndex } from \"drizzle-orm/pg-core\";\nimport { projects } from \"./project.ts\";\n\n/** Narrow `baselines` table definition. */\nexport const baselines = pgTable(\n \"baselines\",\n {\n id: text(\"id\").primaryKey(),\n projectId: text(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n storyId: text(\"story_id\").notNull(),\n viewportName: text(\"viewport_name\").notNull().default(\"desktop\"),\n branch: text(\"branch\").notNull(),\n snapshotId: text(\"snapshot_id\"),\n screenshotPath: text(\"screenshot_path\").notNull(),\n infraHash: text(\"infra_hash\"),\n createdAt: timestamp(\"created_at\", { withTimezone: true, mode: \"string\" }).notNull(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true, mode: \"string\" }).notNull(),\n },\n (t) => [\n uniqueIndex(\"baselines_project_story_viewport_branch_idx\").on(\n t.projectId,\n t.storyId,\n t.viewportName,\n t.branch,\n ),\n index(\"baselines_project_story_idx\").on(t.projectId, t.storyId),\n ],\n);\n\n/** A baseline row. */\nexport interface Baseline {\n id: string;\n projectId: string;\n storyId: string;\n viewportName: string;\n branch: string;\n snapshotId: string | null;\n screenshotPath: string;\n infraHash: string | null;\n createdAt: string;\n updatedAt: string;\n}\n"],"mappings":";;;;;;;AAIA,MAAa,YAAY,QACvB,aACA;CACE,IAAI,KAAK,IAAI,CAAC,CAAC,WAAW;CAC1B,WAAW,KAAK,YAAY,CAAC,CAC1B,QAAQ,CAAC,CACT,iBAAiB,SAAS,IAAI,EAAE,UAAU,UAAU,CAAC;CACxD,SAAS,KAAK,UAAU,CAAC,CAAC,QAAQ;CAClC,cAAc,KAAK,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,SAAS;CAC/D,QAAQ,KAAK,QAAQ,CAAC,CAAC,QAAQ;CAC/B,YAAY,KAAK,aAAa;CAC9B,gBAAgB,KAAK,iBAAiB,CAAC,CAAC,QAAQ;CAChD,WAAW,KAAK,YAAY;CAC5B,WAAW,UAAU,cAAc;EAAE,cAAc;EAAM,MAAM;CAAS,CAAC,CAAC,CAAC,QAAQ;CACnF,WAAW,UAAU,cAAc;EAAE,cAAc;EAAM,MAAM;CAAS,CAAC,CAAC,CAAC,QAAQ;AACrF,IACC,MAAM,CACL,YAAY,6CAA6C,CAAC,CAAC,GACzD,EAAE,WACF,EAAE,SACF,EAAE,cACF,EAAE,MACJ,GACA,MAAM,6BAA6B,CAAC,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAChE,CACF"}
1
+ {"version":3,"file":"baseline.mjs","names":[],"sources":["../../src/schema/baseline.ts"],"sourcesContent":["import { index, pgTable, text, timestamp, uniqueIndex } from \"drizzle-orm/pg-core\";\nimport { projects } from \"./project.ts\";\n\n/** Narrow `baselines` table definition. */\nexport const baselines = pgTable(\n \"baselines\",\n {\n id: text(\"id\").primaryKey(),\n projectId: text(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n storyId: text(\"story_id\").notNull(),\n viewportName: text(\"viewport_name\").notNull().default(\"desktop\"),\n branch: text(\"branch\").notNull(),\n snapshotId: text(\"snapshot_id\"),\n screenshotPath: text(\"screenshot_path\").notNull(),\n infraHash: text(\"infra_hash\"),\n fingerprint: text(\"fingerprint\"),\n mode: text(\"mode\"),\n browser: text(\"browser\").notNull().default(\"chromium\"),\n createdAt: timestamp(\"created_at\", { withTimezone: true, mode: \"string\" }).notNull(),\n updatedAt: timestamp(\"updated_at\", { withTimezone: true, mode: \"string\" }).notNull(),\n },\n (t) => [\n uniqueIndex(\"baselines_project_story_mode_browser_branch_idx\").on(\n t.projectId,\n t.storyId,\n t.viewportName,\n t.browser,\n t.branch,\n ),\n index(\"baselines_project_story_idx\").on(t.projectId, t.storyId),\n ],\n);\n\n/** A baseline row. */\nexport interface Baseline {\n id: string;\n projectId: string;\n storyId: string;\n viewportName: string;\n branch: string;\n snapshotId: string | null;\n screenshotPath: string;\n infraHash: string | null;\n fingerprint: string | null;\n mode?: string | null;\n browser?: string;\n createdAt: string;\n updatedAt: string;\n}\n"],"mappings":";;;;;;;AAIA,MAAa,YAAY,QACvB,aACA;CACE,IAAI,KAAK,IAAI,CAAC,CAAC,WAAW;CAC1B,WAAW,KAAK,YAAY,CAAC,CAC1B,QAAQ,CAAC,CACT,iBAAiB,SAAS,IAAI,EAAE,UAAU,UAAU,CAAC;CACxD,SAAS,KAAK,UAAU,CAAC,CAAC,QAAQ;CAClC,cAAc,KAAK,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,SAAS;CAC/D,QAAQ,KAAK,QAAQ,CAAC,CAAC,QAAQ;CAC/B,YAAY,KAAK,aAAa;CAC9B,gBAAgB,KAAK,iBAAiB,CAAC,CAAC,QAAQ;CAChD,WAAW,KAAK,YAAY;CAC5B,aAAa,KAAK,aAAa;CAC/B,MAAM,KAAK,MAAM;CACjB,SAAS,KAAK,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,UAAU;CACrD,WAAW,UAAU,cAAc;EAAE,cAAc;EAAM,MAAM;CAAS,CAAC,CAAC,CAAC,QAAQ;CACnF,WAAW,UAAU,cAAc;EAAE,cAAc;EAAM,MAAM;CAAS,CAAC,CAAC,CAAC,QAAQ;AACrF,IACC,MAAM,CACL,YAAY,iDAAiD,CAAC,CAAC,GAC7D,EAAE,WACF,EAAE,SACF,EAAE,cACF,EAAE,SACF,EAAE,MACJ,GACA,MAAM,6BAA6B,CAAC,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAChE,CACF"}
@@ -1,14 +1,14 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
- //#region src/schema/status-config.d.ts
4
- /** Narrow `project_status_configs` table definition. */
5
- declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithColumns<{
6
- name: "project_status_configs";
3
+ //#region src/schema/build-component.d.ts
4
+ /** Narrow `build_components` table definition: one row per component of a published build. */
5
+ declare const buildComponents: import("drizzle-orm/pg-core").PgTableWithColumns<{
6
+ name: "build_components";
7
7
  schema: undefined;
8
8
  columns: {
9
9
  id: import("drizzle-orm/pg-core").PgColumn<{
10
10
  name: "id";
11
- tableName: "project_status_configs";
11
+ tableName: "build_components";
12
12
  dataType: "string";
13
13
  columnType: "PgText";
14
14
  data: string;
@@ -25,7 +25,7 @@ declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithCol
25
25
  }, {}, {}>;
26
26
  projectId: import("drizzle-orm/pg-core").PgColumn<{
27
27
  name: "project_id";
28
- tableName: "project_status_configs";
28
+ tableName: "build_components";
29
29
  dataType: "string";
30
30
  columnType: "PgText";
31
31
  data: string;
@@ -40,9 +40,9 @@ declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithCol
40
40
  identity: undefined;
41
41
  generated: undefined;
42
42
  }, {}, {}>;
43
- provider: import("drizzle-orm/pg-core").PgColumn<{
44
- name: "provider";
45
- tableName: "project_status_configs";
43
+ buildId: import("drizzle-orm/pg-core").PgColumn<{
44
+ name: "build_id";
45
+ tableName: "build_components";
46
46
  dataType: "string";
47
47
  columnType: "PgText";
48
48
  data: string;
@@ -57,9 +57,9 @@ declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithCol
57
57
  identity: undefined;
58
58
  generated: undefined;
59
59
  }, {}, {}>;
60
- config: import("drizzle-orm/pg-core").PgColumn<{
61
- name: "config";
62
- tableName: "project_status_configs";
60
+ importPath: import("drizzle-orm/pg-core").PgColumn<{
61
+ name: "import_path";
62
+ tableName: "build_components";
63
63
  dataType: "string";
64
64
  columnType: "PgText";
65
65
  data: string;
@@ -74,9 +74,9 @@ declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithCol
74
74
  identity: undefined;
75
75
  generated: undefined;
76
76
  }, {}, {}>;
77
- tokenEncrypted: import("drizzle-orm/pg-core").PgColumn<{
78
- name: "token_encrypted";
79
- tableName: "project_status_configs";
77
+ title: import("drizzle-orm/pg-core").PgColumn<{
78
+ name: "title";
79
+ tableName: "build_components";
80
80
  dataType: "string";
81
81
  columnType: "PgText";
82
82
  data: string;
@@ -91,11 +91,28 @@ declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithCol
91
91
  identity: undefined;
92
92
  generated: undefined;
93
93
  }, {}, {}>;
94
- createdAt: import("drizzle-orm/pg-core").PgColumn<{
95
- name: "created_at";
96
- tableName: "project_status_configs";
94
+ storyCount: import("drizzle-orm/pg-core").PgColumn<{
95
+ name: "story_count";
96
+ tableName: "build_components";
97
+ dataType: "number";
98
+ columnType: "PgInteger";
99
+ data: number;
100
+ driverParam: string | number;
101
+ notNull: true;
102
+ hasDefault: true;
103
+ isPrimaryKey: false;
104
+ isAutoincrement: false;
105
+ hasRuntimeDefault: false;
106
+ enumValues: undefined;
107
+ baseColumn: never;
108
+ identity: undefined;
109
+ generated: undefined;
110
+ }, {}, {}>;
111
+ hash: import("drizzle-orm/pg-core").PgColumn<{
112
+ name: "hash";
113
+ tableName: "build_components";
97
114
  dataType: "string";
98
- columnType: "PgTimestampString";
115
+ columnType: "PgText";
99
116
  data: string;
100
117
  driverParam: string;
101
118
  notNull: true;
@@ -103,14 +120,14 @@ declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithCol
103
120
  isPrimaryKey: false;
104
121
  isAutoincrement: false;
105
122
  hasRuntimeDefault: false;
106
- enumValues: undefined;
123
+ enumValues: [string, ...string[]];
107
124
  baseColumn: never;
108
125
  identity: undefined;
109
126
  generated: undefined;
110
127
  }, {}, {}>;
111
- updatedAt: import("drizzle-orm/pg-core").PgColumn<{
112
- name: "updated_at";
113
- tableName: "project_status_configs";
128
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
129
+ name: "created_at";
130
+ tableName: "build_components";
114
131
  dataType: "string";
115
132
  columnType: "PgTimestampString";
116
133
  data: string;
@@ -128,16 +145,6 @@ declare const projectStatusConfigs: import("drizzle-orm/pg-core").PgTableWithCol
128
145
  };
129
146
  dialect: 'pg';
130
147
  }>;
131
- /** A project status-config row. */
132
- interface ProjectStatusConfig {
133
- id: string;
134
- projectId: string;
135
- provider: string;
136
- config: string;
137
- tokenEncrypted: string;
138
- createdAt: string;
139
- updatedAt: string;
140
- }
141
148
  //#endregion
142
- export { ProjectStatusConfig, projectStatusConfigs };
143
- //# sourceMappingURL=status-config.d.mts.map
149
+ export { buildComponents };
150
+ //# sourceMappingURL=build-component.d.mts.map
@@ -0,0 +1,25 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { projects } from "./project.mjs";
5
+ import { builds } from "./build.mjs";
6
+ import { index, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
7
+ //#region src/schema/build-component.ts
8
+ /** Narrow `build_components` table definition: one row per component of a published build. */
9
+ const buildComponents = pgTable("build_components", {
10
+ id: text("id").primaryKey(),
11
+ projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
12
+ buildId: text("build_id").notNull().references(() => builds.id, { onDelete: "cascade" }),
13
+ importPath: text("import_path").notNull(),
14
+ title: text("title").notNull(),
15
+ storyCount: integer("story_count").notNull().default(0),
16
+ hash: text("hash").notNull(),
17
+ createdAt: timestamp("created_at", {
18
+ withTimezone: true,
19
+ mode: "string"
20
+ }).notNull()
21
+ }, (table) => [index("build_components_build_id_idx").on(table.buildId), index("build_components_project_import_path_idx").on(table.projectId, table.importPath)]);
22
+ //#endregion
23
+ export { buildComponents };
24
+
25
+ //# sourceMappingURL=build-component.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-component.mjs","names":[],"sources":["../../src/schema/build-component.ts"],"sourcesContent":["import { index, integer, pgTable, text, timestamp } from \"drizzle-orm/pg-core\";\nimport { builds } from \"./build.ts\";\nimport { projects } from \"./project.ts\";\n\n/** Narrow `build_components` table definition: one row per component of a published build. */\nexport const buildComponents = pgTable(\n \"build_components\",\n {\n id: text(\"id\").primaryKey(),\n projectId: text(\"project_id\")\n .notNull()\n .references(() => projects.id, { onDelete: \"cascade\" }),\n buildId: text(\"build_id\")\n .notNull()\n .references(() => builds.id, { onDelete: \"cascade\" }),\n importPath: text(\"import_path\").notNull(),\n title: text(\"title\").notNull(),\n storyCount: integer(\"story_count\").notNull().default(0),\n hash: text(\"hash\").notNull(),\n createdAt: timestamp(\"created_at\", { withTimezone: true, mode: \"string\" }).notNull(),\n },\n (table) => [\n index(\"build_components_build_id_idx\").on(table.buildId),\n index(\"build_components_project_import_path_idx\").on(table.projectId, table.importPath),\n ],\n);\n"],"mappings":";;;;;;;;AAKA,MAAa,kBAAkB,QAC7B,oBACA;CACE,IAAI,KAAK,IAAI,CAAC,CAAC,WAAW;CAC1B,WAAW,KAAK,YAAY,CAAC,CAC1B,QAAQ,CAAC,CACT,iBAAiB,SAAS,IAAI,EAAE,UAAU,UAAU,CAAC;CACxD,SAAS,KAAK,UAAU,CAAC,CACtB,QAAQ,CAAC,CACT,iBAAiB,OAAO,IAAI,EAAE,UAAU,UAAU,CAAC;CACtD,YAAY,KAAK,aAAa,CAAC,CAAC,QAAQ;CACxC,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ;CAC7B,YAAY,QAAQ,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;CACtD,MAAM,KAAK,MAAM,CAAC,CAAC,QAAQ;CAC3B,WAAW,UAAU,cAAc;EAAE,cAAc;EAAM,MAAM;CAAS,CAAC,CAAC,CAAC,QAAQ;AACrF,IACC,UAAU,CACT,MAAM,+BAA+B,CAAC,CAAC,GAAG,MAAM,OAAO,GACvD,MAAM,0CAA0C,CAAC,CAAC,GAAG,MAAM,WAAW,MAAM,UAAU,CACxF,CACF"}