@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/README.md CHANGED
@@ -17,3 +17,59 @@ const db = createPostgresDatabase({ url: "postgres://user:pass@localhost:5432/sh
17
17
  ```
18
18
 
19
19
  For managed providers, pass `ssl`, `prepare`, and pool options via `options` or inject a preconfigured `client` (see `PostgresDatabaseOptions`).
20
+
21
+ ## Configure
22
+
23
+ ```ts
24
+ import { createPostgresDatabase } from "@storyshelf/db-postgres";
25
+
26
+ const database = createPostgresDatabase({
27
+ url: process.env.DATABASE_URL!,
28
+ });
29
+ ```
30
+
31
+ `url` (or `connectionString`) is required unless a preconfigured `client` is injected. Optional `postgres.js` tuning is forwarded via `ssl`, `prepare`, `max`, `idleTimeout`, and `connectTimeout`. Migrations run inside the adapter's `lifecycle.setup` — await them via `app.lifecycle.setup()` after creating the router, and close via `app.lifecycle.teardown()` on shutdown. The adapter implements `DatabaseAdapter`: `insert`, `update`, `get`, `remove`, `list`, `count`, and `all`, plus `metadata`/`lifecycle` from the shared `Adapter` base.
32
+
33
+ ```ts
34
+ // With explicit pooling and TLS
35
+ const database = createPostgresDatabase({
36
+ url: process.env.DATABASE_URL!,
37
+ ssl: true,
38
+ prepare: true,
39
+ max: 10,
40
+ idleTimeout: 30,
41
+ connectTimeout: 10,
42
+ });
43
+ ```
44
+
45
+ ## Provider recipes
46
+
47
+ All providers speak the standard Postgres wire protocol. Pick the connection string and options for your host.
48
+
49
+ | Provider | Connection string shape | TLS | Pooling notes |
50
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
51
+ | Self-hosted | `postgres://user:pass@localhost:5432/shelf` | `ssl: false` or omit for plain TCP; set `ssl: true` if the server enforces TLS | Default `max: 10`; tune `max` / `idleTimeout` for your host |
52
+ | AWS RDS | `postgres://user:pass@<rds-endpoint>:5432/db?sslmode=require` | `ssl: true` for default CA; or `ssl: { ca: rdsCaBundle }` for a custom RDS CA bundle | IAM auth via injected `client` with a refreshed token (see below); `prepare: true` (default) is fine |
53
+ | GCP Cloud SQL | `postgres://user:pass@<cloudsql-ip>:5432/db` | `ssl: { ca, cert, key }` for mutual TLS (Cloud SQL server + client certs) | Use Cloud SQL Connector or inject a `client` with IAM credentials; mutual TLS required when not using the proxy |
54
+ | Supabase | `postgres://postgres.<ref>:<pass>@<pooler-host>:6543/postgres?pgbouncer=true` (pooler) or `:5432/postgres` (direct) | `ssl: true` (Supabase enforces TLS) | **PgBouncer (port `6543`, transaction mode) requires `prepare: false`**; direct connections on `5432` can leave `prepare: true` |
55
+ | Neon | `postgres://user:pass@<neon-host>/db?sslmode=require` | `ssl: true` | Serverless pooler — keep `max` low (e.g. `max: 5`); pooled endpoints via PgBouncer need `prepare: false` |
56
+ | Azure Database for PostgreSQL | `postgres://user:pass@<server>.postgres.database.azure.com:5432/db?sslmode=require` | `ssl: true` | Microsoft Entra ID (IAM) via injected `client` with an access token; otherwise password auth works with default pooling |
57
+
58
+ ## Client injection (IAM and advanced TLS)
59
+
60
+ When `client` is supplied, all other connection options are ignored and the caller owns the client lifecycle. Use this for IAM token refresh or pre-configured TLS:
61
+
62
+ ```ts
63
+ import postgres from "postgres";
64
+ import { createPostgresDatabase } from "@storyshelf/db-postgres";
65
+
66
+ // Example: IAM — fetch a fresh token before connecting (RDS, Azure Entra ID, etc.)
67
+ const client = postgres(process.env.DATABASE_URL!, {
68
+ ssl: true,
69
+ // password is the IAM token; refresh by recreating the client on rotation
70
+ });
71
+
72
+ const database = createPostgresDatabase({ client });
73
+ ```
74
+
75
+ This is also the hook for hermetic tests and for custom CA bundles that are loaded from disk or a secrets manager.
package/dist/ddl.d.mts CHANGED
@@ -2,7 +2,7 @@ import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  //#region src/ddl.d.ts
4
4
  /** Canonical Postgres DDL for all StoryShelf tables and indexes. */
5
- declare const DDL = "\nCREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n slug TEXT NOT NULL UNIQUE,\n git_repository TEXT,\n git_default_branch TEXT NOT NULL DEFAULT 'main',\n pixel_threshold DOUBLE PRECISION NOT NULL DEFAULT 0.1,\n max_diff_ratio DOUBLE PRECISION NOT NULL DEFAULT 0.01,\n public_branch_regex TEXT,\n storybook_meta TEXT,\n execute_play BOOLEAN NOT NULL DEFAULT false,\n play_timeout_ms INTEGER NOT NULL DEFAULT 10000,\n run_a11y BOOLEAN NOT NULL DEFAULT false,\n browser TEXT NOT NULL DEFAULT 'chromium',\n viewports TEXT,\n automigrate BOOLEAN NOT NULL DEFAULT false,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS project_status_configs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n config TEXT NOT NULL,\n token_encrypted TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS builds (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n git_sha TEXT NOT NULL,\n git_branch TEXT NOT NULL,\n is_default BOOLEAN NOT NULL DEFAULT false,\n author_email TEXT,\n author_name TEXT,\n message TEXT,\n public BOOLEAN NOT NULL DEFAULT false,\n status TEXT NOT NULL DEFAULT 'pending',\n snapshot_count INTEGER NOT NULL DEFAULT 0,\n changed_count INTEGER NOT NULL DEFAULT 0,\n approved_count INTEGER NOT NULL DEFAULT 0,\n rejected_count INTEGER NOT NULL DEFAULT 0,\n affected_only BOOLEAN NOT NULL DEFAULT true,\n baseline_sha TEXT,\n changed_files TEXT,\n affected_import_paths TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS builds_project_gitsha_idx ON builds (project_id, git_sha);\nCREATE INDEX IF NOT EXISTS builds_git_branch_idx ON builds (git_branch);\nCREATE TABLE IF NOT EXISTS capture_attempts (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_no INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'queued',\n error TEXT,\n req_id TEXT,\n story_count INTEGER NOT NULL DEFAULT 0,\n failed_count INTEGER NOT NULL DEFAULT 0,\n queued_at TIMESTAMPTZ NOT NULL,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS capture_attempts_build_no_idx ON capture_attempts (build_id, attempt_no);\nCREATE INDEX IF NOT EXISTS capture_attempts_build_id_idx ON capture_attempts (build_id);\nCREATE TABLE IF NOT EXISTS capture_logs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_id TEXT NOT NULL REFERENCES capture_attempts(id) ON DELETE CASCADE,\n seq INTEGER NOT NULL,\n level TEXT NOT NULL DEFAULT 'info',\n message TEXT NOT NULL,\n fields TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS capture_logs_attempt_seq_idx ON capture_logs (attempt_id, seq);\nCREATE TABLE IF NOT EXISTS snapshots (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n story_name TEXT NOT NULL,\n story_title TEXT NOT NULL,\n story_import_path TEXT,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n viewport_width INTEGER NOT NULL DEFAULT 1280,\n viewport_height INTEGER NOT NULL DEFAULT 720,\n screenshot_path TEXT NOT NULL,\n diff_path TEXT,\n diff_pixels INTEGER,\n diff_ratio DOUBLE PRECISION,\n diff_passed BOOLEAN,\n status TEXT NOT NULL DEFAULT 'pending',\n reviewed_by TEXT,\n reviewed_at TIMESTAMPTZ,\n infra_hash TEXT,\n inherited BOOLEAN NOT NULL DEFAULT false,\n baseline_id TEXT,\n baseline_version TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS snapshots_build_story_viewport_idx ON snapshots (build_id, story_id, viewport_name);\nCREATE INDEX IF NOT EXISTS snapshots_build_id_idx ON snapshots (build_id);\nCREATE TABLE IF NOT EXISTS baselines (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n branch TEXT NOT NULL,\n snapshot_id TEXT,\n screenshot_path TEXT NOT NULL,\n infra_hash TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS baselines_project_story_viewport_branch_idx ON baselines (project_id, story_id, viewport_name, branch);\nCREATE INDEX IF NOT EXISTS baselines_project_story_idx ON baselines (project_id, story_id);\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n email TEXT NOT NULL UNIQUE,\n name TEXT NOT NULL,\n avatar_url TEXT,\n role TEXT NOT NULL DEFAULT 'member',\n last_login_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS comments (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n snapshot_id TEXT REFERENCES snapshots(id) ON DELETE CASCADE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n body TEXT NOT NULL,\n parent_id TEXT,\n resolved BOOLEAN NOT NULL DEFAULT false,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS comments_build_id_idx ON comments (build_id);\nCREATE TABLE IF NOT EXISTS label_types (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n key TEXT NOT NULL,\n name TEXT NOT NULL,\n link_template TEXT,\n color TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS label_types_project_key_idx ON label_types (project_id, key);\nCREATE TABLE IF NOT EXISTS build_labels (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n type_key TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS build_labels_build_type_value_idx ON build_labels (build_id, type_key, value);\nCREATE TABLE IF NOT EXISTS tokens (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n hash TEXT NOT NULL UNIQUE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n last_used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS webhooks (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n url TEXT NOT NULL,\n secret_encrypted TEXT NOT NULL,\n events TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS notification_channels (\n id TEXT PRIMARY KEY,\n project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n config TEXT NOT NULL,\n secret_encrypted TEXT,\n events TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS notification_channels_project_id_idx ON notification_channels (project_id);\nCREATE TABLE IF NOT EXISTS notification_subscriptions (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n events TEXT,\n via TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS notification_subscriptions_project_user_idx ON notification_subscriptions (project_id, user_id);\nCREATE TABLE IF NOT EXISTS user_invite_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n token_hash TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS project_members (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n role TEXT NOT NULL DEFAULT 'viewer',\n source TEXT NOT NULL DEFAULT 'manual',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_members_project_user_idx ON project_members (project_id, user_id);\nCREATE TABLE IF NOT EXISTS project_group_mappings (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n group_name TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'viewer',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_group_mappings_project_group_idx ON project_group_mappings (project_id, group_name);\nCREATE TABLE IF NOT EXISTS content_refs (\n hash TEXT PRIMARY KEY,\n ref_count INTEGER NOT NULL DEFAULT 1,\n last_seen_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS \"user\" (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n email TEXT NOT NULL UNIQUE,\n email_verified BOOLEAN NOT NULL DEFAULT false,\n image TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS session (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n token TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n ip_address TEXT,\n user_agent TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS session_token_idx ON session (token);\nCREATE INDEX IF NOT EXISTS session_user_id_idx ON session (user_id);\nCREATE TABLE IF NOT EXISTS account (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n account_id TEXT NOT NULL,\n provider_id TEXT NOT NULL,\n access_token TEXT,\n refresh_token TEXT,\n id_token TEXT,\n access_token_expires_at TIMESTAMPTZ,\n refresh_token_expires_at TIMESTAMPTZ,\n scope TEXT,\n expires_at TIMESTAMPTZ,\n password TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS account_user_id_idx ON account (user_id);\nCREATE TABLE IF NOT EXISTS verification (\n id TEXT PRIMARY KEY,\n identifier TEXT NOT NULL,\n value TEXT NOT NULL,\n expires_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS verification_identifier_idx ON verification (identifier);\nCREATE TABLE IF NOT EXISTS passkey (\n id TEXT PRIMARY KEY,\n name TEXT,\n public_key TEXT NOT NULL,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n credential_id TEXT NOT NULL,\n counter INTEGER NOT NULL,\n device_type TEXT NOT NULL,\n backed_up BOOLEAN NOT NULL DEFAULT false,\n transports TEXT,\n aaguid TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ\n);\nCREATE INDEX IF NOT EXISTS passkey_user_id_idx ON passkey (user_id);\nCREATE INDEX IF NOT EXISTS passkey_credential_id_idx ON passkey (credential_id);\nCREATE TABLE IF NOT EXISTS \"ssoProvider\" (\n id TEXT PRIMARY KEY,\n issuer TEXT NOT NULL,\n oidc_config TEXT,\n saml_config TEXT,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n provider_id TEXT NOT NULL UNIQUE,\n organization_id TEXT,\n domain TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS ssoprovider_domain_idx ON \"ssoProvider\" (domain);\n";
5
+ declare const DDL = "\nCREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n slug TEXT NOT NULL UNIQUE,\n git_repository TEXT,\n git_default_branch TEXT NOT NULL DEFAULT 'main',\n pixel_threshold DOUBLE PRECISION NOT NULL DEFAULT 0.1,\n max_diff_ratio DOUBLE PRECISION NOT NULL DEFAULT 0.01,\n public_branch_regex TEXT,\n storybook_meta TEXT,\n execute_play BOOLEAN NOT NULL DEFAULT false,\n play_timeout_ms INTEGER NOT NULL DEFAULT 10000,\n run_a11y BOOLEAN NOT NULL DEFAULT true,\n run_tests BOOLEAN NOT NULL DEFAULT false,\n browser TEXT NOT NULL DEFAULT 'chromium',\n viewports TEXT,\n browsers TEXT,\n modes_allowlist TEXT,\n automigrate BOOLEAN NOT NULL DEFAULT false,\n ai_profile TEXT,\n review_enabled BOOLEAN NOT NULL DEFAULT true,\n review_approvals INTEGER NOT NULL DEFAULT 1,\n storybook_url_ttl_seconds INTEGER,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS builds (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n git_sha TEXT NOT NULL,\n git_branch TEXT NOT NULL,\n is_default BOOLEAN NOT NULL DEFAULT false,\n author_email TEXT,\n author_name TEXT,\n message TEXT,\n public BOOLEAN NOT NULL DEFAULT false,\n status TEXT NOT NULL DEFAULT 'pending',\n snapshot_count INTEGER NOT NULL DEFAULT 0,\n changed_count INTEGER NOT NULL DEFAULT 0,\n approved_count INTEGER NOT NULL DEFAULT 0,\n rejected_count INTEGER NOT NULL DEFAULT 0,\n inherited_count INTEGER NOT NULL DEFAULT 0,\n affected_only BOOLEAN NOT NULL DEFAULT true,\n baseline_sha TEXT,\n changed_files TEXT,\n affected_import_paths TEXT,\n test_results TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS builds_project_gitsha_idx ON builds (project_id, git_sha);\nCREATE INDEX IF NOT EXISTS builds_git_branch_idx ON builds (git_branch);\nCREATE TABLE IF NOT EXISTS capture_attempts (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_no INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'queued',\n error TEXT,\n req_id TEXT,\n story_count INTEGER NOT NULL DEFAULT 0,\n failed_count INTEGER NOT NULL DEFAULT 0,\n queued_at TIMESTAMPTZ NOT NULL,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS capture_attempts_build_no_idx ON capture_attempts (build_id, attempt_no);\nCREATE INDEX IF NOT EXISTS capture_attempts_build_id_idx ON capture_attempts (build_id);\nCREATE TABLE IF NOT EXISTS capture_shards (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n kind TEXT NOT NULL,\n ordinal INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n attempt_id TEXT,\n payload TEXT,\n result TEXT,\n error TEXT,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS capture_shards_build_kind_ordinal_idx ON capture_shards (build_id, kind, ordinal);\nCREATE INDEX IF NOT EXISTS capture_shards_build_id_idx ON capture_shards (build_id);\nCREATE TABLE IF NOT EXISTS capture_jobs (\n id TEXT PRIMARY KEY,\n entry TEXT NOT NULL,\n job_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n build_id TEXT,\n shard_id TEXT,\n attempt INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n status TEXT NOT NULL,\n visible_at TIMESTAMPTZ,\n owner TEXT,\n payload TEXT,\n cancel_requested_at TIMESTAMPTZ,\n error TEXT,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS capture_jobs_poll_idx ON capture_jobs (kind, visible_at, status);\nCREATE INDEX IF NOT EXISTS capture_jobs_job_id_idx ON capture_jobs (job_id);\nCREATE INDEX IF NOT EXISTS capture_jobs_build_id_idx ON capture_jobs (build_id);\nCREATE INDEX IF NOT EXISTS capture_jobs_entry_created_idx ON capture_jobs (entry, created_at);\nCREATE TABLE IF NOT EXISTS site_settings (\n id TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_by TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS build_components (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n import_path TEXT NOT NULL,\n title TEXT NOT NULL,\n story_count INTEGER NOT NULL DEFAULT 0,\n hash TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS build_components_build_id_idx ON build_components (build_id);\nCREATE INDEX IF NOT EXISTS build_components_project_import_path_idx ON build_components (project_id, import_path);\nCREATE TABLE IF NOT EXISTS capture_logs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_id TEXT NOT NULL REFERENCES capture_attempts(id) ON DELETE CASCADE,\n seq INTEGER NOT NULL,\n level TEXT NOT NULL DEFAULT 'info',\n message TEXT NOT NULL,\n fields TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS capture_logs_attempt_seq_idx ON capture_logs (attempt_id, seq);\nCREATE TABLE IF NOT EXISTS snapshots (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n story_name TEXT NOT NULL,\n story_title TEXT NOT NULL,\n story_import_path TEXT,\n design_url TEXT,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n viewport_width INTEGER NOT NULL DEFAULT 1280,\n viewport_height INTEGER NOT NULL DEFAULT 720,\n screenshot_path TEXT NOT NULL,\n diff_path TEXT,\n diff_pixels INTEGER,\n diff_ratio DOUBLE PRECISION,\n diff_passed BOOLEAN,\n status TEXT NOT NULL DEFAULT 'pending',\n reviewed_by TEXT,\n reviewed_at TIMESTAMPTZ,\n infra_hash TEXT,\n env_change TEXT,\n inherited BOOLEAN NOT NULL DEFAULT false,\n baseline_id TEXT,\n baseline_version TEXT,\n mode TEXT,\n browser TEXT NOT NULL DEFAULT 'chromium',\n duration_ms INTEGER,\n a11y_violations TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS snapshots_build_id_idx ON snapshots (build_id);\nCREATE INDEX IF NOT EXISTS snapshots_project_import_path_idx ON snapshots (project_id, story_import_path);\nCREATE TABLE IF NOT EXISTS baselines (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n branch TEXT NOT NULL,\n snapshot_id TEXT,\n screenshot_path TEXT NOT NULL,\n infra_hash TEXT,\n fingerprint TEXT,\n mode TEXT,\n browser TEXT NOT NULL DEFAULT 'chromium',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS baselines_project_story_idx ON baselines (project_id, story_id);\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n email TEXT NOT NULL UNIQUE,\n name TEXT NOT NULL,\n avatar_url TEXT,\n role TEXT NOT NULL DEFAULT 'member',\n last_login_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS user_connections (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n service TEXT NOT NULL,\n token_encrypted TEXT NOT NULL,\n refresh_token_encrypted TEXT,\n expires_at TIMESTAMPTZ,\n status TEXT NOT NULL DEFAULT 'ok',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS user_connections_user_service_idx ON user_connections (user_id, service);\nCREATE TABLE IF NOT EXISTS comments (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n snapshot_id TEXT REFERENCES snapshots(id) ON DELETE CASCADE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n body TEXT NOT NULL,\n parent_id TEXT,\n resolved BOOLEAN NOT NULL DEFAULT false,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n story_id TEXT\n);\nCREATE INDEX IF NOT EXISTS comments_build_id_idx ON comments (build_id);\nCREATE TABLE IF NOT EXISTS build_reviews (\n id TEXT PRIMARY KEY,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n verdict TEXT NOT NULL,\n body TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS build_reviews_build_id_idx ON build_reviews (build_id);\nCREATE TABLE IF NOT EXISTS label_types (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n key TEXT NOT NULL,\n name TEXT NOT NULL,\n link_template TEXT,\n color TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS label_types_project_key_idx ON label_types (project_id, key);\nCREATE TABLE IF NOT EXISTS build_labels (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n type_key TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS build_labels_build_type_value_idx ON build_labels (build_id, type_key, value);\nCREATE TABLE IF NOT EXISTS project_links (\n id TEXT PRIMARY KEY,\n downstream_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n upstream_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n package_name TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_links_downstream_package_idx ON project_links (downstream_id, package_name);\nCREATE TABLE IF NOT EXISTS design_links (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n import_path TEXT,\n label TEXT,\n url TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS design_links_project_id_idx ON design_links (project_id);\nCREATE TABLE IF NOT EXISTS design_credentials (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n token_encrypted TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'unknown',\n checked_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS design_credentials_project_provider_idx ON design_credentials (project_id, provider);\nCREATE TABLE IF NOT EXISTS design_nodes (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n viewer_id TEXT NOT NULL DEFAULT '',\n file_key TEXT NOT NULL,\n node_id TEXT NOT NULL DEFAULT '',\n name TEXT,\n version TEXT,\n last_modified TEXT,\n state TEXT NOT NULL DEFAULT 'ok',\n render_path TEXT,\n render_version TEXT,\n fetched_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS design_nodes_project_file_node_idx ON design_nodes (project_id, provider, viewer_id, file_key, node_id);\nCREATE TABLE IF NOT EXISTS build_package_usage (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n story_import_path TEXT NOT NULL,\n package_name TEXT NOT NULL,\n module_path TEXT NOT NULL,\n version TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS build_package_usage_build_id_idx ON build_package_usage (build_id);\nCREATE TABLE IF NOT EXISTS tokens (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n hash TEXT NOT NULL UNIQUE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n last_used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS webhooks (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n url TEXT NOT NULL,\n secret_encrypted TEXT NOT NULL,\n events TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS notification_channels (\n id TEXT PRIMARY KEY,\n project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n config TEXT NOT NULL,\n secret_encrypted TEXT,\n events TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n last_error TEXT,\n last_error_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS notification_channels_project_id_idx ON notification_channels (project_id);\nCREATE TABLE IF NOT EXISTS notification_subscriptions (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n events TEXT,\n via TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS notification_subscriptions_project_user_idx ON notification_subscriptions (project_id, user_id);\nCREATE TABLE IF NOT EXISTS insights (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT REFERENCES builds(id) ON DELETE CASCADE,\n kind TEXT NOT NULL,\n window_key TEXT,\n input_hash TEXT NOT NULL,\n status TEXT NOT NULL,\n profile TEXT NOT NULL,\n model TEXT NOT NULL,\n prompt_version TEXT NOT NULL,\n verdict TEXT,\n summary TEXT,\n result TEXT,\n error_code TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ\n);\nCREATE INDEX IF NOT EXISTS insights_project_build_idx ON insights (project_id, build_id);\nCREATE INDEX IF NOT EXISTS insights_created_at_idx ON insights (created_at);\nCREATE UNIQUE INDEX IF NOT EXISTS insights_triage_unique_idx ON insights (project_id, build_id, kind, input_hash);\nCREATE UNIQUE INDEX IF NOT EXISTS insights_health_unique_idx ON insights (project_id, kind, window_key);\nCREATE TABLE IF NOT EXISTS ai_usage (\n id TEXT PRIMARY KEY,\n insight_id TEXT,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n profile TEXT NOT NULL,\n task TEXT NOT NULL,\n model TEXT NOT NULL,\n input_tokens INTEGER NOT NULL DEFAULT 0,\n output_tokens INTEGER NOT NULL DEFAULT 0,\n estimated BOOLEAN NOT NULL DEFAULT false,\n images INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS ai_usage_created_at_idx ON ai_usage (created_at);\nCREATE INDEX IF NOT EXISTS ai_usage_project_created_idx ON ai_usage (project_id, created_at);\nCREATE TABLE IF NOT EXISTS ai_budget_alerts (\n id TEXT PRIMARY KEY,\n day TEXT NOT NULL,\n threshold INTEGER NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS user_invite_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n token_hash TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS project_members (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n role TEXT NOT NULL DEFAULT 'viewer',\n source TEXT NOT NULL DEFAULT 'manual',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_members_project_user_idx ON project_members (project_id, user_id);\nCREATE TABLE IF NOT EXISTS project_group_mappings (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n group_name TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'viewer',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_group_mappings_project_group_idx ON project_group_mappings (project_id, group_name);\nCREATE TABLE IF NOT EXISTS content_refs (\n hash TEXT PRIMARY KEY,\n ref_count INTEGER NOT NULL DEFAULT 1,\n last_seen_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS \"user\" (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n email TEXT NOT NULL UNIQUE,\n email_verified BOOLEAN NOT NULL DEFAULT false,\n image TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS session (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n token TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n ip_address TEXT,\n user_agent TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS session_token_idx ON session (token);\nCREATE INDEX IF NOT EXISTS session_user_id_idx ON session (user_id);\nCREATE TABLE IF NOT EXISTS account (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n account_id TEXT NOT NULL,\n provider_id TEXT NOT NULL,\n access_token TEXT,\n refresh_token TEXT,\n id_token TEXT,\n access_token_expires_at TIMESTAMPTZ,\n refresh_token_expires_at TIMESTAMPTZ,\n scope TEXT,\n expires_at TIMESTAMPTZ,\n password TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS account_user_id_idx ON account (user_id);\nCREATE TABLE IF NOT EXISTS verification (\n id TEXT PRIMARY KEY,\n identifier TEXT NOT NULL,\n value TEXT NOT NULL,\n expires_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS verification_identifier_idx ON verification (identifier);\nCREATE TABLE IF NOT EXISTS passkey (\n id TEXT PRIMARY KEY,\n name TEXT,\n public_key TEXT NOT NULL,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n credential_id TEXT NOT NULL,\n counter INTEGER NOT NULL,\n device_type TEXT NOT NULL,\n backed_up BOOLEAN NOT NULL DEFAULT false,\n transports TEXT,\n aaguid TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ\n);\nCREATE INDEX IF NOT EXISTS passkey_user_id_idx ON passkey (user_id);\nCREATE INDEX IF NOT EXISTS passkey_credential_id_idx ON passkey (credential_id);\nCREATE TABLE IF NOT EXISTS \"ssoProvider\" (\n id TEXT PRIMARY KEY,\n issuer TEXT NOT NULL,\n oidc_config TEXT,\n saml_config TEXT,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n provider_id TEXT NOT NULL UNIQUE,\n organization_id TEXT,\n domain TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS ssoprovider_domain_idx ON \"ssoProvider\" (domain);\n";
6
6
  //#endregion
7
7
  export { DDL };
8
8
  //# sourceMappingURL=ddl.d.mts.map
package/dist/ddl.mjs CHANGED
@@ -16,19 +16,17 @@ CREATE TABLE IF NOT EXISTS projects (
16
16
  storybook_meta TEXT,
17
17
  execute_play BOOLEAN NOT NULL DEFAULT false,
18
18
  play_timeout_ms INTEGER NOT NULL DEFAULT 10000,
19
- run_a11y BOOLEAN NOT NULL DEFAULT false,
19
+ run_a11y BOOLEAN NOT NULL DEFAULT true,
20
+ run_tests BOOLEAN NOT NULL DEFAULT false,
20
21
  browser TEXT NOT NULL DEFAULT 'chromium',
21
22
  viewports TEXT,
23
+ browsers TEXT,
24
+ modes_allowlist TEXT,
22
25
  automigrate BOOLEAN NOT NULL DEFAULT false,
23
- created_at TIMESTAMPTZ NOT NULL,
24
- updated_at TIMESTAMPTZ NOT NULL
25
- );
26
- CREATE TABLE IF NOT EXISTS project_status_configs (
27
- id TEXT PRIMARY KEY,
28
- project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
29
- provider TEXT NOT NULL,
30
- config TEXT NOT NULL,
31
- token_encrypted TEXT NOT NULL,
26
+ ai_profile TEXT,
27
+ review_enabled BOOLEAN NOT NULL DEFAULT true,
28
+ review_approvals INTEGER NOT NULL DEFAULT 1,
29
+ storybook_url_ttl_seconds INTEGER,
32
30
  created_at TIMESTAMPTZ NOT NULL,
33
31
  updated_at TIMESTAMPTZ NOT NULL
34
32
  );
@@ -47,10 +45,12 @@ CREATE TABLE IF NOT EXISTS builds (
47
45
  changed_count INTEGER NOT NULL DEFAULT 0,
48
46
  approved_count INTEGER NOT NULL DEFAULT 0,
49
47
  rejected_count INTEGER NOT NULL DEFAULT 0,
48
+ inherited_count INTEGER NOT NULL DEFAULT 0,
50
49
  affected_only BOOLEAN NOT NULL DEFAULT true,
51
50
  baseline_sha TEXT,
52
51
  changed_files TEXT,
53
52
  affected_import_paths TEXT,
53
+ test_results TEXT,
54
54
  created_at TIMESTAMPTZ NOT NULL,
55
55
  updated_at TIMESTAMPTZ NOT NULL
56
56
  );
@@ -74,6 +74,67 @@ CREATE TABLE IF NOT EXISTS capture_attempts (
74
74
  );
75
75
  CREATE UNIQUE INDEX IF NOT EXISTS capture_attempts_build_no_idx ON capture_attempts (build_id, attempt_no);
76
76
  CREATE INDEX IF NOT EXISTS capture_attempts_build_id_idx ON capture_attempts (build_id);
77
+ CREATE TABLE IF NOT EXISTS capture_shards (
78
+ id TEXT PRIMARY KEY,
79
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
80
+ build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,
81
+ kind TEXT NOT NULL,
82
+ ordinal INTEGER NOT NULL,
83
+ status TEXT NOT NULL DEFAULT 'pending',
84
+ attempt_id TEXT,
85
+ payload TEXT,
86
+ result TEXT,
87
+ error TEXT,
88
+ started_at TIMESTAMPTZ,
89
+ finished_at TIMESTAMPTZ,
90
+ created_at TIMESTAMPTZ NOT NULL,
91
+ updated_at TIMESTAMPTZ NOT NULL
92
+ );
93
+ CREATE UNIQUE INDEX IF NOT EXISTS capture_shards_build_kind_ordinal_idx ON capture_shards (build_id, kind, ordinal);
94
+ CREATE INDEX IF NOT EXISTS capture_shards_build_id_idx ON capture_shards (build_id);
95
+ CREATE TABLE IF NOT EXISTS capture_jobs (
96
+ id TEXT PRIMARY KEY,
97
+ entry TEXT NOT NULL,
98
+ job_id TEXT NOT NULL,
99
+ kind TEXT NOT NULL,
100
+ build_id TEXT,
101
+ shard_id TEXT,
102
+ attempt INTEGER NOT NULL DEFAULT 0,
103
+ max_attempts INTEGER NOT NULL DEFAULT 3,
104
+ status TEXT NOT NULL,
105
+ visible_at TIMESTAMPTZ,
106
+ owner TEXT,
107
+ payload TEXT,
108
+ cancel_requested_at TIMESTAMPTZ,
109
+ error TEXT,
110
+ started_at TIMESTAMPTZ,
111
+ finished_at TIMESTAMPTZ,
112
+ created_at TIMESTAMPTZ NOT NULL,
113
+ updated_at TIMESTAMPTZ NOT NULL
114
+ );
115
+ CREATE INDEX IF NOT EXISTS capture_jobs_poll_idx ON capture_jobs (kind, visible_at, status);
116
+ CREATE INDEX IF NOT EXISTS capture_jobs_job_id_idx ON capture_jobs (job_id);
117
+ CREATE INDEX IF NOT EXISTS capture_jobs_build_id_idx ON capture_jobs (build_id);
118
+ CREATE INDEX IF NOT EXISTS capture_jobs_entry_created_idx ON capture_jobs (entry, created_at);
119
+ CREATE TABLE IF NOT EXISTS site_settings (
120
+ id TEXT PRIMARY KEY,
121
+ value TEXT NOT NULL,
122
+ updated_by TEXT,
123
+ created_at TIMESTAMPTZ NOT NULL,
124
+ updated_at TIMESTAMPTZ NOT NULL
125
+ );
126
+ CREATE TABLE IF NOT EXISTS build_components (
127
+ id TEXT PRIMARY KEY,
128
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
129
+ build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,
130
+ import_path TEXT NOT NULL,
131
+ title TEXT NOT NULL,
132
+ story_count INTEGER NOT NULL DEFAULT 0,
133
+ hash TEXT NOT NULL,
134
+ created_at TIMESTAMPTZ NOT NULL
135
+ );
136
+ CREATE INDEX IF NOT EXISTS build_components_build_id_idx ON build_components (build_id);
137
+ CREATE INDEX IF NOT EXISTS build_components_project_import_path_idx ON build_components (project_id, import_path);
77
138
  CREATE TABLE IF NOT EXISTS capture_logs (
78
139
  id TEXT PRIMARY KEY,
79
140
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
@@ -94,6 +155,7 @@ CREATE TABLE IF NOT EXISTS snapshots (
94
155
  story_name TEXT NOT NULL,
95
156
  story_title TEXT NOT NULL,
96
157
  story_import_path TEXT,
158
+ design_url TEXT,
97
159
  viewport_name TEXT NOT NULL DEFAULT 'desktop',
98
160
  viewport_width INTEGER NOT NULL DEFAULT 1280,
99
161
  viewport_height INTEGER NOT NULL DEFAULT 720,
@@ -106,14 +168,19 @@ CREATE TABLE IF NOT EXISTS snapshots (
106
168
  reviewed_by TEXT,
107
169
  reviewed_at TIMESTAMPTZ,
108
170
  infra_hash TEXT,
171
+ env_change TEXT,
109
172
  inherited BOOLEAN NOT NULL DEFAULT false,
110
173
  baseline_id TEXT,
111
174
  baseline_version TEXT,
175
+ mode TEXT,
176
+ browser TEXT NOT NULL DEFAULT 'chromium',
177
+ duration_ms INTEGER,
178
+ a11y_violations TEXT,
112
179
  created_at TIMESTAMPTZ NOT NULL,
113
180
  updated_at TIMESTAMPTZ NOT NULL
114
181
  );
115
- CREATE UNIQUE INDEX IF NOT EXISTS snapshots_build_story_viewport_idx ON snapshots (build_id, story_id, viewport_name);
116
182
  CREATE INDEX IF NOT EXISTS snapshots_build_id_idx ON snapshots (build_id);
183
+ CREATE INDEX IF NOT EXISTS snapshots_project_import_path_idx ON snapshots (project_id, story_import_path);
117
184
  CREATE TABLE IF NOT EXISTS baselines (
118
185
  id TEXT PRIMARY KEY,
119
186
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
@@ -123,10 +190,12 @@ CREATE TABLE IF NOT EXISTS baselines (
123
190
  snapshot_id TEXT,
124
191
  screenshot_path TEXT NOT NULL,
125
192
  infra_hash TEXT,
193
+ fingerprint TEXT,
194
+ mode TEXT,
195
+ browser TEXT NOT NULL DEFAULT 'chromium',
126
196
  created_at TIMESTAMPTZ NOT NULL,
127
197
  updated_at TIMESTAMPTZ NOT NULL
128
198
  );
129
- CREATE UNIQUE INDEX IF NOT EXISTS baselines_project_story_viewport_branch_idx ON baselines (project_id, story_id, viewport_name, branch);
130
199
  CREATE INDEX IF NOT EXISTS baselines_project_story_idx ON baselines (project_id, story_id);
131
200
  CREATE TABLE IF NOT EXISTS users (
132
201
  id TEXT PRIMARY KEY,
@@ -137,6 +206,18 @@ CREATE TABLE IF NOT EXISTS users (
137
206
  last_login_at TIMESTAMPTZ,
138
207
  created_at TIMESTAMPTZ NOT NULL
139
208
  );
209
+ CREATE TABLE IF NOT EXISTS user_connections (
210
+ id TEXT PRIMARY KEY,
211
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
212
+ service TEXT NOT NULL,
213
+ token_encrypted TEXT NOT NULL,
214
+ refresh_token_encrypted TEXT,
215
+ expires_at TIMESTAMPTZ,
216
+ status TEXT NOT NULL DEFAULT 'ok',
217
+ created_at TIMESTAMPTZ NOT NULL,
218
+ updated_at TIMESTAMPTZ NOT NULL
219
+ );
220
+ CREATE UNIQUE INDEX IF NOT EXISTS user_connections_user_service_idx ON user_connections (user_id, service);
140
221
  CREATE TABLE IF NOT EXISTS comments (
141
222
  id TEXT PRIMARY KEY,
142
223
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
@@ -147,9 +228,19 @@ CREATE TABLE IF NOT EXISTS comments (
147
228
  parent_id TEXT,
148
229
  resolved BOOLEAN NOT NULL DEFAULT false,
149
230
  created_at TIMESTAMPTZ NOT NULL,
150
- updated_at TIMESTAMPTZ NOT NULL
231
+ updated_at TIMESTAMPTZ NOT NULL,
232
+ story_id TEXT
151
233
  );
152
234
  CREATE INDEX IF NOT EXISTS comments_build_id_idx ON comments (build_id);
235
+ CREATE TABLE IF NOT EXISTS build_reviews (
236
+ id TEXT PRIMARY KEY,
237
+ build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,
238
+ user_id TEXT REFERENCES users(id) ON DELETE CASCADE,
239
+ verdict TEXT NOT NULL,
240
+ body TEXT,
241
+ created_at TIMESTAMPTZ NOT NULL
242
+ );
243
+ CREATE INDEX IF NOT EXISTS build_reviews_build_id_idx ON build_reviews (build_id);
153
244
  CREATE TABLE IF NOT EXISTS label_types (
154
245
  id TEXT PRIMARY KEY,
155
246
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
@@ -169,6 +260,64 @@ CREATE TABLE IF NOT EXISTS build_labels (
169
260
  created_at TIMESTAMPTZ NOT NULL
170
261
  );
171
262
  CREATE UNIQUE INDEX IF NOT EXISTS build_labels_build_type_value_idx ON build_labels (build_id, type_key, value);
263
+ CREATE TABLE IF NOT EXISTS project_links (
264
+ id TEXT PRIMARY KEY,
265
+ downstream_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
266
+ upstream_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
267
+ package_name TEXT NOT NULL,
268
+ created_at TIMESTAMPTZ NOT NULL
269
+ );
270
+ CREATE UNIQUE INDEX IF NOT EXISTS project_links_downstream_package_idx ON project_links (downstream_id, package_name);
271
+ CREATE TABLE IF NOT EXISTS design_links (
272
+ id TEXT PRIMARY KEY,
273
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
274
+ import_path TEXT,
275
+ label TEXT,
276
+ url TEXT NOT NULL,
277
+ created_at TIMESTAMPTZ NOT NULL,
278
+ updated_at TIMESTAMPTZ NOT NULL
279
+ );
280
+ CREATE INDEX IF NOT EXISTS design_links_project_id_idx ON design_links (project_id);
281
+ CREATE TABLE IF NOT EXISTS design_credentials (
282
+ id TEXT PRIMARY KEY,
283
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
284
+ provider TEXT NOT NULL,
285
+ token_encrypted TEXT NOT NULL,
286
+ status TEXT NOT NULL DEFAULT 'unknown',
287
+ checked_at TIMESTAMPTZ,
288
+ created_at TIMESTAMPTZ NOT NULL,
289
+ updated_at TIMESTAMPTZ NOT NULL
290
+ );
291
+ CREATE UNIQUE INDEX IF NOT EXISTS design_credentials_project_provider_idx ON design_credentials (project_id, provider);
292
+ CREATE TABLE IF NOT EXISTS design_nodes (
293
+ id TEXT PRIMARY KEY,
294
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
295
+ provider TEXT NOT NULL,
296
+ viewer_id TEXT NOT NULL DEFAULT '',
297
+ file_key TEXT NOT NULL,
298
+ node_id TEXT NOT NULL DEFAULT '',
299
+ name TEXT,
300
+ version TEXT,
301
+ last_modified TEXT,
302
+ state TEXT NOT NULL DEFAULT 'ok',
303
+ render_path TEXT,
304
+ render_version TEXT,
305
+ fetched_at TIMESTAMPTZ NOT NULL,
306
+ created_at TIMESTAMPTZ NOT NULL,
307
+ updated_at TIMESTAMPTZ NOT NULL
308
+ );
309
+ CREATE UNIQUE INDEX IF NOT EXISTS design_nodes_project_file_node_idx ON design_nodes (project_id, provider, viewer_id, file_key, node_id);
310
+ CREATE TABLE IF NOT EXISTS build_package_usage (
311
+ id TEXT PRIMARY KEY,
312
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
313
+ build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,
314
+ story_import_path TEXT NOT NULL,
315
+ package_name TEXT NOT NULL,
316
+ module_path TEXT NOT NULL,
317
+ version TEXT,
318
+ created_at TIMESTAMPTZ NOT NULL
319
+ );
320
+ CREATE INDEX IF NOT EXISTS build_package_usage_build_id_idx ON build_package_usage (build_id);
172
321
  CREATE TABLE IF NOT EXISTS tokens (
173
322
  id TEXT PRIMARY KEY,
174
323
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
@@ -195,6 +344,8 @@ CREATE TABLE IF NOT EXISTS notification_channels (
195
344
  secret_encrypted TEXT,
196
345
  events TEXT,
197
346
  enabled BOOLEAN NOT NULL DEFAULT TRUE,
347
+ last_error TEXT,
348
+ last_error_at TIMESTAMPTZ,
198
349
  created_at TIMESTAMPTZ NOT NULL,
199
350
  updated_at TIMESTAMPTZ NOT NULL
200
351
  );
@@ -209,6 +360,51 @@ CREATE TABLE IF NOT EXISTS notification_subscriptions (
209
360
  created_at TIMESTAMPTZ NOT NULL
210
361
  );
211
362
  CREATE UNIQUE INDEX IF NOT EXISTS notification_subscriptions_project_user_idx ON notification_subscriptions (project_id, user_id);
363
+ CREATE TABLE IF NOT EXISTS insights (
364
+ id TEXT PRIMARY KEY,
365
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
366
+ build_id TEXT REFERENCES builds(id) ON DELETE CASCADE,
367
+ kind TEXT NOT NULL,
368
+ window_key TEXT,
369
+ input_hash TEXT NOT NULL,
370
+ status TEXT NOT NULL,
371
+ profile TEXT NOT NULL,
372
+ model TEXT NOT NULL,
373
+ prompt_version TEXT NOT NULL,
374
+ verdict TEXT,
375
+ summary TEXT,
376
+ result TEXT,
377
+ error_code TEXT,
378
+ created_at TIMESTAMPTZ NOT NULL,
379
+ started_at TIMESTAMPTZ,
380
+ finished_at TIMESTAMPTZ
381
+ );
382
+ CREATE INDEX IF NOT EXISTS insights_project_build_idx ON insights (project_id, build_id);
383
+ CREATE INDEX IF NOT EXISTS insights_created_at_idx ON insights (created_at);
384
+ CREATE UNIQUE INDEX IF NOT EXISTS insights_triage_unique_idx ON insights (project_id, build_id, kind, input_hash);
385
+ CREATE UNIQUE INDEX IF NOT EXISTS insights_health_unique_idx ON insights (project_id, kind, window_key);
386
+ CREATE TABLE IF NOT EXISTS ai_usage (
387
+ id TEXT PRIMARY KEY,
388
+ insight_id TEXT,
389
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
390
+ profile TEXT NOT NULL,
391
+ task TEXT NOT NULL,
392
+ model TEXT NOT NULL,
393
+ input_tokens INTEGER NOT NULL DEFAULT 0,
394
+ output_tokens INTEGER NOT NULL DEFAULT 0,
395
+ estimated BOOLEAN NOT NULL DEFAULT false,
396
+ images INTEGER NOT NULL DEFAULT 0,
397
+ status TEXT NOT NULL,
398
+ created_at TIMESTAMPTZ NOT NULL
399
+ );
400
+ CREATE INDEX IF NOT EXISTS ai_usage_created_at_idx ON ai_usage (created_at);
401
+ CREATE INDEX IF NOT EXISTS ai_usage_project_created_idx ON ai_usage (project_id, created_at);
402
+ CREATE TABLE IF NOT EXISTS ai_budget_alerts (
403
+ id TEXT PRIMARY KEY,
404
+ day TEXT NOT NULL,
405
+ threshold INTEGER NOT NULL,
406
+ created_at TIMESTAMPTZ NOT NULL
407
+ );
212
408
  CREATE TABLE IF NOT EXISTS user_invite_tokens (
213
409
  id TEXT PRIMARY KEY,
214
410
  user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
package/dist/ddl.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ddl.mjs","names":[],"sources":["../src/ddl.ts"],"sourcesContent":["/** Canonical Postgres DDL for all StoryShelf tables and indexes. */\nexport const DDL = `\nCREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n slug TEXT NOT NULL UNIQUE,\n git_repository TEXT,\n git_default_branch TEXT NOT NULL DEFAULT 'main',\n pixel_threshold DOUBLE PRECISION NOT NULL DEFAULT 0.1,\n max_diff_ratio DOUBLE PRECISION NOT NULL DEFAULT 0.01,\n public_branch_regex TEXT,\n storybook_meta TEXT,\n execute_play BOOLEAN NOT NULL DEFAULT false,\n play_timeout_ms INTEGER NOT NULL DEFAULT 10000,\n run_a11y BOOLEAN NOT NULL DEFAULT false,\n browser TEXT NOT NULL DEFAULT 'chromium',\n viewports TEXT,\n automigrate BOOLEAN NOT NULL DEFAULT false,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS project_status_configs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n config TEXT NOT NULL,\n token_encrypted TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS builds (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n git_sha TEXT NOT NULL,\n git_branch TEXT NOT NULL,\n is_default BOOLEAN NOT NULL DEFAULT false,\n author_email TEXT,\n author_name TEXT,\n message TEXT,\n public BOOLEAN NOT NULL DEFAULT false,\n status TEXT NOT NULL DEFAULT 'pending',\n snapshot_count INTEGER NOT NULL DEFAULT 0,\n changed_count INTEGER NOT NULL DEFAULT 0,\n approved_count INTEGER NOT NULL DEFAULT 0,\n rejected_count INTEGER NOT NULL DEFAULT 0,\n affected_only BOOLEAN NOT NULL DEFAULT true,\n baseline_sha TEXT,\n changed_files TEXT,\n affected_import_paths TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS builds_project_gitsha_idx ON builds (project_id, git_sha);\nCREATE INDEX IF NOT EXISTS builds_git_branch_idx ON builds (git_branch);\nCREATE TABLE IF NOT EXISTS capture_attempts (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_no INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'queued',\n error TEXT,\n req_id TEXT,\n story_count INTEGER NOT NULL DEFAULT 0,\n failed_count INTEGER NOT NULL DEFAULT 0,\n queued_at TIMESTAMPTZ NOT NULL,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS capture_attempts_build_no_idx ON capture_attempts (build_id, attempt_no);\nCREATE INDEX IF NOT EXISTS capture_attempts_build_id_idx ON capture_attempts (build_id);\nCREATE TABLE IF NOT EXISTS capture_logs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_id TEXT NOT NULL REFERENCES capture_attempts(id) ON DELETE CASCADE,\n seq INTEGER NOT NULL,\n level TEXT NOT NULL DEFAULT 'info',\n message TEXT NOT NULL,\n fields TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS capture_logs_attempt_seq_idx ON capture_logs (attempt_id, seq);\nCREATE TABLE IF NOT EXISTS snapshots (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n story_name TEXT NOT NULL,\n story_title TEXT NOT NULL,\n story_import_path TEXT,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n viewport_width INTEGER NOT NULL DEFAULT 1280,\n viewport_height INTEGER NOT NULL DEFAULT 720,\n screenshot_path TEXT NOT NULL,\n diff_path TEXT,\n diff_pixels INTEGER,\n diff_ratio DOUBLE PRECISION,\n diff_passed BOOLEAN,\n status TEXT NOT NULL DEFAULT 'pending',\n reviewed_by TEXT,\n reviewed_at TIMESTAMPTZ,\n infra_hash TEXT,\n inherited BOOLEAN NOT NULL DEFAULT false,\n baseline_id TEXT,\n baseline_version TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS snapshots_build_story_viewport_idx ON snapshots (build_id, story_id, viewport_name);\nCREATE INDEX IF NOT EXISTS snapshots_build_id_idx ON snapshots (build_id);\nCREATE TABLE IF NOT EXISTS baselines (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n branch TEXT NOT NULL,\n snapshot_id TEXT,\n screenshot_path TEXT NOT NULL,\n infra_hash TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS baselines_project_story_viewport_branch_idx ON baselines (project_id, story_id, viewport_name, branch);\nCREATE INDEX IF NOT EXISTS baselines_project_story_idx ON baselines (project_id, story_id);\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n email TEXT NOT NULL UNIQUE,\n name TEXT NOT NULL,\n avatar_url TEXT,\n role TEXT NOT NULL DEFAULT 'member',\n last_login_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS comments (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n snapshot_id TEXT REFERENCES snapshots(id) ON DELETE CASCADE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n body TEXT NOT NULL,\n parent_id TEXT,\n resolved BOOLEAN NOT NULL DEFAULT false,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS comments_build_id_idx ON comments (build_id);\nCREATE TABLE IF NOT EXISTS label_types (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n key TEXT NOT NULL,\n name TEXT NOT NULL,\n link_template TEXT,\n color TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS label_types_project_key_idx ON label_types (project_id, key);\nCREATE TABLE IF NOT EXISTS build_labels (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n type_key TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS build_labels_build_type_value_idx ON build_labels (build_id, type_key, value);\nCREATE TABLE IF NOT EXISTS tokens (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n hash TEXT NOT NULL UNIQUE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n last_used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS webhooks (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n url TEXT NOT NULL,\n secret_encrypted TEXT NOT NULL,\n events TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS notification_channels (\n id TEXT PRIMARY KEY,\n project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n config TEXT NOT NULL,\n secret_encrypted TEXT,\n events TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS notification_channels_project_id_idx ON notification_channels (project_id);\nCREATE TABLE IF NOT EXISTS notification_subscriptions (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n events TEXT,\n via TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS notification_subscriptions_project_user_idx ON notification_subscriptions (project_id, user_id);\nCREATE TABLE IF NOT EXISTS user_invite_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n token_hash TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS project_members (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n role TEXT NOT NULL DEFAULT 'viewer',\n source TEXT NOT NULL DEFAULT 'manual',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_members_project_user_idx ON project_members (project_id, user_id);\nCREATE TABLE IF NOT EXISTS project_group_mappings (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n group_name TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'viewer',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_group_mappings_project_group_idx ON project_group_mappings (project_id, group_name);\nCREATE TABLE IF NOT EXISTS content_refs (\n hash TEXT PRIMARY KEY,\n ref_count INTEGER NOT NULL DEFAULT 1,\n last_seen_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS \"user\" (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n email TEXT NOT NULL UNIQUE,\n email_verified BOOLEAN NOT NULL DEFAULT false,\n image TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS session (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n token TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n ip_address TEXT,\n user_agent TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS session_token_idx ON session (token);\nCREATE INDEX IF NOT EXISTS session_user_id_idx ON session (user_id);\nCREATE TABLE IF NOT EXISTS account (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n account_id TEXT NOT NULL,\n provider_id TEXT NOT NULL,\n access_token TEXT,\n refresh_token TEXT,\n id_token TEXT,\n access_token_expires_at TIMESTAMPTZ,\n refresh_token_expires_at TIMESTAMPTZ,\n scope TEXT,\n expires_at TIMESTAMPTZ,\n password TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS account_user_id_idx ON account (user_id);\nCREATE TABLE IF NOT EXISTS verification (\n id TEXT PRIMARY KEY,\n identifier TEXT NOT NULL,\n value TEXT NOT NULL,\n expires_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS verification_identifier_idx ON verification (identifier);\nCREATE TABLE IF NOT EXISTS passkey (\n id TEXT PRIMARY KEY,\n name TEXT,\n public_key TEXT NOT NULL,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n credential_id TEXT NOT NULL,\n counter INTEGER NOT NULL,\n device_type TEXT NOT NULL,\n backed_up BOOLEAN NOT NULL DEFAULT false,\n transports TEXT,\n aaguid TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ\n);\nCREATE INDEX IF NOT EXISTS passkey_user_id_idx ON passkey (user_id);\nCREATE INDEX IF NOT EXISTS passkey_credential_id_idx ON passkey (credential_id);\nCREATE TABLE IF NOT EXISTS \"ssoProvider\" (\n id TEXT PRIMARY KEY,\n issuer TEXT NOT NULL,\n oidc_config TEXT,\n saml_config TEXT,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n provider_id TEXT NOT NULL UNIQUE,\n organization_id TEXT,\n domain TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS ssoprovider_domain_idx ON \"ssoProvider\" (domain);\n`;\n"],"mappings":";;;;;AACA,MAAa,MAAM"}
1
+ {"version":3,"file":"ddl.mjs","names":[],"sources":["../src/ddl.ts"],"sourcesContent":["/** Canonical Postgres DDL for all StoryShelf tables and indexes. */\nexport const DDL = `\nCREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n slug TEXT NOT NULL UNIQUE,\n git_repository TEXT,\n git_default_branch TEXT NOT NULL DEFAULT 'main',\n pixel_threshold DOUBLE PRECISION NOT NULL DEFAULT 0.1,\n max_diff_ratio DOUBLE PRECISION NOT NULL DEFAULT 0.01,\n public_branch_regex TEXT,\n storybook_meta TEXT,\n execute_play BOOLEAN NOT NULL DEFAULT false,\n play_timeout_ms INTEGER NOT NULL DEFAULT 10000,\n run_a11y BOOLEAN NOT NULL DEFAULT true,\n run_tests BOOLEAN NOT NULL DEFAULT false,\n browser TEXT NOT NULL DEFAULT 'chromium',\n viewports TEXT,\n browsers TEXT,\n modes_allowlist TEXT,\n automigrate BOOLEAN NOT NULL DEFAULT false,\n ai_profile TEXT,\n review_enabled BOOLEAN NOT NULL DEFAULT true,\n review_approvals INTEGER NOT NULL DEFAULT 1,\n storybook_url_ttl_seconds INTEGER,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS builds (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n git_sha TEXT NOT NULL,\n git_branch TEXT NOT NULL,\n is_default BOOLEAN NOT NULL DEFAULT false,\n author_email TEXT,\n author_name TEXT,\n message TEXT,\n public BOOLEAN NOT NULL DEFAULT false,\n status TEXT NOT NULL DEFAULT 'pending',\n snapshot_count INTEGER NOT NULL DEFAULT 0,\n changed_count INTEGER NOT NULL DEFAULT 0,\n approved_count INTEGER NOT NULL DEFAULT 0,\n rejected_count INTEGER NOT NULL DEFAULT 0,\n inherited_count INTEGER NOT NULL DEFAULT 0,\n affected_only BOOLEAN NOT NULL DEFAULT true,\n baseline_sha TEXT,\n changed_files TEXT,\n affected_import_paths TEXT,\n test_results TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS builds_project_gitsha_idx ON builds (project_id, git_sha);\nCREATE INDEX IF NOT EXISTS builds_git_branch_idx ON builds (git_branch);\nCREATE TABLE IF NOT EXISTS capture_attempts (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_no INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'queued',\n error TEXT,\n req_id TEXT,\n story_count INTEGER NOT NULL DEFAULT 0,\n failed_count INTEGER NOT NULL DEFAULT 0,\n queued_at TIMESTAMPTZ NOT NULL,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS capture_attempts_build_no_idx ON capture_attempts (build_id, attempt_no);\nCREATE INDEX IF NOT EXISTS capture_attempts_build_id_idx ON capture_attempts (build_id);\nCREATE TABLE IF NOT EXISTS capture_shards (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n kind TEXT NOT NULL,\n ordinal INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n attempt_id TEXT,\n payload TEXT,\n result TEXT,\n error TEXT,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS capture_shards_build_kind_ordinal_idx ON capture_shards (build_id, kind, ordinal);\nCREATE INDEX IF NOT EXISTS capture_shards_build_id_idx ON capture_shards (build_id);\nCREATE TABLE IF NOT EXISTS capture_jobs (\n id TEXT PRIMARY KEY,\n entry TEXT NOT NULL,\n job_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n build_id TEXT,\n shard_id TEXT,\n attempt INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n status TEXT NOT NULL,\n visible_at TIMESTAMPTZ,\n owner TEXT,\n payload TEXT,\n cancel_requested_at TIMESTAMPTZ,\n error TEXT,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS capture_jobs_poll_idx ON capture_jobs (kind, visible_at, status);\nCREATE INDEX IF NOT EXISTS capture_jobs_job_id_idx ON capture_jobs (job_id);\nCREATE INDEX IF NOT EXISTS capture_jobs_build_id_idx ON capture_jobs (build_id);\nCREATE INDEX IF NOT EXISTS capture_jobs_entry_created_idx ON capture_jobs (entry, created_at);\nCREATE TABLE IF NOT EXISTS site_settings (\n id TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_by TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS build_components (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n import_path TEXT NOT NULL,\n title TEXT NOT NULL,\n story_count INTEGER NOT NULL DEFAULT 0,\n hash TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS build_components_build_id_idx ON build_components (build_id);\nCREATE INDEX IF NOT EXISTS build_components_project_import_path_idx ON build_components (project_id, import_path);\nCREATE TABLE IF NOT EXISTS capture_logs (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n attempt_id TEXT NOT NULL REFERENCES capture_attempts(id) ON DELETE CASCADE,\n seq INTEGER NOT NULL,\n level TEXT NOT NULL DEFAULT 'info',\n message TEXT NOT NULL,\n fields TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS capture_logs_attempt_seq_idx ON capture_logs (attempt_id, seq);\nCREATE TABLE IF NOT EXISTS snapshots (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n story_name TEXT NOT NULL,\n story_title TEXT NOT NULL,\n story_import_path TEXT,\n design_url TEXT,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n viewport_width INTEGER NOT NULL DEFAULT 1280,\n viewport_height INTEGER NOT NULL DEFAULT 720,\n screenshot_path TEXT NOT NULL,\n diff_path TEXT,\n diff_pixels INTEGER,\n diff_ratio DOUBLE PRECISION,\n diff_passed BOOLEAN,\n status TEXT NOT NULL DEFAULT 'pending',\n reviewed_by TEXT,\n reviewed_at TIMESTAMPTZ,\n infra_hash TEXT,\n env_change TEXT,\n inherited BOOLEAN NOT NULL DEFAULT false,\n baseline_id TEXT,\n baseline_version TEXT,\n mode TEXT,\n browser TEXT NOT NULL DEFAULT 'chromium',\n duration_ms INTEGER,\n a11y_violations TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS snapshots_build_id_idx ON snapshots (build_id);\nCREATE INDEX IF NOT EXISTS snapshots_project_import_path_idx ON snapshots (project_id, story_import_path);\nCREATE TABLE IF NOT EXISTS baselines (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n story_id TEXT NOT NULL,\n viewport_name TEXT NOT NULL DEFAULT 'desktop',\n branch TEXT NOT NULL,\n snapshot_id TEXT,\n screenshot_path TEXT NOT NULL,\n infra_hash TEXT,\n fingerprint TEXT,\n mode TEXT,\n browser TEXT NOT NULL DEFAULT 'chromium',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS baselines_project_story_idx ON baselines (project_id, story_id);\nCREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n email TEXT NOT NULL UNIQUE,\n name TEXT NOT NULL,\n avatar_url TEXT,\n role TEXT NOT NULL DEFAULT 'member',\n last_login_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS user_connections (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n service TEXT NOT NULL,\n token_encrypted TEXT NOT NULL,\n refresh_token_encrypted TEXT,\n expires_at TIMESTAMPTZ,\n status TEXT NOT NULL DEFAULT 'ok',\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS user_connections_user_service_idx ON user_connections (user_id, service);\nCREATE TABLE IF NOT EXISTS comments (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n snapshot_id TEXT REFERENCES snapshots(id) ON DELETE CASCADE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n body TEXT NOT NULL,\n parent_id TEXT,\n resolved BOOLEAN NOT NULL DEFAULT false,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL,\n story_id TEXT\n);\nCREATE INDEX IF NOT EXISTS comments_build_id_idx ON comments (build_id);\nCREATE TABLE IF NOT EXISTS build_reviews (\n id TEXT PRIMARY KEY,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n verdict TEXT NOT NULL,\n body TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS build_reviews_build_id_idx ON build_reviews (build_id);\nCREATE TABLE IF NOT EXISTS label_types (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n key TEXT NOT NULL,\n name TEXT NOT NULL,\n link_template TEXT,\n color TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS label_types_project_key_idx ON label_types (project_id, key);\nCREATE TABLE IF NOT EXISTS build_labels (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n type_key TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS build_labels_build_type_value_idx ON build_labels (build_id, type_key, value);\nCREATE TABLE IF NOT EXISTS project_links (\n id TEXT PRIMARY KEY,\n downstream_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n upstream_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n package_name TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_links_downstream_package_idx ON project_links (downstream_id, package_name);\nCREATE TABLE IF NOT EXISTS design_links (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n import_path TEXT,\n label TEXT,\n url TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS design_links_project_id_idx ON design_links (project_id);\nCREATE TABLE IF NOT EXISTS design_credentials (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n token_encrypted TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'unknown',\n checked_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS design_credentials_project_provider_idx ON design_credentials (project_id, provider);\nCREATE TABLE IF NOT EXISTS design_nodes (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n viewer_id TEXT NOT NULL DEFAULT '',\n file_key TEXT NOT NULL,\n node_id TEXT NOT NULL DEFAULT '',\n name TEXT,\n version TEXT,\n last_modified TEXT,\n state TEXT NOT NULL DEFAULT 'ok',\n render_path TEXT,\n render_version TEXT,\n fetched_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS design_nodes_project_file_node_idx ON design_nodes (project_id, provider, viewer_id, file_key, node_id);\nCREATE TABLE IF NOT EXISTS build_package_usage (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE,\n story_import_path TEXT NOT NULL,\n package_name TEXT NOT NULL,\n module_path TEXT NOT NULL,\n version TEXT,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS build_package_usage_build_id_idx ON build_package_usage (build_id);\nCREATE TABLE IF NOT EXISTS tokens (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n hash TEXT NOT NULL UNIQUE,\n user_id TEXT REFERENCES users(id) ON DELETE CASCADE,\n last_used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS webhooks (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n url TEXT NOT NULL,\n secret_encrypted TEXT NOT NULL,\n events TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS notification_channels (\n id TEXT PRIMARY KEY,\n project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n config TEXT NOT NULL,\n secret_encrypted TEXT,\n events TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n last_error TEXT,\n last_error_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS notification_channels_project_id_idx ON notification_channels (project_id);\nCREATE TABLE IF NOT EXISTS notification_subscriptions (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n events TEXT,\n via TEXT,\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS notification_subscriptions_project_user_idx ON notification_subscriptions (project_id, user_id);\nCREATE TABLE IF NOT EXISTS insights (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n build_id TEXT REFERENCES builds(id) ON DELETE CASCADE,\n kind TEXT NOT NULL,\n window_key TEXT,\n input_hash TEXT NOT NULL,\n status TEXT NOT NULL,\n profile TEXT NOT NULL,\n model TEXT NOT NULL,\n prompt_version TEXT NOT NULL,\n verdict TEXT,\n summary TEXT,\n result TEXT,\n error_code TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n started_at TIMESTAMPTZ,\n finished_at TIMESTAMPTZ\n);\nCREATE INDEX IF NOT EXISTS insights_project_build_idx ON insights (project_id, build_id);\nCREATE INDEX IF NOT EXISTS insights_created_at_idx ON insights (created_at);\nCREATE UNIQUE INDEX IF NOT EXISTS insights_triage_unique_idx ON insights (project_id, build_id, kind, input_hash);\nCREATE UNIQUE INDEX IF NOT EXISTS insights_health_unique_idx ON insights (project_id, kind, window_key);\nCREATE TABLE IF NOT EXISTS ai_usage (\n id TEXT PRIMARY KEY,\n insight_id TEXT,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n profile TEXT NOT NULL,\n task TEXT NOT NULL,\n model TEXT NOT NULL,\n input_tokens INTEGER NOT NULL DEFAULT 0,\n output_tokens INTEGER NOT NULL DEFAULT 0,\n estimated BOOLEAN NOT NULL DEFAULT false,\n images INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS ai_usage_created_at_idx ON ai_usage (created_at);\nCREATE INDEX IF NOT EXISTS ai_usage_project_created_idx ON ai_usage (project_id, created_at);\nCREATE TABLE IF NOT EXISTS ai_budget_alerts (\n id TEXT PRIMARY KEY,\n day TEXT NOT NULL,\n threshold INTEGER NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS user_invite_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n token_hash TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n used_at TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS project_members (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\n role TEXT NOT NULL DEFAULT 'viewer',\n source TEXT NOT NULL DEFAULT 'manual',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_members_project_user_idx ON project_members (project_id, user_id);\nCREATE TABLE IF NOT EXISTS project_group_mappings (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n group_name TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'viewer',\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS project_group_mappings_project_group_idx ON project_group_mappings (project_id, group_name);\nCREATE TABLE IF NOT EXISTS content_refs (\n hash TEXT PRIMARY KEY,\n ref_count INTEGER NOT NULL DEFAULT 1,\n last_seen_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS \"user\" (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n email TEXT NOT NULL UNIQUE,\n email_verified BOOLEAN NOT NULL DEFAULT false,\n image TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE TABLE IF NOT EXISTS session (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n token TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMPTZ NOT NULL,\n ip_address TEXT,\n user_agent TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS session_token_idx ON session (token);\nCREATE INDEX IF NOT EXISTS session_user_id_idx ON session (user_id);\nCREATE TABLE IF NOT EXISTS account (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n account_id TEXT NOT NULL,\n provider_id TEXT NOT NULL,\n access_token TEXT,\n refresh_token TEXT,\n id_token TEXT,\n access_token_expires_at TIMESTAMPTZ,\n refresh_token_expires_at TIMESTAMPTZ,\n scope TEXT,\n expires_at TIMESTAMPTZ,\n password TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS account_user_id_idx ON account (user_id);\nCREATE TABLE IF NOT EXISTS verification (\n id TEXT PRIMARY KEY,\n identifier TEXT NOT NULL,\n value TEXT NOT NULL,\n expires_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ NOT NULL\n);\nCREATE INDEX IF NOT EXISTS verification_identifier_idx ON verification (identifier);\nCREATE TABLE IF NOT EXISTS passkey (\n id TEXT PRIMARY KEY,\n name TEXT,\n public_key TEXT NOT NULL,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n credential_id TEXT NOT NULL,\n counter INTEGER NOT NULL,\n device_type TEXT NOT NULL,\n backed_up BOOLEAN NOT NULL DEFAULT false,\n transports TEXT,\n aaguid TEXT,\n created_at TIMESTAMPTZ NOT NULL,\n updated_at TIMESTAMPTZ\n);\nCREATE INDEX IF NOT EXISTS passkey_user_id_idx ON passkey (user_id);\nCREATE INDEX IF NOT EXISTS passkey_credential_id_idx ON passkey (credential_id);\nCREATE TABLE IF NOT EXISTS \"ssoProvider\" (\n id TEXT PRIMARY KEY,\n issuer TEXT NOT NULL,\n oidc_config TEXT,\n saml_config TEXT,\n user_id TEXT NOT NULL REFERENCES \"user\"(id) ON DELETE CASCADE,\n provider_id TEXT NOT NULL UNIQUE,\n organization_id TEXT,\n domain TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS ssoprovider_domain_idx ON \"ssoProvider\" (domain);\n`;\n"],"mappings":";;;;;AACA,MAAa,MAAM"}
package/dist/index.mjs CHANGED
@@ -28,7 +28,7 @@ function createPostgresDatabase(options) {
28
28
  return createDrizzlePgAdapter(db, {
29
29
  metadata: {
30
30
  name: "Postgres",
31
- version: globalThis.__PKG_VERSION__ ?? "0.0.0",
31
+ version: "0.7.0",
32
32
  description: "Postgres database adapter (postgres.js + Drizzle)",
33
33
  kind: "postgres",
34
34
  category: "database"
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/postgres-js\";\nimport postgres from \"postgres\";\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 * TLS options for Postgres connections. When `true`, the driver negotiates\n * TLS with the server's default CA. When an object, `ca`/`cert`/`key` are\n * forwarded to `postgres.js` for mutual TLS (e.g. GCP Cloud SQL) or custom\n * RDS bundles.\n */\nexport type PostgresSslOptions = boolean | { ca?: string; cert?: string; key?: string };\n\n/**\n * Options for creating a Postgres-backed DatabaseAdapter.\n *\n * `url` (or `connectionString`) is the Postgres connection string\n * (`postgres://user:pass@host:5432/db`). For managed providers, see the\n * deployment guide for per-provider recipes (RDS CA bundle, Cloud SQL\n * mutual TLS, Supabase pooler port `6543` with `prepare: false`, etc.).\n *\n * When `client` is supplied, all other connection options are ignored and\n * the caller owns the lifecycle of the client. This is the hook for\n * advanced setups (IAM token refresh, pre-configured TLS, etc.) and for\n * hermetic tests.\n */\nexport interface PostgresDatabaseOptions {\n url?: string;\n connectionString?: string;\n ssl?: PostgresSslOptions;\n prepare?: boolean;\n max?: number;\n idleTimeout?: number;\n connectTimeout?: number;\n client?: ReturnType<typeof postgres>;\n}\n\n/**\n * Create a Postgres-backed DatabaseAdapter using postgres.js and Drizzle ORM.\n *\n * Works with self-hosted Postgres, AWS RDS, GCP Cloud SQL, Supabase, Neon,\n * and Azure Database for PostgreSQL — all speak the standard wire protocol.\n * For provider-specific TLS and pooling notes, see the deployment guide.\n */\nexport function createPostgresDatabase(options: PostgresDatabaseOptions): DatabaseAdapter {\n const connectionString = options.connectionString ?? options.url;\n if (!options.client && !connectionString) {\n throw new Error(\n \"createPostgresDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n\n const client =\n options.client ??\n postgres(connectionString as string, {\n ssl: options.ssl as never,\n prepare: options.prepare,\n max: options.max,\n idle_timeout: options.idleTimeout,\n connect_timeout: options.connectTimeout,\n });\n\n // oxlint-disable-next-line typescript/no-unsafe-argument -- postgres instance may be from isolated store vs workspace\n const db = drizzle(client as never, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Postgres\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"Postgres database adapter (postgres.js + Drizzle)\",\n kind: \"postgres\",\n category: \"database\",\n },\n tables: schema as unknown as DatabaseAdapter[\"tables\"],\n migrate: async () => {\n await runMigrations(async (sql: string) => await client.unsafe(sql));\n },\n close: async () => {\n await client.end();\n },\n ping: async () => {\n await client.unsafe(\"SELECT 1\");\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgDA,SAAgB,uBAAuB,SAAmD;CACxF,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,QAAQ,UAAU,CAAC,kBACtB,MAAM,IAAI,MACR,2FACF;CAGF,MAAM,SACJ,QAAQ,UACR,SAAS,kBAA4B;EACnC,KAAK,QAAQ;EACb,SAAS,QAAQ;EACjB,KAAK,QAAQ;EACb,cAAc,QAAQ;EACtB,iBAAiB,QAAQ;CAC3B,CAAC;CAGH,MAAM,KAAK,QAAQ,QAAiB,EAAE,OAAO,CAAC;CAE9C,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,QAAgB,MAAM,OAAO,OAAO,GAAG,CAAC;EACrE;EACA,OAAO,YAAY;GACjB,MAAM,OAAO,IAAI;EACnB;EACA,MAAM,YAAY;GAChB,MAAM,OAAO,OAAO,UAAU;EAChC;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { drizzle } from \"drizzle-orm/postgres-js\";\nimport postgres from \"postgres\";\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 * TLS options for Postgres connections. When `true`, the driver negotiates\n * TLS with the server's default CA. When an object, `ca`/`cert`/`key` are\n * forwarded to `postgres.js` for mutual TLS (e.g. GCP Cloud SQL) or custom\n * RDS bundles.\n */\nexport type PostgresSslOptions = boolean | { ca?: string; cert?: string; key?: string };\n\n/**\n * Options for creating a Postgres-backed DatabaseAdapter.\n *\n * `url` (or `connectionString`) is the Postgres connection string\n * (`postgres://user:pass@host:5432/db`). For managed providers, see the\n * deployment guide for per-provider recipes (RDS CA bundle, Cloud SQL\n * mutual TLS, Supabase pooler port `6543` with `prepare: false`, etc.).\n *\n * When `client` is supplied, all other connection options are ignored and\n * the caller owns the lifecycle of the client. This is the hook for\n * advanced setups (IAM token refresh, pre-configured TLS, etc.) and for\n * hermetic tests.\n */\nexport interface PostgresDatabaseOptions {\n url?: string;\n connectionString?: string;\n ssl?: PostgresSslOptions;\n prepare?: boolean;\n max?: number;\n idleTimeout?: number;\n connectTimeout?: number;\n client?: ReturnType<typeof postgres>;\n}\n\n/**\n * Create a Postgres-backed DatabaseAdapter using postgres.js and Drizzle ORM.\n *\n * Works with self-hosted Postgres, AWS RDS, GCP Cloud SQL, Supabase, Neon,\n * and Azure Database for PostgreSQL — all speak the standard wire protocol.\n * For provider-specific TLS and pooling notes, see the deployment guide.\n */\nexport function createPostgresDatabase(options: PostgresDatabaseOptions): DatabaseAdapter {\n const connectionString = options.connectionString ?? options.url;\n if (!options.client && !connectionString) {\n throw new Error(\n \"createPostgresDatabase: provide `url` (or `connectionString`) or a preconfigured `client`\",\n );\n }\n\n const client =\n options.client ??\n postgres(connectionString as string, {\n ssl: options.ssl as never,\n prepare: options.prepare,\n max: options.max,\n idle_timeout: options.idleTimeout,\n connect_timeout: options.connectTimeout,\n });\n\n // oxlint-disable-next-line typescript/no-unsafe-argument -- postgres instance may be from isolated store vs workspace\n const db = drizzle(client as never, { schema });\n\n return createDrizzlePgAdapter(db, {\n metadata: {\n name: \"Postgres\",\n version: typeof __PKG_VERSION__ === \"string\" ? __PKG_VERSION__ : \"0.0.0\",\n description: \"Postgres database adapter (postgres.js + Drizzle)\",\n kind: \"postgres\",\n category: \"database\",\n },\n tables: schema as unknown as DatabaseAdapter[\"tables\"],\n migrate: async () => {\n await runMigrations(async (sql: string) => await client.unsafe(sql));\n },\n close: async () => {\n await client.end();\n },\n ping: async () => {\n await client.unsafe(\"SELECT 1\");\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgDA,SAAgB,uBAAuB,SAAmD;CACxF,MAAM,mBAAmB,QAAQ,oBAAoB,QAAQ;CAC7D,IAAI,CAAC,QAAQ,UAAU,CAAC,kBACtB,MAAM,IAAI,MACR,2FACF;CAGF,MAAM,SACJ,QAAQ,UACR,SAAS,kBAA4B;EACnC,KAAK,QAAQ;EACb,SAAS,QAAQ;EACjB,KAAK,QAAQ;EACb,cAAc,QAAQ;EACtB,iBAAiB,QAAQ;CAC3B,CAAC;CAGH,MAAM,KAAK,QAAQ,QAAiB,EAAE,OAAO,CAAC;CAE9C,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,QAAgB,MAAM,OAAO,OAAO,GAAG,CAAC;EACrE;EACA,OAAO,YAAY;GACjB,MAAM,OAAO,IAAI;EACnB;EACA,MAAM,YAAY;GAChB,MAAM,OAAO,OAAO,UAAU;EAChC;CACF,CAAC;AACH"}