@agent-native/core 0.77.7 → 0.77.10
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 +2 -2
- package/corpus/core/CHANGELOG.md +46 -0
- package/corpus/core/package.json +1 -1
- 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/production-agent.ts +18 -0
- 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/storage.ts +20 -2
- package/corpus/core/src/db/ddl-guard.ts +302 -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 +32 -2
- 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 +35 -6
- 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/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/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +18 -0
- package/dist/agent/production-agent.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/routes.d.ts +2 -2
- 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 +151 -0
- package/dist/db/ddl-guard.d.ts.map +1 -0
- package/dist/db/ddl-guard.js +265 -0
- package/dist/db/ddl-guard.js.map +1 -0
- 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/file-upload/actions/upload-image.d.ts +2 -2
- 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/routes.d.ts +2 -2
- 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/routes.d.ts +7 -7
- 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/handlers.d.ts +2 -2
- 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 +22 -2
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +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/server/transcribe-voice.d.ts +1 -1
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +30 -6
- 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 +1 -1
|
@@ -3,10 +3,11 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import {
|
|
4
4
|
getDbExec,
|
|
5
5
|
intType,
|
|
6
|
+
isPostgres,
|
|
6
7
|
isUniqueViolation,
|
|
7
|
-
retryOnDdlRace,
|
|
8
8
|
safeJsonParse,
|
|
9
9
|
} from "../db/client.js";
|
|
10
|
+
import { ensureIndexExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
10
11
|
import { recordChange } from "../server/poll.js";
|
|
11
12
|
import type {
|
|
12
13
|
AgentRun,
|
|
@@ -42,32 +43,46 @@ async function ensureTable(): Promise<void> {
|
|
|
42
43
|
if (!_initPromise) {
|
|
43
44
|
_initPromise = (async () => {
|
|
44
45
|
const client = getDbExec();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
46
|
+
const createSql = `
|
|
47
|
+
CREATE TABLE IF NOT EXISTS progress_runs (
|
|
48
|
+
id TEXT PRIMARY KEY,
|
|
49
|
+
owner TEXT NOT NULL,
|
|
50
|
+
title TEXT NOT NULL,
|
|
51
|
+
step TEXT,
|
|
52
|
+
percent ${intType()},
|
|
53
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
54
|
+
metadata TEXT,
|
|
55
|
+
started_at ${intType()} NOT NULL,
|
|
56
|
+
updated_at ${intType()} NOT NULL,
|
|
57
|
+
completed_at ${intType()}
|
|
58
|
+
)
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
if (isPostgres()) {
|
|
62
|
+
// PG-guard: probe information_schema / pg_indexes before issuing DDL to
|
|
63
|
+
// avoid ACCESS EXCLUSIVE lock contention in fresh background-worker processes.
|
|
64
|
+
await ensureTableExists("progress_runs", createSql);
|
|
65
|
+
await ensureIndexExists(
|
|
66
|
+
"idx_progress_runs_owner_status",
|
|
63
67
|
`CREATE INDEX IF NOT EXISTS idx_progress_runs_owner_status ON progress_runs (owner, status, started_at)`,
|
|
64
|
-
)
|
|
65
|
-
|
|
68
|
+
);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// SQLite (local dev): no lock problem — keep the original behaviour.
|
|
66
73
|
// NOTE: table name is `progress_runs` (not `agent_runs`) to avoid
|
|
67
74
|
// colliding with core's existing agent/run-store.ts which uses
|
|
68
75
|
// `agent_runs` for agent-chat turn lifecycle tracking. These are
|
|
69
76
|
// separate concerns — progress = user-facing task status, agent_runs =
|
|
70
77
|
// internal chat turn bookkeeping.
|
|
78
|
+
await client.execute(createSql);
|
|
79
|
+
try {
|
|
80
|
+
await client.execute(
|
|
81
|
+
`CREATE INDEX IF NOT EXISTS idx_progress_runs_owner_status ON progress_runs (owner, status, started_at)`,
|
|
82
|
+
);
|
|
83
|
+
} catch {
|
|
84
|
+
// Index already exists or the dialect rejected a duplicate.
|
|
85
|
+
}
|
|
71
86
|
})().catch((err) => {
|
|
72
87
|
// Reset on failure so a transient DB outage doesn't poison the cached
|
|
73
88
|
// promise and reject every future insert/update call for the lifetime
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { getDbExec, intType, isPostgres, type DbExec } from "../db/client.js";
|
|
11
|
+
import { ensureTableExists, ensureIndexExists } from "../db/ddl-guard.js";
|
|
11
12
|
|
|
12
13
|
export type ProviderCorpusJobStatus =
|
|
13
14
|
| "running"
|
|
@@ -81,7 +82,7 @@ async function ensureTables(): Promise<void> {
|
|
|
81
82
|
initPromise = (async () => {
|
|
82
83
|
const db = getDbExec();
|
|
83
84
|
const integerType = intType();
|
|
84
|
-
|
|
85
|
+
const createJobsSql = `
|
|
85
86
|
CREATE TABLE IF NOT EXISTS provider_corpus_jobs (
|
|
86
87
|
id TEXT NOT NULL,
|
|
87
88
|
app_id TEXT NOT NULL,
|
|
@@ -108,18 +109,37 @@ async function ensureTables(): Promise<void> {
|
|
|
108
109
|
updated_at ${integerType} NOT NULL,
|
|
109
110
|
PRIMARY KEY (id)
|
|
110
111
|
)
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
`;
|
|
113
|
+
const createHitsSql = `
|
|
113
114
|
CREATE TABLE IF NOT EXISTS provider_corpus_job_hits (
|
|
114
115
|
job_id TEXT NOT NULL,
|
|
115
116
|
hit_index ${integerType} NOT NULL,
|
|
116
117
|
hit_data TEXT NOT NULL,
|
|
117
118
|
PRIMARY KEY (job_id, hit_index)
|
|
118
119
|
)
|
|
119
|
-
|
|
120
|
+
`;
|
|
120
121
|
if (isPostgres()) {
|
|
121
|
-
|
|
122
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
123
|
+
await ensureTableExists("provider_corpus_jobs", createJobsSql);
|
|
124
|
+
await ensureTableExists("provider_corpus_job_hits", createHitsSql);
|
|
125
|
+
await widenPostgresIntegerColumns(db); // best-effort type widening — unchanged
|
|
126
|
+
await ensureIndexExists(
|
|
127
|
+
"provider_corpus_jobs_scope_idx",
|
|
128
|
+
`CREATE INDEX IF NOT EXISTS provider_corpus_jobs_scope_idx ON provider_corpus_jobs (app_id, owner_email, updated_at)`,
|
|
129
|
+
);
|
|
130
|
+
await ensureIndexExists(
|
|
131
|
+
"provider_corpus_jobs_status_idx",
|
|
132
|
+
`CREATE INDEX IF NOT EXISTS provider_corpus_jobs_status_idx ON provider_corpus_jobs (app_id, owner_email, status)`,
|
|
133
|
+
);
|
|
134
|
+
await ensureIndexExists(
|
|
135
|
+
"provider_corpus_job_hits_job_idx",
|
|
136
|
+
`CREATE INDEX IF NOT EXISTS provider_corpus_job_hits_job_idx ON provider_corpus_job_hits (job_id)`,
|
|
137
|
+
);
|
|
138
|
+
return;
|
|
122
139
|
}
|
|
140
|
+
// SQLite (local dev): keep existing behavior
|
|
141
|
+
await db.execute(createJobsSql);
|
|
142
|
+
await db.execute(createHitsSql);
|
|
123
143
|
for (const ddl of [
|
|
124
144
|
`CREATE INDEX IF NOT EXISTS provider_corpus_jobs_scope_idx ON provider_corpus_jobs (app_id, owner_email, updated_at)`,
|
|
125
145
|
`CREATE INDEX IF NOT EXISTS provider_corpus_jobs_status_idx ON provider_corpus_jobs (app_id, owner_email, status)`,
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { getDbExec, isPostgres } from "../db/client.js";
|
|
24
|
+
import { ensureTableExists } from "../db/ddl-guard.js";
|
|
24
25
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
25
26
|
import { isBlockedExtensionUrlWithDns } from "../extensions/url-safety.js";
|
|
26
27
|
|
|
@@ -91,10 +92,20 @@ async function ensureTable(): Promise<void> {
|
|
|
91
92
|
if (!_initPromise) {
|
|
92
93
|
_initPromise = (async () => {
|
|
93
94
|
const client = getDbExec();
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
|
|
96
|
+
if (isPostgres()) {
|
|
97
|
+
const pgSql = CREATE_SQL.replace(/\bINTEGER\b/g, "BIGINT");
|
|
98
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
99
|
+
await ensureTableExists("custom_api_providers", pgSql);
|
|
100
|
+
// Widen any pre-existing int4 timestamp columns to BIGINT (no-op once done)
|
|
101
|
+
await widenIntColumnsToBigInt("custom_api_providers", [
|
|
102
|
+
"created_at",
|
|
103
|
+
"updated_at",
|
|
104
|
+
]);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// SQLite (local dev): keep existing behavior
|
|
108
|
+
await client.execute(CREATE_SQL);
|
|
98
109
|
// Fresh Postgres tables get BIGINT via the replace above, but tables
|
|
99
110
|
// created before that compat existed kept int4 timestamp columns; widen
|
|
100
111
|
// them so `Date.now()` writes don't overflow. No-op once done.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
3
|
import type { CredentialContext } from "../credentials/index.js";
|
|
4
|
-
import { getDbExec, intType } from "../db/client.js";
|
|
4
|
+
import { getDbExec, intType, isPostgres } from "../db/client.js";
|
|
5
|
+
import { ensureTableExists, ensureIndexExists } from "../db/ddl-guard.js";
|
|
5
6
|
|
|
6
7
|
export interface ProviderQuotaIdentityInput {
|
|
7
8
|
appId: string;
|
|
@@ -398,7 +399,7 @@ async function ensureCooldownTable(): Promise<void> {
|
|
|
398
399
|
state.initPromise = (async () => {
|
|
399
400
|
const db = getDbExec();
|
|
400
401
|
const integerType = intType();
|
|
401
|
-
|
|
402
|
+
const createSql = `
|
|
402
403
|
CREATE TABLE IF NOT EXISTS provider_api_cooldowns (
|
|
403
404
|
quota_key TEXT NOT NULL,
|
|
404
405
|
provider_id TEXT NOT NULL,
|
|
@@ -409,7 +410,18 @@ async function ensureCooldownTable(): Promise<void> {
|
|
|
409
410
|
updated_at ${integerType} NOT NULL,
|
|
410
411
|
PRIMARY KEY (quota_key)
|
|
411
412
|
)
|
|
412
|
-
|
|
413
|
+
`;
|
|
414
|
+
if (isPostgres()) {
|
|
415
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
416
|
+
await ensureTableExists("provider_api_cooldowns", createSql);
|
|
417
|
+
await ensureIndexExists(
|
|
418
|
+
"provider_api_cooldowns_provider_idx",
|
|
419
|
+
`CREATE INDEX IF NOT EXISTS provider_api_cooldowns_provider_idx ON provider_api_cooldowns (provider_id, cooldown_until)`,
|
|
420
|
+
);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
// SQLite (local dev): keep existing behavior
|
|
424
|
+
await db.execute(createSql);
|
|
413
425
|
try {
|
|
414
426
|
await db.execute(
|
|
415
427
|
`CREATE INDEX IF NOT EXISTS provider_api_cooldowns_provider_idx ON provider_api_cooldowns (provider_id, cooldown_until)`,
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { getDbExec, intType, isPostgres, type DbExec } from "../db/client.js";
|
|
17
|
+
import { ensureTableExists, ensureIndexExists } from "../db/ddl-guard.js";
|
|
17
18
|
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Caps
|
|
@@ -32,7 +33,7 @@ async function ensureTables(): Promise<void> {
|
|
|
32
33
|
_initPromise = (async () => {
|
|
33
34
|
const db = getDbExec();
|
|
34
35
|
const integerType = intType();
|
|
35
|
-
|
|
36
|
+
const createDatasetsSql = `
|
|
36
37
|
CREATE TABLE IF NOT EXISTS staged_datasets (
|
|
37
38
|
id TEXT NOT NULL,
|
|
38
39
|
app_id TEXT NOT NULL,
|
|
@@ -45,18 +46,34 @@ async function ensureTables(): Promise<void> {
|
|
|
45
46
|
updated_at ${integerType} NOT NULL,
|
|
46
47
|
PRIMARY KEY (id)
|
|
47
48
|
)
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
`;
|
|
50
|
+
const createRowsSql = `
|
|
50
51
|
CREATE TABLE IF NOT EXISTS staged_dataset_rows (
|
|
51
52
|
dataset_id TEXT NOT NULL,
|
|
52
53
|
row_index ${integerType} NOT NULL,
|
|
53
54
|
row_data TEXT NOT NULL,
|
|
54
55
|
PRIMARY KEY (dataset_id, row_index)
|
|
55
56
|
)
|
|
56
|
-
|
|
57
|
+
`;
|
|
57
58
|
if (isPostgres()) {
|
|
58
|
-
|
|
59
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
60
|
+
await ensureTableExists("staged_datasets", createDatasetsSql);
|
|
61
|
+
await ensureTableExists("staged_dataset_rows", createRowsSql);
|
|
62
|
+
await widenPostgresIntegerColumns(db); // best-effort type widening — unchanged
|
|
63
|
+
await ensureIndexExists(
|
|
64
|
+
"staged_datasets_scope_idx",
|
|
65
|
+
`CREATE INDEX IF NOT EXISTS staged_datasets_scope_idx ON staged_datasets (app_id, owner_email)`,
|
|
66
|
+
);
|
|
67
|
+
await ensureIndexExists(
|
|
68
|
+
"staged_dataset_rows_dataset_idx",
|
|
69
|
+
`CREATE INDEX IF NOT EXISTS staged_dataset_rows_dataset_idx ON staged_dataset_rows (dataset_id)`,
|
|
70
|
+
);
|
|
71
|
+
return;
|
|
59
72
|
}
|
|
73
|
+
// SQLite (local dev): keep existing behavior
|
|
74
|
+
await db.execute(createDatasetsSql);
|
|
75
|
+
await db.execute(createRowsSql);
|
|
76
|
+
// Note: widenPostgresIntegerColumns is Postgres-only, skip on SQLite
|
|
60
77
|
for (const ddl of [
|
|
61
78
|
`CREATE INDEX IF NOT EXISTS staged_datasets_scope_idx ON staged_datasets (app_id, owner_email)`,
|
|
62
79
|
`CREATE INDEX IF NOT EXISTS staged_dataset_rows_dataset_idx ON staged_dataset_rows (dataset_id)`,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
retryOnDdlRace,
|
|
8
8
|
type DbExec,
|
|
9
9
|
} from "../db/client.js";
|
|
10
|
+
import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
10
11
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
11
12
|
import {
|
|
12
13
|
canUseLocalWorkspaceResourcePath,
|
|
@@ -751,37 +752,71 @@ async function ensureTable(): Promise<void> {
|
|
|
751
752
|
|
|
752
753
|
async function _doEnsureTable(): Promise<void> {
|
|
753
754
|
const client = getDbExec();
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
)
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
755
|
+
const createSql = `
|
|
756
|
+
CREATE TABLE IF NOT EXISTS resources (
|
|
757
|
+
id TEXT PRIMARY KEY,
|
|
758
|
+
path TEXT NOT NULL,
|
|
759
|
+
owner TEXT NOT NULL,
|
|
760
|
+
content TEXT NOT NULL DEFAULT '',
|
|
761
|
+
mime_type TEXT NOT NULL DEFAULT 'text/markdown',
|
|
762
|
+
size ${intType()} NOT NULL DEFAULT 0,
|
|
763
|
+
created_at ${intType()} NOT NULL,
|
|
764
|
+
updated_at ${intType()} NOT NULL,
|
|
765
|
+
created_by TEXT NOT NULL DEFAULT 'user',
|
|
766
|
+
visibility TEXT NOT NULL DEFAULT 'workspace',
|
|
767
|
+
thread_id TEXT,
|
|
768
|
+
run_id TEXT,
|
|
769
|
+
expires_at ${intType()},
|
|
770
|
+
metadata TEXT,
|
|
771
|
+
UNIQUE(path, owner)
|
|
772
|
+
)
|
|
773
|
+
`;
|
|
774
|
+
|
|
775
|
+
if (isPostgres()) {
|
|
776
|
+
// Hot path: the `resources` table and its additive columns are virtually
|
|
777
|
+
// always already present in production. Issuing `CREATE TABLE`/`ALTER
|
|
778
|
+
// TABLE` still takes an ACCESS EXCLUSIVE lock that, in a fresh
|
|
779
|
+
// background-worker process behind a concurrent connection on the shared
|
|
780
|
+
// Neon DB, can block ~indefinitely. The ensure* wrappers probe
|
|
781
|
+
// `information_schema` first (plain reads, no lock) and run DDL ONLY for
|
|
782
|
+
// what is actually missing, bounded by a transaction-scoped `lock_timeout`.
|
|
783
|
+
// If a swallowed lock-timeout leaves the schema still missing they RE-PROBE
|
|
784
|
+
// and THROW rather than letting init memoize success against absent schema.
|
|
785
|
+
await ensureTableExists("resources", createSql);
|
|
786
|
+
// Additive columns — guarded so the hot path (columns already present)
|
|
787
|
+
// skips the ACCESS EXCLUSIVE ALTER entirely.
|
|
788
|
+
const pgColumns: Array<[string, string]> = [
|
|
789
|
+
["created_by", "TEXT NOT NULL DEFAULT 'user'"],
|
|
790
|
+
["visibility", "TEXT NOT NULL DEFAULT 'workspace'"],
|
|
791
|
+
["thread_id", "TEXT"],
|
|
792
|
+
["run_id", "TEXT"],
|
|
793
|
+
["expires_at", intType()],
|
|
794
|
+
["metadata", "TEXT"],
|
|
795
|
+
];
|
|
796
|
+
for (const [col, def] of pgColumns) {
|
|
797
|
+
await ensureColumnExists(
|
|
798
|
+
"resources",
|
|
799
|
+
col,
|
|
800
|
+
`ALTER TABLE resources ADD COLUMN IF NOT EXISTS ${col} ${def}`,
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
} else {
|
|
804
|
+
// SQLite (local dev): no lock problem — keep the original behaviour using
|
|
805
|
+
// `retryOnDdlRace` + `ensureResourceColumn` (duplicate-column catch).
|
|
806
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
807
|
+
await ensureResourceColumn(
|
|
808
|
+
client,
|
|
809
|
+
"created_by TEXT NOT NULL DEFAULT 'user'",
|
|
810
|
+
);
|
|
811
|
+
await ensureResourceColumn(
|
|
812
|
+
client,
|
|
813
|
+
"visibility TEXT NOT NULL DEFAULT 'workspace'",
|
|
814
|
+
);
|
|
815
|
+
await ensureResourceColumn(client, "thread_id TEXT");
|
|
816
|
+
await ensureResourceColumn(client, "run_id TEXT");
|
|
817
|
+
await ensureResourceColumn(client, `expires_at ${intType()}`);
|
|
818
|
+
await ensureResourceColumn(client, "metadata TEXT");
|
|
819
|
+
}
|
|
785
820
|
|
|
786
821
|
// Older deployments have 32-bit timestamp columns; on Postgres the
|
|
787
822
|
// `Date.now()` written on insert/update overflows int4. Widen in place
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
16
16
|
|
|
17
17
|
import { getDbExec, isPostgres } from "../db/client.js";
|
|
18
|
+
import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
18
19
|
import {
|
|
19
20
|
encryptSecretValue as encryptValue,
|
|
20
21
|
decryptSecretValue as decryptValue,
|
|
@@ -34,10 +35,39 @@ async function ensureTable(): Promise<void> {
|
|
|
34
35
|
const client = getDbExec();
|
|
35
36
|
// Postgres version of the CREATE TABLE — the generic `INTEGER` maps to
|
|
36
37
|
// BIGINT on Postgres, which we need for millisecond timestamps.
|
|
37
|
-
const
|
|
38
|
+
const createSql = isPostgres()
|
|
38
39
|
? APP_SECRETS_CREATE_SQL.replace(/\bINTEGER\b/g, "BIGINT")
|
|
39
40
|
: APP_SECRETS_CREATE_SQL;
|
|
40
|
-
|
|
41
|
+
|
|
42
|
+
if (isPostgres()) {
|
|
43
|
+
// Hot path: in production the table and both additive columns are
|
|
44
|
+
// virtually always already present. Issuing `CREATE`/`ALTER` would
|
|
45
|
+
// still take an ACCESS EXCLUSIVE lock — which, in a fresh background
|
|
46
|
+
// worker process behind a concurrent connection on the shared Neon DB,
|
|
47
|
+
// can block ~indefinitely. `ensureTableExists` / `ensureColumnExists`
|
|
48
|
+
// check `information_schema` first (a plain read, no lock) and run DDL
|
|
49
|
+
// ONLY for what is actually missing, wrapping any DDL that must run in a
|
|
50
|
+
// transaction-scoped `lock_timeout` so a contended lock fails fast. They
|
|
51
|
+
// also re-probe after a swallowed lock-timeout and THROW if the schema
|
|
52
|
+
// is still missing, so a timed-out DDL never poisons this init memo.
|
|
53
|
+
await ensureTableExists("app_secrets", createSql);
|
|
54
|
+
await ensureColumnExists(
|
|
55
|
+
"app_secrets",
|
|
56
|
+
"description",
|
|
57
|
+
`ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS description TEXT`,
|
|
58
|
+
);
|
|
59
|
+
await ensureColumnExists(
|
|
60
|
+
"app_secrets",
|
|
61
|
+
"url_allowlist",
|
|
62
|
+
`ALTER TABLE app_secrets ADD COLUMN IF NOT EXISTS url_allowlist TEXT`,
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// SQLite (local dev): no ACCESS EXCLUSIVE lock problem, keep the original
|
|
68
|
+
// create-then-additive-alter behaviour. SQLite has no
|
|
69
|
+
// `ADD COLUMN IF NOT EXISTS`, so the ALTERs stay wrapped in try/catch.
|
|
70
|
+
await client.execute(createSql);
|
|
41
71
|
|
|
42
72
|
// Additive migration: description column (for ad-hoc keys)
|
|
43
73
|
try {
|
|
@@ -14,7 +14,13 @@
|
|
|
14
14
|
* for UI/status; this table only drives dispatch, idempotent claiming, and
|
|
15
15
|
* cross-invocation continuation.
|
|
16
16
|
*/
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
getDbExec,
|
|
19
|
+
intType,
|
|
20
|
+
isPostgres,
|
|
21
|
+
retryOnDdlRace,
|
|
22
|
+
} from "../db/client.js";
|
|
23
|
+
import { ensureIndexExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
18
24
|
|
|
19
25
|
/** Max cross-invocation continuations for one sub-agent run. Each continuation
|
|
20
26
|
* is one ~40s soft-timeout chunk, so ~60 ≈ ~40 minutes of wall-clock work. Two
|
|
@@ -77,8 +83,7 @@ async function ensureTable(): Promise<void> {
|
|
|
77
83
|
if (!_initPromise) {
|
|
78
84
|
_initPromise = (async () => {
|
|
79
85
|
const client = getDbExec();
|
|
80
|
-
|
|
81
|
-
client.execute(`
|
|
86
|
+
const createSql = `
|
|
82
87
|
CREATE TABLE IF NOT EXISTS agent_team_run_queue (
|
|
83
88
|
task_id TEXT PRIMARY KEY,
|
|
84
89
|
thread_id TEXT NOT NULL,
|
|
@@ -92,13 +97,20 @@ async function ensureTable(): Promise<void> {
|
|
|
92
97
|
created_at ${intType()} NOT NULL,
|
|
93
98
|
updated_at ${intType()} NOT NULL
|
|
94
99
|
)
|
|
95
|
-
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
`;
|
|
101
|
+
const indexSql = `CREATE INDEX IF NOT EXISTS idx_agent_team_run_queue_status ON agent_team_run_queue (status, updated_at)`;
|
|
102
|
+
|
|
103
|
+
// PG guard: probe information_schema / pg_indexes first (no lock), run
|
|
104
|
+
// DDL only when missing, bounded by a transaction-scoped lock_timeout.
|
|
105
|
+
if (isPostgres()) {
|
|
106
|
+
await ensureTableExists("agent_team_run_queue", createSql);
|
|
107
|
+
await ensureIndexExists("idx_agent_team_run_queue_status", indexSql);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// SQLite (local dev): no lock problem — keep the original behaviour.
|
|
112
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
113
|
+
await retryOnDdlRace(() => client.execute(indexSql));
|
|
102
114
|
})().catch((err) => {
|
|
103
115
|
_initPromise = undefined;
|
|
104
116
|
throw err;
|
|
@@ -72,6 +72,7 @@ import {
|
|
|
72
72
|
retryOnDdlRace,
|
|
73
73
|
describeDbError,
|
|
74
74
|
} from "../db/client.js";
|
|
75
|
+
import { ensureColumnExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
75
76
|
import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
|
|
76
77
|
import { readBody } from "../server/h3-helpers.js";
|
|
77
78
|
import { putSetting } from "../settings/store.js";
|
|
@@ -865,15 +866,32 @@ async function ensureSessionTable(): Promise<void> {
|
|
|
865
866
|
if (!_sessionInitPromise) {
|
|
866
867
|
_sessionInitPromise = (async () => {
|
|
867
868
|
const client = getDbExec();
|
|
868
|
-
|
|
869
|
-
client.execute(`
|
|
869
|
+
const createSql = `
|
|
870
870
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
871
871
|
token TEXT PRIMARY KEY,
|
|
872
872
|
email TEXT,
|
|
873
873
|
created_at ${intType()} NOT NULL
|
|
874
874
|
)
|
|
875
|
-
|
|
876
|
-
|
|
875
|
+
`;
|
|
876
|
+
|
|
877
|
+
// PG guard: probe information_schema first (no lock), run DDL only when
|
|
878
|
+
// missing, bounded by a transaction-scoped lock_timeout.
|
|
879
|
+
if (isPostgres()) {
|
|
880
|
+
await ensureTableExists("sessions", createSql);
|
|
881
|
+
await ensureColumnExists(
|
|
882
|
+
"sessions",
|
|
883
|
+
"email",
|
|
884
|
+
`ALTER TABLE sessions ADD COLUMN IF NOT EXISTS email TEXT`,
|
|
885
|
+
);
|
|
886
|
+
// Older deployments have a 32-bit `created_at`; on Postgres the
|
|
887
|
+
// `Date.now()` written on session create overflows int4. Widen in place
|
|
888
|
+
// (no-op once done / on fresh DBs).
|
|
889
|
+
await widenIntColumnsToBigInt("sessions", ["created_at"]);
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// SQLite (local dev): no lock problem — keep the original behaviour.
|
|
894
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
877
895
|
try {
|
|
878
896
|
await client.execute(`ALTER TABLE sessions ADD COLUMN email TEXT`);
|
|
879
897
|
} catch {
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
neonPoolMax,
|
|
40
40
|
attachNeonPoolErrorLogger,
|
|
41
41
|
} from "../db/client.js";
|
|
42
|
+
import { ensureTableExists } from "../db/ddl-guard.js";
|
|
42
43
|
import { saveOAuthTokens } from "../oauth-tokens/store.js";
|
|
43
44
|
import { acceptPendingInvitationsForEmail } from "../org/accept-pending.js";
|
|
44
45
|
import { autoJoinDomainMatchingOrgs } from "../org/auto-join-domain.js";
|
|
@@ -693,29 +694,62 @@ async function mirrorGoogleAccountToOAuthTokens(account: {
|
|
|
693
694
|
|
|
694
695
|
async function ensureBetterAuthTables(): Promise<void> {
|
|
695
696
|
const db = getDbExec();
|
|
696
|
-
|
|
697
|
-
|
|
697
|
+
|
|
698
|
+
// PG guard: probe information_schema first (no lock) for each table; run
|
|
699
|
+
// DDL only when missing, bounded by a transaction-scoped lock_timeout.
|
|
700
|
+
// Probe names are UNQUOTED (what information_schema.tables.table_name stores);
|
|
701
|
+
// createSql keeps the QUOTED "user"/"session"/… form required by Postgres.
|
|
702
|
+
if (isPostgres()) {
|
|
703
|
+
const pgTables: Array<[name: string, createSql: string]> = [
|
|
704
|
+
[
|
|
705
|
+
"user",
|
|
698
706
|
`CREATE TABLE IF NOT EXISTS "user" (id TEXT PRIMARY KEY, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE, email_verified BOOLEAN NOT NULL DEFAULT FALSE, image TEXT, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL)`,
|
|
707
|
+
],
|
|
708
|
+
[
|
|
709
|
+
"session",
|
|
699
710
|
`CREATE TABLE IF NOT EXISTS "session" (id TEXT PRIMARY KEY, expires_at TIMESTAMPTZ NOT NULL, token TEXT NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, ip_address TEXT, user_agent TEXT, user_id TEXT NOT NULL, active_organization_id TEXT)`,
|
|
711
|
+
],
|
|
712
|
+
[
|
|
713
|
+
"account",
|
|
700
714
|
`CREATE TABLE IF NOT EXISTS "account" (id TEXT PRIMARY KEY, account_id TEXT NOT NULL, provider_id TEXT NOT NULL, user_id TEXT NOT NULL, access_token TEXT, refresh_token TEXT, id_token TEXT, access_token_expires_at TIMESTAMPTZ, refresh_token_expires_at TIMESTAMPTZ, scope TEXT, password TEXT, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL)`,
|
|
715
|
+
],
|
|
716
|
+
[
|
|
717
|
+
"verification",
|
|
701
718
|
`CREATE TABLE IF NOT EXISTS "verification" (id TEXT PRIMARY KEY, identifier TEXT NOT NULL, value TEXT NOT NULL, expires_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL)`,
|
|
719
|
+
],
|
|
720
|
+
[
|
|
721
|
+
"organization",
|
|
702
722
|
`CREATE TABLE IF NOT EXISTS "organization" (id TEXT PRIMARY KEY, name TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, logo TEXT, metadata TEXT, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL)`,
|
|
723
|
+
],
|
|
724
|
+
[
|
|
725
|
+
"member",
|
|
703
726
|
`CREATE TABLE IF NOT EXISTS "member" (id TEXT PRIMARY KEY, organization_id TEXT NOT NULL, user_id TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'member', created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL)`,
|
|
727
|
+
],
|
|
728
|
+
[
|
|
729
|
+
"invitation",
|
|
704
730
|
`CREATE TABLE IF NOT EXISTS "invitation" (id TEXT PRIMARY KEY, organization_id TEXT NOT NULL, email TEXT NOT NULL, role TEXT, status TEXT NOT NULL DEFAULT 'pending', expires_at TIMESTAMPTZ NOT NULL, inviter_id TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL)`,
|
|
731
|
+
],
|
|
732
|
+
[
|
|
733
|
+
"jwks",
|
|
705
734
|
`CREATE TABLE IF NOT EXISTS "jwks" (id TEXT PRIMARY KEY, public_key TEXT NOT NULL, private_key TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL, expires_at TIMESTAMPTZ)`,
|
|
706
|
-
]
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
735
|
+
],
|
|
736
|
+
];
|
|
737
|
+
for (const [name, sql] of pgTables) await ensureTableExists(name, sql);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// SQLite (local dev): no lock problem — keep the original behaviour.
|
|
742
|
+
const sqliteStatements = [
|
|
743
|
+
`CREATE TABLE IF NOT EXISTS user (id TEXT PRIMARY KEY, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE, email_verified INTEGER NOT NULL DEFAULT 0, image TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
744
|
+
`CREATE TABLE IF NOT EXISTS session (id TEXT PRIMARY KEY, expires_at INTEGER NOT NULL, token TEXT NOT NULL UNIQUE, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, ip_address TEXT, user_agent TEXT, user_id TEXT NOT NULL, active_organization_id TEXT)`,
|
|
745
|
+
`CREATE TABLE IF NOT EXISTS account (id TEXT PRIMARY KEY, account_id TEXT NOT NULL, provider_id TEXT NOT NULL, user_id TEXT NOT NULL, access_token TEXT, refresh_token TEXT, id_token TEXT, access_token_expires_at INTEGER, refresh_token_expires_at INTEGER, scope TEXT, password TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
746
|
+
`CREATE TABLE IF NOT EXISTS verification (id TEXT PRIMARY KEY, identifier TEXT NOT NULL, value TEXT NOT NULL, expires_at INTEGER NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
747
|
+
`CREATE TABLE IF NOT EXISTS organization (id TEXT PRIMARY KEY, name TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, logo TEXT, metadata TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
748
|
+
`CREATE TABLE IF NOT EXISTS member (id TEXT PRIMARY KEY, organization_id TEXT NOT NULL, user_id TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'member', created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
749
|
+
`CREATE TABLE IF NOT EXISTS invitation (id TEXT PRIMARY KEY, organization_id TEXT NOT NULL, email TEXT NOT NULL, role TEXT, status TEXT NOT NULL DEFAULT 'pending', expires_at INTEGER NOT NULL, inviter_id TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
750
|
+
`CREATE TABLE IF NOT EXISTS jwks (id TEXT PRIMARY KEY, public_key TEXT NOT NULL, private_key TEXT NOT NULL, created_at INTEGER NOT NULL, expires_at INTEGER)`,
|
|
751
|
+
];
|
|
752
|
+
for (const sql of sqliteStatements) await db.execute(sql);
|
|
719
753
|
}
|
|
720
754
|
|
|
721
755
|
/**
|