@agent-native/core 0.77.8 → 0.77.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +35 -0
- package/corpus/core/package.json +3 -3
- package/corpus/core/src/a2a/task-store.ts +25 -3
- package/corpus/core/src/agent/harness/store.ts +89 -55
- package/corpus/core/src/agent/observational-memory/store.ts +40 -14
- package/corpus/core/src/agent/run-store.ts +116 -59
- package/corpus/core/src/application-state/store.ts +36 -2
- package/corpus/core/src/audit/store.ts +37 -6
- package/corpus/core/src/browser-sessions/store.ts +31 -12
- package/corpus/core/src/chat-threads/store.ts +67 -3
- package/corpus/core/src/checkpoints/store.ts +14 -3
- package/corpus/core/src/cli/create.ts +9 -0
- package/corpus/core/src/collab/awareness.ts +12 -9
- package/corpus/core/src/collab/client.ts +4 -2
- package/corpus/core/src/collab/storage.ts +20 -2
- package/corpus/core/src/db/ddl-guard.ts +112 -0
- package/corpus/core/src/extensions/store.ts +76 -3
- package/corpus/core/src/integrations/a2a-continuations-store.ts +69 -26
- package/corpus/core/src/integrations/config-store.ts +19 -18
- package/corpus/core/src/integrations/pending-tasks-store.ts +40 -16
- package/corpus/core/src/integrations/remote-commands-store.ts +37 -23
- package/corpus/core/src/integrations/remote-devices-store.ts +64 -20
- package/corpus/core/src/integrations/remote-push-store.ts +75 -35
- package/corpus/core/src/integrations/remote-run-events-store.ts +38 -12
- package/corpus/core/src/integrations/thread-mapping-store.ts +11 -2
- package/corpus/core/src/mcp/connect-store.ts +53 -16
- package/corpus/core/src/mcp/oauth-store.ts +32 -7
- package/corpus/core/src/notifications/store.ts +20 -4
- package/corpus/core/src/oauth-tokens/store.ts +45 -2
- package/corpus/core/src/observability/store.ts +154 -47
- package/corpus/core/src/progress/store.ts +36 -21
- package/corpus/core/src/provider-api/corpus-jobs-store.ts +25 -5
- package/corpus/core/src/provider-api/custom-registry.ts +15 -4
- package/corpus/core/src/provider-api/quota-governor.ts +15 -3
- package/corpus/core/src/provider-api/staged-datasets-store.ts +22 -5
- package/corpus/core/src/resources/store.ts +66 -31
- package/corpus/core/src/secrets/storage.ts +18 -22
- package/corpus/core/src/server/agent-teams-run-queue.ts +22 -10
- package/corpus/core/src/server/auth.ts +22 -4
- package/corpus/core/src/server/better-auth-instance.ts +49 -15
- package/corpus/core/src/server/embed-session.ts +19 -4
- package/corpus/core/src/server/identity-sso-store.ts +40 -11
- package/corpus/core/src/server/recap-image-store.ts +28 -9
- package/corpus/core/src/settings/store.ts +14 -19
- package/corpus/core/src/usage/store.ts +51 -16
- package/corpus/core/src/workspace-connections/store.ts +200 -22
- package/corpus/templates/calendar/changelog/2026-06-25-booking-link-previews-now-show-the-content-directly-on-the-g.md +6 -0
- package/corpus/templates/calendar/server/lib/booking-og-image.ts +0 -2
- package/corpus/templates/clips/chrome-extension/package.json +1 -1
- package/corpus/templates/content/actions/list-trashed-content-databases.ts +36 -2
- package/corpus/templates/content/actions/move-document.ts +79 -33
- package/corpus/templates/content/actions/restore-content-database.ts +40 -3
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +84 -2
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +177 -49
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +393 -219
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +632 -467
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +114 -14
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +56 -15
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +6 -5
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +12 -4
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/hooks/use-create-page.ts +36 -7
- package/corpus/templates/content/app/i18n-data.ts +140 -10
- package/corpus/templates/content/changelog/2026-06-25-comment-cards-now-track-their-highlighted-text-while-scrolli.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-comments-now-scroll-with-the-document-and-stay-below-the-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-creating-a-database-from-the-slash-menu-no-longer-leaves-sta.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-sidebar-hover-controls-no-longer-leave-a-lingering-fade-when.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-sidebar-page-actions-are-now-easier-to-see-when-hovering-ina.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-text-selections-in-the-editor-no-longer-show-white-gaps-when.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-has-a-one-click-page-link-copy-button.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-shows-page-breadcrumbs-and-the-latest.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-the-page-command-now-leaves-a-notion-style-page-reference-an.md +6 -0
- package/corpus/templates/content/shared/nfm.ts +16 -0
- package/corpus/templates/forms/changelog/2026-06-25-form-previews-now-show-the-content-directly-on-the-grid-back.md +6 -0
- package/corpus/templates/forms/server/lib/form-og-image.ts +0 -2
- package/corpus/templates/plan/app/global.css +6 -11
- package/corpus/templates/plan/app/pages/PlansPage.tsx +12 -10
- package/corpus/templates/plan/changelog/2026-06-25-plan-access-request-pages-stay-visible-during-background-ref.md +6 -0
- package/corpus/templates/plan/changelog/2026-06-25-plan-documents-keep-their-full-reading-width-below-1200px-an.md +6 -0
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +19 -3
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/agent/harness/store.d.ts.map +1 -1
- package/dist/agent/harness/store.js +63 -34
- package/dist/agent/harness/store.js.map +1 -1
- package/dist/agent/observational-memory/store.d.ts.map +1 -1
- package/dist/agent/observational-memory/store.js +30 -8
- package/dist/agent/observational-memory/store.js.map +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +103 -46
- package/dist/agent/run-store.js.map +1 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +28 -2
- package/dist/application-state/store.js.map +1 -1
- package/dist/audit/store.d.ts.map +1 -1
- package/dist/audit/store.js +18 -3
- package/dist/audit/store.js.map +1 -1
- package/dist/browser-sessions/store.d.ts.map +1 -1
- package/dist/browser-sessions/store.js +22 -7
- package/dist/browser-sessions/store.js.map +1 -1
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +51 -3
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/checkpoints/store.d.ts.map +1 -1
- package/dist/checkpoints/store.js +12 -3
- package/dist/checkpoints/store.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +9 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/collab/awareness.d.ts +1 -1
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/awareness.js +12 -8
- package/dist/collab/awareness.js.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +4 -3
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts.map +1 -1
- package/dist/collab/storage.js +14 -2
- package/dist/collab/storage.js.map +1 -1
- package/dist/db/ddl-guard.d.ts +63 -0
- package/dist/db/ddl-guard.d.ts.map +1 -1
- package/dist/db/ddl-guard.js +85 -0
- package/dist/db/ddl-guard.js.map +1 -1
- package/dist/extensions/store.d.ts.map +1 -1
- package/dist/extensions/store.js +32 -3
- package/dist/extensions/store.js.map +1 -1
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +44 -24
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/config-store.d.ts.map +1 -1
- package/dist/integrations/config-store.js +17 -11
- package/dist/integrations/config-store.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +24 -16
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/remote-commands-store.d.ts.map +1 -1
- package/dist/integrations/remote-commands-store.js +29 -21
- package/dist/integrations/remote-commands-store.js.map +1 -1
- package/dist/integrations/remote-devices-store.d.ts.map +1 -1
- package/dist/integrations/remote-devices-store.js +33 -18
- package/dist/integrations/remote-devices-store.js.map +1 -1
- package/dist/integrations/remote-push-store.d.ts.map +1 -1
- package/dist/integrations/remote-push-store.js +53 -31
- package/dist/integrations/remote-push-store.js.map +1 -1
- package/dist/integrations/remote-run-events-store.d.ts.map +1 -1
- package/dist/integrations/remote-run-events-store.js +26 -10
- package/dist/integrations/remote-run-events-store.js.map +1 -1
- package/dist/integrations/thread-mapping-store.d.ts.map +1 -1
- package/dist/integrations/thread-mapping-store.js +10 -2
- package/dist/integrations/thread-mapping-store.js.map +1 -1
- package/dist/mcp/connect-store.d.ts.map +1 -1
- package/dist/mcp/connect-store.js +34 -16
- package/dist/mcp/connect-store.js.map +1 -1
- package/dist/mcp/oauth-store.d.ts.map +1 -1
- package/dist/mcp/oauth-store.js +22 -7
- package/dist/mcp/oauth-store.js.map +1 -1
- package/dist/notifications/store.d.ts.map +1 -1
- package/dist/notifications/store.js +15 -3
- package/dist/notifications/store.js.map +1 -1
- package/dist/oauth-tokens/store.d.ts.map +1 -1
- package/dist/oauth-tokens/store.js +33 -2
- package/dist/oauth-tokens/store.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +72 -29
- package/dist/observability/store.js.map +1 -1
- package/dist/progress/store.d.ts.map +1 -1
- package/dist/progress/store.js +31 -16
- package/dist/progress/store.js.map +1 -1
- package/dist/provider-api/corpus-jobs-store.d.ts.map +1 -1
- package/dist/provider-api/corpus-jobs-store.js +16 -5
- package/dist/provider-api/corpus-jobs-store.js.map +1 -1
- package/dist/provider-api/custom-registry.d.ts.map +1 -1
- package/dist/provider-api/custom-registry.js +14 -4
- package/dist/provider-api/custom-registry.js.map +1 -1
- package/dist/provider-api/quota-governor.d.ts.map +1 -1
- package/dist/provider-api/quota-governor.js +12 -3
- package/dist/provider-api/quota-governor.js.map +1 -1
- package/dist/provider-api/staged-datasets-store.d.ts.map +1 -1
- package/dist/provider-api/staged-datasets-store.js +16 -5
- package/dist/provider-api/staged-datasets-store.js.map +1 -1
- package/dist/resources/store.d.ts.map +1 -1
- package/dist/resources/store.js +56 -25
- package/dist/resources/store.js.map +1 -1
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +10 -14
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/agent-teams-run-queue.d.ts.map +1 -1
- package/dist/server/agent-teams-run-queue.js +15 -4
- package/dist/server/agent-teams-run-queue.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +16 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +55 -21
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/embed-session.d.ts.map +1 -1
- package/dist/server/embed-session.js +15 -4
- package/dist/server/embed-session.js.map +1 -1
- package/dist/server/identity-sso-store.d.ts.map +1 -1
- package/dist/server/identity-sso-store.js +30 -11
- package/dist/server/identity-sso-store.js.map +1 -1
- package/dist/server/recap-image-store.d.ts.map +1 -1
- package/dist/server/recap-image-store.js +21 -7
- package/dist/server/recap-image-store.js.map +1 -1
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +11 -13
- package/dist/settings/store.js.map +1 -1
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +36 -11
- package/dist/usage/store.js.map +1 -1
- package/dist/workspace-connections/store.d.ts.map +1 -1
- package/dist/workspace-connections/store.js +57 -7
- package/dist/workspace-connections/store.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staged-datasets-store.js","sourceRoot":"","sources":["../../src/provider-api/staged-datasets-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Scratch storage for staged provider-API datasets.\n *\n * Rows are stored as JSON text — no dialect-specific JSON-column types needed.\n * Aggregation is done in TypeScript server-side (portable across Postgres and\n * SQLite) rather than via JSON SQL fragments. See `staged-datasets-aggregate.ts`.\n *\n * Storage caps:\n * - MAX_ROWS_PER_APP: 200 000 rows\n * - MAX_BYTES_PER_APP: 50 MB (approximate, measured as raw JSON text length)\n *\n * Scoping: datasets are owned by (app_id, owner_email) so different apps or\n * different users never share or cross-read each other's scratch data.\n */\n\nimport { getDbExec, intType, isPostgres, type DbExec } from \"../db/client.js\";\n\n// ---------------------------------------------------------------------------\n// Caps\n// ---------------------------------------------------------------------------\nexport const MAX_ROWS_PER_APP = 200_000;\nexport const MAX_BYTES_PER_APP = 50 * 1024 * 1024; // 50 MB\n\n// ---------------------------------------------------------------------------\n// Table initialisation\n// ---------------------------------------------------------------------------\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const db = getDbExec();\n const integerType = intType();\n await db.execute(`\n CREATE TABLE IF NOT EXISTS staged_datasets (\n id TEXT NOT NULL,\n app_id TEXT NOT NULL,\n owner_email TEXT NOT NULL,\n name TEXT NOT NULL,\n columns TEXT NOT NULL,\n row_count ${integerType} NOT NULL DEFAULT 0,\n byte_size ${integerType} NOT NULL DEFAULT 0,\n created_at ${integerType} NOT NULL,\n updated_at ${integerType} NOT NULL,\n PRIMARY KEY (id)\n )\n `);\n await db.execute(`\n CREATE TABLE IF NOT EXISTS staged_dataset_rows (\n dataset_id TEXT NOT NULL,\n row_index ${integerType} NOT NULL,\n row_data TEXT NOT NULL,\n PRIMARY KEY (dataset_id, row_index)\n )\n `);\n if (isPostgres()) {\n await widenPostgresIntegerColumns(db);\n }\n for (const ddl of [\n `CREATE INDEX IF NOT EXISTS staged_datasets_scope_idx ON staged_datasets (app_id, owner_email)`,\n `CREATE INDEX IF NOT EXISTS staged_dataset_rows_dataset_idx ON staged_dataset_rows (dataset_id)`,\n ]) {\n try {\n await db.execute(ddl);\n } catch {\n // Index already exists — harmless.\n }\n }\n })().catch((err) => {\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nasync function widenPostgresIntegerColumns(db: DbExec): Promise<void> {\n const statements = [\n `ALTER TABLE staged_datasets ALTER COLUMN row_count TYPE BIGINT USING row_count::bigint`,\n `ALTER TABLE staged_datasets ALTER COLUMN byte_size TYPE BIGINT USING byte_size::bigint`,\n `ALTER TABLE staged_datasets ALTER COLUMN created_at TYPE BIGINT USING created_at::bigint`,\n `ALTER TABLE staged_datasets ALTER COLUMN updated_at TYPE BIGINT USING updated_at::bigint`,\n `ALTER TABLE staged_dataset_rows ALTER COLUMN row_index TYPE BIGINT USING row_index::bigint`,\n ];\n for (const sql of statements) {\n try {\n await db.execute(sql);\n } catch {\n // Best-effort compatibility for older deployments. Widening is\n // non-destructive; if a database role cannot ALTER, the later write will\n // still surface the real DB error.\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface StagedDatasetMeta {\n id: string;\n appId: string;\n ownerEmail: string;\n name: string;\n columns: string[];\n rowCount: number;\n byteSize: number;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface UpsertDatasetOptions {\n id: string;\n appId: string;\n ownerEmail: string;\n name: string;\n /** All rows to store; replaces any existing rows. */\n rows: Record<string, unknown>[];\n columns: string[];\n /** When true, append rows instead of replacing. */\n append?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generateId(): string {\n return `ds_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/** Derive column names from a set of rows (first 20 rows surveyed). */\nexport function deriveColumns(rows: Record<string, unknown>[]): string[] {\n const seen = new Set<string>();\n for (const row of rows.slice(0, 20)) {\n for (const key of Object.keys(row)) seen.add(key);\n }\n return Array.from(seen);\n}\n\n// ---------------------------------------------------------------------------\n// Scope check\n// ---------------------------------------------------------------------------\n\nasync function getAppRowCount(appId: string): Promise<number> {\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT COALESCE(SUM(row_count), 0) as total FROM staged_datasets WHERE app_id = ?`,\n args: [appId],\n });\n return Number(rows[0]?.total ?? 0);\n}\n\nasync function getAppByteSize(appId: string): Promise<number> {\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT COALESCE(SUM(byte_size), 0) as total FROM staged_datasets WHERE app_id = ?`,\n args: [appId],\n });\n return Number(rows[0]?.total ?? 0);\n}\n\n// ---------------------------------------------------------------------------\n// Write\n// ---------------------------------------------------------------------------\n\n/**\n * Create or replace a staged dataset. Returns metadata including the\n * resolved dataset ID (generated when not supplied in options).\n */\nexport async function upsertStagedDataset(\n options: UpsertDatasetOptions,\n): Promise<StagedDatasetMeta> {\n await ensureTables();\n const db = getDbExec();\n const now = Date.now();\n const id = options.id || generateId();\n\n // If appending, load existing rows first.\n let existingRows: Record<string, unknown>[] = [];\n if (options.append) {\n existingRows = await getStagedDatasetRows({\n id,\n appId: options.appId,\n ownerEmail: options.ownerEmail,\n });\n }\n\n const allRows = options.append\n ? [...existingRows, ...options.rows]\n : options.rows;\n\n // Check caps (net new count after this write).\n const currentAppRows = await getAppRowCount(options.appId);\n const currentDatasetRows = options.append\n ? existingRows.length\n : await (async () => {\n const { rows } = await db.execute({\n sql: `SELECT row_count FROM staged_datasets WHERE id = ?`,\n args: [id],\n });\n return Number(rows[0]?.row_count ?? 0);\n })();\n const netNewRows = allRows.length - currentDatasetRows;\n if (currentAppRows + netNewRows > MAX_ROWS_PER_APP) {\n throw new Error(\n `Staged dataset cap exceeded: this app already has ${currentAppRows} rows stored ` +\n `(limit ${MAX_ROWS_PER_APP}). Delete older datasets before staging more data.`,\n );\n }\n\n // Serialize rows and measure byte size.\n const serialized = allRows.map((row) => JSON.stringify(row));\n const byteSize = serialized.reduce((sum, s) => sum + s.length, 0);\n\n const currentAppBytes = await getAppByteSize(options.appId);\n const existingDatasetBytes = options.append\n ? await (async () => {\n const { rows } = await db.execute({\n sql: `SELECT byte_size FROM staged_datasets WHERE id = ?`,\n args: [id],\n });\n return Number(rows[0]?.byte_size ?? 0);\n })()\n : 0;\n const netNewBytes = byteSize - existingDatasetBytes;\n if (currentAppBytes + netNewBytes > MAX_BYTES_PER_APP) {\n throw new Error(\n `Staged dataset byte cap exceeded: this app already stores ` +\n `${(currentAppBytes / 1024 / 1024).toFixed(1)} MB (limit 50 MB). ` +\n `Delete older datasets before staging more data.`,\n );\n }\n\n const columns = options.columns.length\n ? options.columns\n : deriveColumns(allRows);\n const columnsJson = JSON.stringify(columns);\n\n await withDbTransaction(db, async (tx) => {\n // Delete old rows and insert the replacement row set atomically with the\n // metadata update so a failed batch cannot leave an empty or partial dataset.\n await tx.execute({\n sql: `DELETE FROM staged_dataset_rows WHERE dataset_id = ?`,\n args: [id],\n });\n\n const BATCH = 500;\n for (let i = 0; i < serialized.length; i += BATCH) {\n const slice = serialized.slice(i, i + BATCH);\n for (let j = 0; j < slice.length; j++) {\n await tx.execute({\n sql: `INSERT INTO staged_dataset_rows (dataset_id, row_index, row_data) VALUES (?, ?, ?)`,\n args: [id, i + j, slice[j]],\n });\n }\n }\n\n await tx.execute({\n sql: isPostgres()\n ? `INSERT INTO staged_datasets (id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name, columns=EXCLUDED.columns, row_count=EXCLUDED.row_count, byte_size=EXCLUDED.byte_size, updated_at=EXCLUDED.updated_at`\n : `INSERT OR REPLACE INTO staged_datasets (id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n options.appId,\n options.ownerEmail,\n options.name,\n columnsJson,\n allRows.length,\n byteSize,\n now,\n now,\n ],\n });\n });\n\n return {\n id,\n appId: options.appId,\n ownerEmail: options.ownerEmail,\n name: options.name,\n columns,\n rowCount: allRows.length,\n byteSize,\n createdAt: now,\n updatedAt: now,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Read\n// ---------------------------------------------------------------------------\n\n/**\n * Fetch all rows for a dataset, asserting scope (appId + ownerEmail).\n */\nexport async function getStagedDatasetRows(options: {\n id: string;\n appId: string;\n ownerEmail: string;\n}): Promise<Record<string, unknown>[]> {\n await ensureTables();\n const db = getDbExec();\n // Scope check\n const { rows: meta } = await db.execute({\n sql: `SELECT id FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n if (meta.length === 0) return [];\n\n const { rows } = await db.execute({\n sql: `SELECT row_data FROM staged_dataset_rows WHERE dataset_id = ? ORDER BY row_index ASC`,\n args: [options.id],\n });\n return rows.map(\n (r) => JSON.parse(r.row_data as string) as Record<string, unknown>,\n );\n}\n\n/**\n * Get dataset metadata (no rows), asserting scope.\n */\nexport async function getStagedDatasetMeta(options: {\n id: string;\n appId: string;\n ownerEmail: string;\n}): Promise<StagedDatasetMeta | null> {\n await ensureTables();\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n if (rows.length === 0) return null;\n return rowToMeta(rows[0]);\n}\n\n/**\n * List all datasets scoped to (appId, ownerEmail), newest first.\n */\nexport async function listStagedDatasets(options: {\n appId: string;\n ownerEmail: string;\n}): Promise<StagedDatasetMeta[]> {\n await ensureTables();\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at FROM staged_datasets WHERE app_id = ? AND owner_email = ? ORDER BY updated_at DESC`,\n args: [options.appId, options.ownerEmail],\n });\n return rows.map(rowToMeta);\n}\n\n// ---------------------------------------------------------------------------\n// Delete\n// ---------------------------------------------------------------------------\n\nexport async function deleteStagedDataset(options: {\n id: string;\n appId: string;\n ownerEmail: string;\n}): Promise<boolean> {\n await ensureTables();\n const db = getDbExec();\n // Scope check\n const { rows: meta } = await db.execute({\n sql: `SELECT id FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n if (meta.length === 0) return false;\n\n const result = await withDbTransaction(db, async (tx) => {\n await tx.execute({\n sql: `DELETE FROM staged_dataset_rows WHERE dataset_id = ?`,\n args: [options.id],\n });\n return tx.execute({\n sql: `DELETE FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n });\n return result.rowsAffected > 0;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction rowToMeta(row: Record<string, unknown>): StagedDatasetMeta {\n return {\n id: row.id as string,\n appId: row.app_id as string,\n ownerEmail: row.owner_email as string,\n name: row.name as string,\n columns: JSON.parse(row.columns as string) as string[],\n rowCount: Number(row.row_count),\n byteSize: Number(row.byte_size),\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n };\n}\n\nasync function withDbTransaction<T>(\n db: DbExec,\n fn: (tx: DbExec) => Promise<T>,\n): Promise<T> {\n if (db.transaction) return db.transaction(fn);\n\n await db.execute(\"BEGIN\");\n try {\n const result = await fn(db);\n await db.execute(\"COMMIT\");\n return result;\n } catch (err) {\n await db.execute(\"ROLLBACK\").catch(() => {});\n throw err;\n }\n}\n\n/** Reset the init promise (only used in tests). */\nexport function _resetInitPromiseForTests(): void {\n _initPromise = undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"staged-datasets-store.js","sourceRoot":"","sources":["../../src/provider-api/staged-datasets-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Scratch storage for staged provider-API datasets.\n *\n * Rows are stored as JSON text — no dialect-specific JSON-column types needed.\n * Aggregation is done in TypeScript server-side (portable across Postgres and\n * SQLite) rather than via JSON SQL fragments. See `staged-datasets-aggregate.ts`.\n *\n * Storage caps:\n * - MAX_ROWS_PER_APP: 200 000 rows\n * - MAX_BYTES_PER_APP: 50 MB (approximate, measured as raw JSON text length)\n *\n * Scoping: datasets are owned by (app_id, owner_email) so different apps or\n * different users never share or cross-read each other's scratch data.\n */\n\nimport { getDbExec, intType, isPostgres, type DbExec } from \"../db/client.js\";\nimport { ensureTableExists, ensureIndexExists } from \"../db/ddl-guard.js\";\n\n// ---------------------------------------------------------------------------\n// Caps\n// ---------------------------------------------------------------------------\nexport const MAX_ROWS_PER_APP = 200_000;\nexport const MAX_BYTES_PER_APP = 50 * 1024 * 1024; // 50 MB\n\n// ---------------------------------------------------------------------------\n// Table initialisation\n// ---------------------------------------------------------------------------\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const db = getDbExec();\n const integerType = intType();\n const createDatasetsSql = `\n CREATE TABLE IF NOT EXISTS staged_datasets (\n id TEXT NOT NULL,\n app_id TEXT NOT NULL,\n owner_email TEXT NOT NULL,\n name TEXT NOT NULL,\n columns TEXT NOT NULL,\n row_count ${integerType} NOT NULL DEFAULT 0,\n byte_size ${integerType} NOT NULL DEFAULT 0,\n created_at ${integerType} NOT NULL,\n updated_at ${integerType} NOT NULL,\n PRIMARY KEY (id)\n )\n `;\n const createRowsSql = `\n CREATE TABLE IF NOT EXISTS staged_dataset_rows (\n dataset_id TEXT NOT NULL,\n row_index ${integerType} NOT NULL,\n row_data TEXT NOT NULL,\n PRIMARY KEY (dataset_id, row_index)\n )\n `;\n if (isPostgres()) {\n // PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout\n await ensureTableExists(\"staged_datasets\", createDatasetsSql);\n await ensureTableExists(\"staged_dataset_rows\", createRowsSql);\n await widenPostgresIntegerColumns(db); // best-effort type widening — unchanged\n await ensureIndexExists(\n \"staged_datasets_scope_idx\",\n `CREATE INDEX IF NOT EXISTS staged_datasets_scope_idx ON staged_datasets (app_id, owner_email)`,\n );\n await ensureIndexExists(\n \"staged_dataset_rows_dataset_idx\",\n `CREATE INDEX IF NOT EXISTS staged_dataset_rows_dataset_idx ON staged_dataset_rows (dataset_id)`,\n );\n return;\n }\n // SQLite (local dev): keep existing behavior\n await db.execute(createDatasetsSql);\n await db.execute(createRowsSql);\n // Note: widenPostgresIntegerColumns is Postgres-only, skip on SQLite\n for (const ddl of [\n `CREATE INDEX IF NOT EXISTS staged_datasets_scope_idx ON staged_datasets (app_id, owner_email)`,\n `CREATE INDEX IF NOT EXISTS staged_dataset_rows_dataset_idx ON staged_dataset_rows (dataset_id)`,\n ]) {\n try {\n await db.execute(ddl);\n } catch {\n // Index already exists — harmless.\n }\n }\n })().catch((err) => {\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nasync function widenPostgresIntegerColumns(db: DbExec): Promise<void> {\n const statements = [\n `ALTER TABLE staged_datasets ALTER COLUMN row_count TYPE BIGINT USING row_count::bigint`,\n `ALTER TABLE staged_datasets ALTER COLUMN byte_size TYPE BIGINT USING byte_size::bigint`,\n `ALTER TABLE staged_datasets ALTER COLUMN created_at TYPE BIGINT USING created_at::bigint`,\n `ALTER TABLE staged_datasets ALTER COLUMN updated_at TYPE BIGINT USING updated_at::bigint`,\n `ALTER TABLE staged_dataset_rows ALTER COLUMN row_index TYPE BIGINT USING row_index::bigint`,\n ];\n for (const sql of statements) {\n try {\n await db.execute(sql);\n } catch {\n // Best-effort compatibility for older deployments. Widening is\n // non-destructive; if a database role cannot ALTER, the later write will\n // still surface the real DB error.\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface StagedDatasetMeta {\n id: string;\n appId: string;\n ownerEmail: string;\n name: string;\n columns: string[];\n rowCount: number;\n byteSize: number;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface UpsertDatasetOptions {\n id: string;\n appId: string;\n ownerEmail: string;\n name: string;\n /** All rows to store; replaces any existing rows. */\n rows: Record<string, unknown>[];\n columns: string[];\n /** When true, append rows instead of replacing. */\n append?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generateId(): string {\n return `ds_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/** Derive column names from a set of rows (first 20 rows surveyed). */\nexport function deriveColumns(rows: Record<string, unknown>[]): string[] {\n const seen = new Set<string>();\n for (const row of rows.slice(0, 20)) {\n for (const key of Object.keys(row)) seen.add(key);\n }\n return Array.from(seen);\n}\n\n// ---------------------------------------------------------------------------\n// Scope check\n// ---------------------------------------------------------------------------\n\nasync function getAppRowCount(appId: string): Promise<number> {\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT COALESCE(SUM(row_count), 0) as total FROM staged_datasets WHERE app_id = ?`,\n args: [appId],\n });\n return Number(rows[0]?.total ?? 0);\n}\n\nasync function getAppByteSize(appId: string): Promise<number> {\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT COALESCE(SUM(byte_size), 0) as total FROM staged_datasets WHERE app_id = ?`,\n args: [appId],\n });\n return Number(rows[0]?.total ?? 0);\n}\n\n// ---------------------------------------------------------------------------\n// Write\n// ---------------------------------------------------------------------------\n\n/**\n * Create or replace a staged dataset. Returns metadata including the\n * resolved dataset ID (generated when not supplied in options).\n */\nexport async function upsertStagedDataset(\n options: UpsertDatasetOptions,\n): Promise<StagedDatasetMeta> {\n await ensureTables();\n const db = getDbExec();\n const now = Date.now();\n const id = options.id || generateId();\n\n // If appending, load existing rows first.\n let existingRows: Record<string, unknown>[] = [];\n if (options.append) {\n existingRows = await getStagedDatasetRows({\n id,\n appId: options.appId,\n ownerEmail: options.ownerEmail,\n });\n }\n\n const allRows = options.append\n ? [...existingRows, ...options.rows]\n : options.rows;\n\n // Check caps (net new count after this write).\n const currentAppRows = await getAppRowCount(options.appId);\n const currentDatasetRows = options.append\n ? existingRows.length\n : await (async () => {\n const { rows } = await db.execute({\n sql: `SELECT row_count FROM staged_datasets WHERE id = ?`,\n args: [id],\n });\n return Number(rows[0]?.row_count ?? 0);\n })();\n const netNewRows = allRows.length - currentDatasetRows;\n if (currentAppRows + netNewRows > MAX_ROWS_PER_APP) {\n throw new Error(\n `Staged dataset cap exceeded: this app already has ${currentAppRows} rows stored ` +\n `(limit ${MAX_ROWS_PER_APP}). Delete older datasets before staging more data.`,\n );\n }\n\n // Serialize rows and measure byte size.\n const serialized = allRows.map((row) => JSON.stringify(row));\n const byteSize = serialized.reduce((sum, s) => sum + s.length, 0);\n\n const currentAppBytes = await getAppByteSize(options.appId);\n const existingDatasetBytes = options.append\n ? await (async () => {\n const { rows } = await db.execute({\n sql: `SELECT byte_size FROM staged_datasets WHERE id = ?`,\n args: [id],\n });\n return Number(rows[0]?.byte_size ?? 0);\n })()\n : 0;\n const netNewBytes = byteSize - existingDatasetBytes;\n if (currentAppBytes + netNewBytes > MAX_BYTES_PER_APP) {\n throw new Error(\n `Staged dataset byte cap exceeded: this app already stores ` +\n `${(currentAppBytes / 1024 / 1024).toFixed(1)} MB (limit 50 MB). ` +\n `Delete older datasets before staging more data.`,\n );\n }\n\n const columns = options.columns.length\n ? options.columns\n : deriveColumns(allRows);\n const columnsJson = JSON.stringify(columns);\n\n await withDbTransaction(db, async (tx) => {\n // Delete old rows and insert the replacement row set atomically with the\n // metadata update so a failed batch cannot leave an empty or partial dataset.\n await tx.execute({\n sql: `DELETE FROM staged_dataset_rows WHERE dataset_id = ?`,\n args: [id],\n });\n\n const BATCH = 500;\n for (let i = 0; i < serialized.length; i += BATCH) {\n const slice = serialized.slice(i, i + BATCH);\n for (let j = 0; j < slice.length; j++) {\n await tx.execute({\n sql: `INSERT INTO staged_dataset_rows (dataset_id, row_index, row_data) VALUES (?, ?, ?)`,\n args: [id, i + j, slice[j]],\n });\n }\n }\n\n await tx.execute({\n sql: isPostgres()\n ? `INSERT INTO staged_datasets (id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name, columns=EXCLUDED.columns, row_count=EXCLUDED.row_count, byte_size=EXCLUDED.byte_size, updated_at=EXCLUDED.updated_at`\n : `INSERT OR REPLACE INTO staged_datasets (id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n options.appId,\n options.ownerEmail,\n options.name,\n columnsJson,\n allRows.length,\n byteSize,\n now,\n now,\n ],\n });\n });\n\n return {\n id,\n appId: options.appId,\n ownerEmail: options.ownerEmail,\n name: options.name,\n columns,\n rowCount: allRows.length,\n byteSize,\n createdAt: now,\n updatedAt: now,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Read\n// ---------------------------------------------------------------------------\n\n/**\n * Fetch all rows for a dataset, asserting scope (appId + ownerEmail).\n */\nexport async function getStagedDatasetRows(options: {\n id: string;\n appId: string;\n ownerEmail: string;\n}): Promise<Record<string, unknown>[]> {\n await ensureTables();\n const db = getDbExec();\n // Scope check\n const { rows: meta } = await db.execute({\n sql: `SELECT id FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n if (meta.length === 0) return [];\n\n const { rows } = await db.execute({\n sql: `SELECT row_data FROM staged_dataset_rows WHERE dataset_id = ? ORDER BY row_index ASC`,\n args: [options.id],\n });\n return rows.map(\n (r) => JSON.parse(r.row_data as string) as Record<string, unknown>,\n );\n}\n\n/**\n * Get dataset metadata (no rows), asserting scope.\n */\nexport async function getStagedDatasetMeta(options: {\n id: string;\n appId: string;\n ownerEmail: string;\n}): Promise<StagedDatasetMeta | null> {\n await ensureTables();\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n if (rows.length === 0) return null;\n return rowToMeta(rows[0]);\n}\n\n/**\n * List all datasets scoped to (appId, ownerEmail), newest first.\n */\nexport async function listStagedDatasets(options: {\n appId: string;\n ownerEmail: string;\n}): Promise<StagedDatasetMeta[]> {\n await ensureTables();\n const db = getDbExec();\n const { rows } = await db.execute({\n sql: `SELECT id, app_id, owner_email, name, columns, row_count, byte_size, created_at, updated_at FROM staged_datasets WHERE app_id = ? AND owner_email = ? ORDER BY updated_at DESC`,\n args: [options.appId, options.ownerEmail],\n });\n return rows.map(rowToMeta);\n}\n\n// ---------------------------------------------------------------------------\n// Delete\n// ---------------------------------------------------------------------------\n\nexport async function deleteStagedDataset(options: {\n id: string;\n appId: string;\n ownerEmail: string;\n}): Promise<boolean> {\n await ensureTables();\n const db = getDbExec();\n // Scope check\n const { rows: meta } = await db.execute({\n sql: `SELECT id FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n if (meta.length === 0) return false;\n\n const result = await withDbTransaction(db, async (tx) => {\n await tx.execute({\n sql: `DELETE FROM staged_dataset_rows WHERE dataset_id = ?`,\n args: [options.id],\n });\n return tx.execute({\n sql: `DELETE FROM staged_datasets WHERE id = ? AND app_id = ? AND owner_email = ?`,\n args: [options.id, options.appId, options.ownerEmail],\n });\n });\n return result.rowsAffected > 0;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction rowToMeta(row: Record<string, unknown>): StagedDatasetMeta {\n return {\n id: row.id as string,\n appId: row.app_id as string,\n ownerEmail: row.owner_email as string,\n name: row.name as string,\n columns: JSON.parse(row.columns as string) as string[],\n rowCount: Number(row.row_count),\n byteSize: Number(row.byte_size),\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n };\n}\n\nasync function withDbTransaction<T>(\n db: DbExec,\n fn: (tx: DbExec) => Promise<T>,\n): Promise<T> {\n if (db.transaction) return db.transaction(fn);\n\n await db.execute(\"BEGIN\");\n try {\n const result = await fn(db);\n await db.execute(\"COMMIT\");\n return result;\n } catch (err) {\n await db.execute(\"ROLLBACK\").catch(() => {});\n throw err;\n }\n}\n\n/** Reset the init promise (only used in tests). */\nexport function _resetInitPromiseForTests(): void {\n _initPromise = undefined;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/resources/store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/resources/store.ts"],"names":[],"mappings":"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"}
|
package/dist/resources/store.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
import { getDbExec, isPostgres, intType, retryOnDdlRace, } from "../db/client.js";
|
|
3
|
+
import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
3
4
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
4
5
|
import { canUseLocalWorkspaceResourcePath, deleteLocalWorkspaceResource, isLocalWorkspaceResourceId, isLocalWorkspaceResourcesEnabled, listLocalWorkspaceResources, localWorkspaceResourcePathFromId, readLocalWorkspaceResource, writeLocalWorkspaceResource, } from "../local-artifacts/index.js";
|
|
5
6
|
import { getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
|
|
@@ -532,31 +533,61 @@ async function ensureTable() {
|
|
|
532
533
|
}
|
|
533
534
|
async function _doEnsureTable() {
|
|
534
535
|
const client = getDbExec();
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
536
|
+
const createSql = `
|
|
537
|
+
CREATE TABLE IF NOT EXISTS resources (
|
|
538
|
+
id TEXT PRIMARY KEY,
|
|
539
|
+
path TEXT NOT NULL,
|
|
540
|
+
owner TEXT NOT NULL,
|
|
541
|
+
content TEXT NOT NULL DEFAULT '',
|
|
542
|
+
mime_type TEXT NOT NULL DEFAULT 'text/markdown',
|
|
543
|
+
size ${intType()} NOT NULL DEFAULT 0,
|
|
544
|
+
created_at ${intType()} NOT NULL,
|
|
545
|
+
updated_at ${intType()} NOT NULL,
|
|
546
|
+
created_by TEXT NOT NULL DEFAULT 'user',
|
|
547
|
+
visibility TEXT NOT NULL DEFAULT 'workspace',
|
|
548
|
+
thread_id TEXT,
|
|
549
|
+
run_id TEXT,
|
|
550
|
+
expires_at ${intType()},
|
|
551
|
+
metadata TEXT,
|
|
552
|
+
UNIQUE(path, owner)
|
|
553
|
+
)
|
|
554
|
+
`;
|
|
555
|
+
if (isPostgres()) {
|
|
556
|
+
// Hot path: the `resources` table and its additive columns are virtually
|
|
557
|
+
// always already present in production. Issuing `CREATE TABLE`/`ALTER
|
|
558
|
+
// TABLE` still takes an ACCESS EXCLUSIVE lock that, in a fresh
|
|
559
|
+
// background-worker process behind a concurrent connection on the shared
|
|
560
|
+
// Neon DB, can block ~indefinitely. The ensure* wrappers probe
|
|
561
|
+
// `information_schema` first (plain reads, no lock) and run DDL ONLY for
|
|
562
|
+
// what is actually missing, bounded by a transaction-scoped `lock_timeout`.
|
|
563
|
+
// If a swallowed lock-timeout leaves the schema still missing they RE-PROBE
|
|
564
|
+
// and THROW rather than letting init memoize success against absent schema.
|
|
565
|
+
await ensureTableExists("resources", createSql);
|
|
566
|
+
// Additive columns — guarded so the hot path (columns already present)
|
|
567
|
+
// skips the ACCESS EXCLUSIVE ALTER entirely.
|
|
568
|
+
const pgColumns = [
|
|
569
|
+
["created_by", "TEXT NOT NULL DEFAULT 'user'"],
|
|
570
|
+
["visibility", "TEXT NOT NULL DEFAULT 'workspace'"],
|
|
571
|
+
["thread_id", "TEXT"],
|
|
572
|
+
["run_id", "TEXT"],
|
|
573
|
+
["expires_at", intType()],
|
|
574
|
+
["metadata", "TEXT"],
|
|
575
|
+
];
|
|
576
|
+
for (const [col, def] of pgColumns) {
|
|
577
|
+
await ensureColumnExists("resources", col, `ALTER TABLE resources ADD COLUMN IF NOT EXISTS ${col} ${def}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
// SQLite (local dev): no lock problem — keep the original behaviour using
|
|
582
|
+
// `retryOnDdlRace` + `ensureResourceColumn` (duplicate-column catch).
|
|
583
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
584
|
+
await ensureResourceColumn(client, "created_by TEXT NOT NULL DEFAULT 'user'");
|
|
585
|
+
await ensureResourceColumn(client, "visibility TEXT NOT NULL DEFAULT 'workspace'");
|
|
586
|
+
await ensureResourceColumn(client, "thread_id TEXT");
|
|
587
|
+
await ensureResourceColumn(client, "run_id TEXT");
|
|
588
|
+
await ensureResourceColumn(client, `expires_at ${intType()}`);
|
|
589
|
+
await ensureResourceColumn(client, "metadata TEXT");
|
|
590
|
+
}
|
|
560
591
|
// Older deployments have 32-bit timestamp columns; on Postgres the
|
|
561
592
|
// `Date.now()` written on insert/update overflows int4. Widen in place
|
|
562
593
|
// (no-op once done / on fresh DBs).
|