feat: add SQL authoritative host storage#222
Conversation
|
Important Review skippedToo many files! This PR contains 192 files, which is 92 over the limit of 100. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (192)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Preview DeployedLanding: https://pr-222.preview.caplets.dev Built from commit d5c1333 |
|
| Filename | Overview |
|---|---|
| packages/core/src/storage/caplet-records.ts | N+1 list() fix is in place (5 bounded batch queries); collectAssetGarbage does a full-table SELECT including the potentially large payload/bytea column when only hash and createdAt are needed for GC candidate selection. |
| packages/core/src/storage/coordination.ts | Cluster coordination: previously-flagged deadlock (Postgres heartbeat) and SQLite deferred-transaction (lease acquisition) bugs are fixed; clock-authoritative activeNodeCount uses clock_timestamp(); advisory locks protect config-generation and lease operations. |
| packages/core/src/storage/migrations.ts | SQLite migration runner now uses INTEGER PRIMARY KEY and validates the full applied history with hashes; Postgres delegates to Drizzle migrator; assertSchemaIsNotNewer prevents downgrade. |
| packages/core/src/storage/database.ts | HostStorage factory correctly opens SQLite/Postgres, auto-migrates SQLite on createHostStorage, validates Postgres health before serving, and properly closes all resources. |
| packages/core/src/storage/schema/postgres.ts | Comprehensive Postgres schema covering caplet records, revisions, installations, vault, remote auth, dashboard sessions, and cluster coordination; proper FK cascades and unique indexes throughout. |
| packages/core/src/storage/schema/sqlite.ts | SQLite schema mirrors Postgres with appropriate type translations (jsonb→text/json, bytea→blob, boolean→integer); consistent FK cascades and index definitions. |
| deploy/postgres/finalize-runtime-grants.mjs | Post-migration script grants SELECT/INSERT/UPDATE/DELETE to caplets_runtime on all tables except the migration tracking tables; revokes sequences tied to caplets_migrations/caplets_schema. |
| deploy/postgres/init-caplets-roles.sh | Idempotent shell script that provisions caplets_migrator and caplets_runtime roles with least-privilege grants; schema name validation mirrors the TypeScript regex. |
| deploy/postgres/render-config.mjs | Renders a Caplets config JSON with the Postgres connection string using URL encoding for special characters in passwords; writes with mode 0o600 to protect credentials. |
| packages/core/src/storage/legacy-migration.ts | Migrates legacy file-based state (OAuth tokens, vault, remote auth, setup state, operator activity) to SQL storage; supports dry-run mode and optional backup. |
| apps/dashboard/src/components/StoredCapletsPage.tsx | New dashboard page for viewing, editing, importing, and exporting caplet records from SQL storage; uses React state, no unsafe HTML rendering found. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant App
participant HostStorage
participant SQLite/Postgres
participant S3
App->>HostStorage: createHostStorage(config)
HostStorage->>SQLite/Postgres: migrateHostDatabase()
SQLite/Postgres-->>HostStorage: schema ready
App->>HostStorage: caplets.importBundle(input)
HostStorage->>SQLite/Postgres: prepareAssetStorage (upsert blobs)
opt S3 configured
HostStorage->>S3: upload blob
end
HostStorage->>SQLite/Postgres: insert record + revision + tags + backends + entries
App->>HostStorage: caplets.list()
HostStorage->>SQLite/Postgres: SELECT caplet_records
HostStorage->>SQLite/Postgres: SELECT caplet_revisions (batch)
HostStorage->>SQLite/Postgres: SELECT tags + backends + entries (parallel)
SQLite/Postgres-->>HostStorage: rows
HostStorage-->>App: CapletRecordView[]
App->>HostStorage: maintainAssets()
HostStorage->>SQLite/Postgres: acquireLease (advisory lock / exclusive tx)
HostStorage->>SQLite/Postgres: collectAssetGarbage
opt S3 configured
HostStorage->>S3: delete orphaned objects
end
HostStorage->>SQLite/Postgres: checkpointLease
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant App
participant HostStorage
participant SQLite/Postgres
participant S3
App->>HostStorage: createHostStorage(config)
HostStorage->>SQLite/Postgres: migrateHostDatabase()
SQLite/Postgres-->>HostStorage: schema ready
App->>HostStorage: caplets.importBundle(input)
HostStorage->>SQLite/Postgres: prepareAssetStorage (upsert blobs)
opt S3 configured
HostStorage->>S3: upload blob
end
HostStorage->>SQLite/Postgres: insert record + revision + tags + backends + entries
App->>HostStorage: caplets.list()
HostStorage->>SQLite/Postgres: SELECT caplet_records
HostStorage->>SQLite/Postgres: SELECT caplet_revisions (batch)
HostStorage->>SQLite/Postgres: SELECT tags + backends + entries (parallel)
SQLite/Postgres-->>HostStorage: rows
HostStorage-->>App: CapletRecordView[]
App->>HostStorage: maintainAssets()
HostStorage->>SQLite/Postgres: acquireLease (advisory lock / exclusive tx)
HostStorage->>SQLite/Postgres: collectAssetGarbage
opt S3 configured
HostStorage->>S3: delete orphaned objects
end
HostStorage->>SQLite/Postgres: checkpointLease
Reviews (4): Last reviewed commit: "fix: serialize PostgreSQL node heartbeat..." | Re-trigger Greptile
Summary
Verification
pnpm verify