@agent-native/core 0.77.8 → 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 +1 -1
- package/corpus/core/CHANGELOG.md +29 -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/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 +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/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/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 +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/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/routes.d.ts +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 +3 -3
- 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-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 +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 +1 -1
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
isPostgres,
|
|
4
|
-
intType,
|
|
5
|
-
retryOnDdlRace,
|
|
6
|
-
} from "../db/client.js";
|
|
1
|
+
import { getDbExec, isPostgres, intType } from "../db/client.js";
|
|
2
|
+
import { ensureTableExists } from "../db/ddl-guard.js";
|
|
7
3
|
|
|
8
4
|
let _initPromise: Promise<void> | undefined;
|
|
9
5
|
|
|
@@ -11,18 +7,23 @@ async function ensureTable(): Promise<void> {
|
|
|
11
7
|
if (!_initPromise) {
|
|
12
8
|
_initPromise = (async () => {
|
|
13
9
|
const client = getDbExec();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
10
|
+
const createSql = `CREATE TABLE IF NOT EXISTS integration_configs (
|
|
11
|
+
platform TEXT NOT NULL,
|
|
12
|
+
config_key TEXT NOT NULL,
|
|
13
|
+
config_data TEXT NOT NULL,
|
|
14
|
+
owner TEXT,
|
|
15
|
+
updated_at ${intType()} NOT NULL,
|
|
16
|
+
PRIMARY KEY (platform, config_key)
|
|
17
|
+
)`;
|
|
18
|
+
|
|
19
|
+
if (isPostgres()) {
|
|
20
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
21
|
+
await ensureTableExists("integration_configs", createSql);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// SQLite (local dev): keep existing behavior
|
|
26
|
+
await client.execute(createSql);
|
|
26
27
|
})().catch((err) => {
|
|
27
28
|
// Don't cache the rejection — let the next caller retry a fresh init.
|
|
28
29
|
_initPromise = undefined;
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
* invocation gets its own fresh function timeout budget.
|
|
12
12
|
*/
|
|
13
13
|
import { getDbExec, isPostgres, intType } from "../db/client.js";
|
|
14
|
+
import {
|
|
15
|
+
ensureTableExists,
|
|
16
|
+
ensureColumnExists,
|
|
17
|
+
ensureIndexExists,
|
|
18
|
+
} from "../db/ddl-guard.js";
|
|
14
19
|
|
|
15
20
|
let _initPromise: Promise<void> | undefined;
|
|
16
21
|
|
|
@@ -18,22 +23,41 @@ async function ensureTable(): Promise<void> {
|
|
|
18
23
|
if (!_initPromise) {
|
|
19
24
|
_initPromise = (async () => {
|
|
20
25
|
const client = getDbExec();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
const createSql = `CREATE TABLE IF NOT EXISTS integration_pending_tasks (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
platform TEXT NOT NULL,
|
|
29
|
+
external_thread_id TEXT NOT NULL,
|
|
30
|
+
payload TEXT NOT NULL,
|
|
31
|
+
owner_email TEXT NOT NULL,
|
|
32
|
+
org_id TEXT,
|
|
33
|
+
status TEXT NOT NULL,
|
|
34
|
+
attempts ${intType()} NOT NULL DEFAULT 0,
|
|
35
|
+
error_message TEXT,
|
|
36
|
+
created_at ${intType()} NOT NULL,
|
|
37
|
+
updated_at ${intType()} NOT NULL,
|
|
38
|
+
completed_at ${intType()}
|
|
39
|
+
)`;
|
|
40
|
+
|
|
41
|
+
if (isPostgres()) {
|
|
42
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
43
|
+
await ensureTableExists("integration_pending_tasks", createSql);
|
|
44
|
+
await ensureColumnExists(
|
|
45
|
+
"integration_pending_tasks",
|
|
46
|
+
"external_event_key",
|
|
47
|
+
`ALTER TABLE integration_pending_tasks ADD COLUMN IF NOT EXISTS external_event_key TEXT`,
|
|
48
|
+
);
|
|
49
|
+
await ensureIndexExists(
|
|
50
|
+
"idx_pending_tasks_status_created",
|
|
51
|
+
`CREATE INDEX IF NOT EXISTS idx_pending_tasks_status_created ON integration_pending_tasks(status, created_at)`,
|
|
52
|
+
);
|
|
53
|
+
await ensureIndexExists(
|
|
54
|
+
"idx_pending_tasks_event_key",
|
|
55
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_pending_tasks_event_key ON integration_pending_tasks(platform, external_event_key)`,
|
|
56
|
+
);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await client.execute(createSql);
|
|
37
61
|
await client.execute(
|
|
38
62
|
`CREATE INDEX IF NOT EXISTS idx_pending_tasks_status_created ON integration_pending_tasks(status, created_at)`,
|
|
39
63
|
);
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
isPostgres,
|
|
5
5
|
retryOnDdlRace,
|
|
6
6
|
} from "../db/client.js";
|
|
7
|
+
import { ensureTableExists, ensureIndexExists } from "../db/ddl-guard.js";
|
|
7
8
|
import type {
|
|
8
9
|
RemoteCommand,
|
|
9
10
|
RemoteCommandKind,
|
|
@@ -29,29 +30,42 @@ async function ensureTable(): Promise<void> {
|
|
|
29
30
|
if (!_initPromise) {
|
|
30
31
|
_initPromise = (async () => {
|
|
31
32
|
const client = getDbExec();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
33
|
+
const createSql = `CREATE TABLE IF NOT EXISTS integration_remote_commands (
|
|
34
|
+
id TEXT PRIMARY KEY,
|
|
35
|
+
device_id TEXT NOT NULL,
|
|
36
|
+
owner_email TEXT NOT NULL,
|
|
37
|
+
org_id TEXT,
|
|
38
|
+
kind TEXT NOT NULL,
|
|
39
|
+
params_json TEXT NOT NULL,
|
|
40
|
+
status TEXT NOT NULL,
|
|
41
|
+
result_json TEXT,
|
|
42
|
+
platform TEXT,
|
|
43
|
+
external_thread_id TEXT,
|
|
44
|
+
attempts ${intType()} NOT NULL DEFAULT 0,
|
|
45
|
+
next_check_at ${intType()} NOT NULL,
|
|
46
|
+
claimed_at ${intType()},
|
|
47
|
+
completed_at ${intType()},
|
|
48
|
+
error_message TEXT,
|
|
49
|
+
created_at ${intType()} NOT NULL,
|
|
50
|
+
updated_at ${intType()} NOT NULL
|
|
51
|
+
)`;
|
|
52
|
+
|
|
53
|
+
if (isPostgres()) {
|
|
54
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
55
|
+
await ensureTableExists("integration_remote_commands", createSql);
|
|
56
|
+
await ensureIndexExists(
|
|
57
|
+
"idx_remote_commands_device_status_next",
|
|
58
|
+
`CREATE INDEX IF NOT EXISTS idx_remote_commands_device_status_next ON integration_remote_commands(device_id, status, next_check_at)`,
|
|
59
|
+
);
|
|
60
|
+
await ensureIndexExists(
|
|
61
|
+
"idx_remote_commands_owner",
|
|
62
|
+
`CREATE INDEX IF NOT EXISTS idx_remote_commands_owner ON integration_remote_commands(owner_email, org_id)`,
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// SQLite: keep existing behavior
|
|
68
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
55
69
|
await retryOnDdlRace(() =>
|
|
56
70
|
client.execute(
|
|
57
71
|
`CREATE INDEX IF NOT EXISTS idx_remote_commands_device_status_next ON integration_remote_commands(device_id, status, next_check_at)`,
|
|
@@ -4,6 +4,11 @@ import {
|
|
|
4
4
|
isPostgres,
|
|
5
5
|
retryOnDdlRace,
|
|
6
6
|
} from "../db/client.js";
|
|
7
|
+
import {
|
|
8
|
+
ensureColumnExists,
|
|
9
|
+
ensureIndexExists,
|
|
10
|
+
ensureTableExists,
|
|
11
|
+
} from "../db/ddl-guard.js";
|
|
7
12
|
import type { PublicRemoteDevice, RemoteDevice } from "./remote-types.js";
|
|
8
13
|
|
|
9
14
|
let _initPromise: Promise<void> | undefined;
|
|
@@ -12,26 +17,65 @@ async function ensureTable(): Promise<void> {
|
|
|
12
17
|
if (!_initPromise) {
|
|
13
18
|
_initPromise = (async () => {
|
|
14
19
|
const client = getDbExec();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
20
|
+
const createSql = `
|
|
21
|
+
CREATE TABLE IF NOT EXISTS integration_remote_devices (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
owner_email TEXT NOT NULL,
|
|
24
|
+
org_id TEXT,
|
|
25
|
+
label TEXT NOT NULL,
|
|
26
|
+
platform TEXT,
|
|
27
|
+
app_version TEXT,
|
|
28
|
+
host_name TEXT,
|
|
29
|
+
metadata_json TEXT,
|
|
30
|
+
device_token_hash TEXT NOT NULL,
|
|
31
|
+
last_seen_at ${intType()},
|
|
32
|
+
status TEXT NOT NULL,
|
|
33
|
+
revoked_at ${intType()},
|
|
34
|
+
created_at ${intType()} NOT NULL,
|
|
35
|
+
updated_at ${intType()} NOT NULL
|
|
36
|
+
)
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
if (isPostgres()) {
|
|
40
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
41
|
+
await ensureTableExists("integration_remote_devices", createSql);
|
|
42
|
+
await ensureColumnExists(
|
|
43
|
+
"integration_remote_devices",
|
|
44
|
+
"platform",
|
|
45
|
+
`ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS platform TEXT`,
|
|
46
|
+
);
|
|
47
|
+
await ensureColumnExists(
|
|
48
|
+
"integration_remote_devices",
|
|
49
|
+
"app_version",
|
|
50
|
+
`ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS app_version TEXT`,
|
|
51
|
+
);
|
|
52
|
+
await ensureColumnExists(
|
|
53
|
+
"integration_remote_devices",
|
|
54
|
+
"host_name",
|
|
55
|
+
`ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS host_name TEXT`,
|
|
56
|
+
);
|
|
57
|
+
await ensureColumnExists(
|
|
58
|
+
"integration_remote_devices",
|
|
59
|
+
"metadata_json",
|
|
60
|
+
`ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS metadata_json TEXT`,
|
|
61
|
+
);
|
|
62
|
+
await ensureColumnExists(
|
|
63
|
+
"integration_remote_devices",
|
|
64
|
+
"revoked_at",
|
|
65
|
+
`ALTER TABLE integration_remote_devices ADD COLUMN IF NOT EXISTS revoked_at ${intType()}`,
|
|
66
|
+
);
|
|
67
|
+
await ensureIndexExists(
|
|
68
|
+
"idx_remote_devices_token_hash",
|
|
69
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_devices_token_hash ON integration_remote_devices(device_token_hash)`,
|
|
70
|
+
);
|
|
71
|
+
await ensureIndexExists(
|
|
72
|
+
"idx_remote_devices_owner",
|
|
73
|
+
`CREATE INDEX IF NOT EXISTS idx_remote_devices_owner ON integration_remote_devices(owner_email, org_id)`,
|
|
74
|
+
);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// SQLite (local dev): keep existing behavior verbatim
|
|
78
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
35
79
|
await addColumnIfMissing("platform", "TEXT");
|
|
36
80
|
await addColumnIfMissing("app_version", "TEXT");
|
|
37
81
|
await addColumnIfMissing("host_name", "TEXT");
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getDbExec,
|
|
3
|
+
isPostgres,
|
|
4
|
+
intType,
|
|
5
|
+
retryOnDdlRace,
|
|
6
|
+
} from "../db/client.js";
|
|
7
|
+
import { ensureTableExists, ensureIndexExists } from "../db/ddl-guard.js";
|
|
2
8
|
import type {
|
|
3
9
|
PublicRemotePushRegistration,
|
|
4
10
|
RemotePushNotification,
|
|
@@ -7,29 +13,77 @@ import type {
|
|
|
7
13
|
|
|
8
14
|
let _initPromise: Promise<void> | undefined;
|
|
9
15
|
|
|
16
|
+
// Build the CREATE SQL lazily (not at module scope) so intType() runs at
|
|
17
|
+
// RUNTIME, not import time — a module-scope call breaks any consumer whose
|
|
18
|
+
// db/client mock doesn't stub intType (e.g. db-admin specs).
|
|
19
|
+
function buildCreateRegistrationsSql(): string {
|
|
20
|
+
return `
|
|
21
|
+
CREATE TABLE IF NOT EXISTS integration_remote_push_registrations (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
owner_email TEXT NOT NULL,
|
|
24
|
+
org_id TEXT,
|
|
25
|
+
provider TEXT NOT NULL,
|
|
26
|
+
platform TEXT,
|
|
27
|
+
client_device_id TEXT,
|
|
28
|
+
label TEXT,
|
|
29
|
+
token TEXT NOT NULL,
|
|
30
|
+
token_hash TEXT NOT NULL,
|
|
31
|
+
status TEXT NOT NULL,
|
|
32
|
+
last_seen_at ${intType()},
|
|
33
|
+
created_at ${intType()} NOT NULL,
|
|
34
|
+
updated_at ${intType()} NOT NULL
|
|
35
|
+
)
|
|
36
|
+
`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildCreateNotificationsSql(): string {
|
|
40
|
+
return `
|
|
41
|
+
CREATE TABLE IF NOT EXISTS integration_remote_push_notifications (
|
|
42
|
+
id TEXT PRIMARY KEY,
|
|
43
|
+
owner_email TEXT NOT NULL,
|
|
44
|
+
org_id TEXT,
|
|
45
|
+
registration_id TEXT NOT NULL,
|
|
46
|
+
payload_json TEXT NOT NULL,
|
|
47
|
+
status TEXT NOT NULL,
|
|
48
|
+
attempts ${intType()} NOT NULL DEFAULT 0,
|
|
49
|
+
created_at ${intType()} NOT NULL,
|
|
50
|
+
updated_at ${intType()} NOT NULL
|
|
51
|
+
)
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
|
|
10
55
|
async function ensureTables(): Promise<void> {
|
|
11
56
|
if (!_initPromise) {
|
|
12
57
|
_initPromise = (async () => {
|
|
13
58
|
const client = getDbExec();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
59
|
+
const createRegistrationsSql = buildCreateRegistrationsSql();
|
|
60
|
+
const createNotificationsSql = buildCreateNotificationsSql();
|
|
61
|
+
if (isPostgres()) {
|
|
62
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
63
|
+
await ensureTableExists(
|
|
64
|
+
"integration_remote_push_registrations",
|
|
65
|
+
createRegistrationsSql,
|
|
66
|
+
);
|
|
67
|
+
await ensureIndexExists(
|
|
68
|
+
"idx_remote_push_token_hash",
|
|
69
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_push_token_hash ON integration_remote_push_registrations(token_hash)`,
|
|
70
|
+
);
|
|
71
|
+
await ensureIndexExists(
|
|
72
|
+
"idx_remote_push_owner",
|
|
73
|
+
`CREATE INDEX IF NOT EXISTS idx_remote_push_owner ON integration_remote_push_registrations(owner_email, org_id, status)`,
|
|
74
|
+
);
|
|
75
|
+
await ensureTableExists(
|
|
76
|
+
"integration_remote_push_notifications",
|
|
77
|
+
createNotificationsSql,
|
|
78
|
+
);
|
|
79
|
+
await ensureIndexExists(
|
|
80
|
+
"idx_remote_push_notifications_owner",
|
|
81
|
+
`CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_owner ON integration_remote_push_notifications(owner_email, org_id, status, created_at)`,
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// SQLite (local dev): keep existing behavior
|
|
86
|
+
await retryOnDdlRace(() => client.execute(createRegistrationsSql));
|
|
33
87
|
await retryOnDdlRace(() =>
|
|
34
88
|
client.execute(
|
|
35
89
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_push_token_hash ON integration_remote_push_registrations(token_hash)`,
|
|
@@ -41,21 +95,7 @@ async function ensureTables(): Promise<void> {
|
|
|
41
95
|
),
|
|
42
96
|
);
|
|
43
97
|
|
|
44
|
-
await retryOnDdlRace(() =>
|
|
45
|
-
client.execute(`
|
|
46
|
-
CREATE TABLE IF NOT EXISTS integration_remote_push_notifications (
|
|
47
|
-
id TEXT PRIMARY KEY,
|
|
48
|
-
owner_email TEXT NOT NULL,
|
|
49
|
-
org_id TEXT,
|
|
50
|
-
registration_id TEXT NOT NULL,
|
|
51
|
-
payload_json TEXT NOT NULL,
|
|
52
|
-
status TEXT NOT NULL,
|
|
53
|
-
attempts ${intType()} NOT NULL DEFAULT 0,
|
|
54
|
-
created_at ${intType()} NOT NULL,
|
|
55
|
-
updated_at ${intType()} NOT NULL
|
|
56
|
-
)
|
|
57
|
-
`),
|
|
58
|
-
);
|
|
98
|
+
await retryOnDdlRace(() => client.execute(createNotificationsSql));
|
|
59
99
|
await retryOnDdlRace(() =>
|
|
60
100
|
client.execute(
|
|
61
101
|
`CREATE INDEX IF NOT EXISTS idx_remote_push_notifications_owner ON integration_remote_push_notifications(owner_email, org_id, status, created_at)`,
|
|
@@ -1,23 +1,49 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getDbExec,
|
|
3
|
+
isPostgres,
|
|
4
|
+
intType,
|
|
5
|
+
retryOnDdlRace,
|
|
6
|
+
} from "../db/client.js";
|
|
7
|
+
import { ensureTableExists, ensureIndexExists } from "../db/ddl-guard.js";
|
|
2
8
|
import type { RemoteRunEvent } from "./remote-types.js";
|
|
3
9
|
|
|
4
10
|
let _initPromise: Promise<void> | undefined;
|
|
5
11
|
|
|
12
|
+
// Build the CREATE SQL lazily (not at module scope) so intType() runs at
|
|
13
|
+
// RUNTIME, not import time — a module-scope call breaks any consumer whose
|
|
14
|
+
// db/client mock doesn't stub intType (e.g. db-admin specs).
|
|
15
|
+
function buildCreateSql(): string {
|
|
16
|
+
return `
|
|
17
|
+
CREATE TABLE IF NOT EXISTS integration_remote_run_events (
|
|
18
|
+
device_id TEXT NOT NULL,
|
|
19
|
+
remote_run_id TEXT NOT NULL,
|
|
20
|
+
seq ${intType()} NOT NULL,
|
|
21
|
+
event_json TEXT NOT NULL,
|
|
22
|
+
created_at ${intType()} NOT NULL
|
|
23
|
+
)
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
26
|
+
|
|
6
27
|
async function ensureTable(): Promise<void> {
|
|
7
28
|
if (!_initPromise) {
|
|
8
29
|
_initPromise = (async () => {
|
|
9
30
|
const client = getDbExec();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
const createSql = buildCreateSql();
|
|
32
|
+
if (isPostgres()) {
|
|
33
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
34
|
+
await ensureTableExists("integration_remote_run_events", createSql);
|
|
35
|
+
await ensureIndexExists(
|
|
36
|
+
"idx_remote_run_events_unique",
|
|
37
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_run_events_unique ON integration_remote_run_events(device_id, remote_run_id, seq)`,
|
|
38
|
+
);
|
|
39
|
+
await ensureIndexExists(
|
|
40
|
+
"idx_remote_run_events_run",
|
|
41
|
+
`CREATE INDEX IF NOT EXISTS idx_remote_run_events_run ON integration_remote_run_events(device_id, remote_run_id, seq)`,
|
|
42
|
+
);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// SQLite (local dev): keep existing behavior
|
|
46
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
21
47
|
await retryOnDdlRace(() =>
|
|
22
48
|
client.execute(
|
|
23
49
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_remote_run_events_unique ON integration_remote_run_events(device_id, remote_run_id, seq)`,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getDbExec, isPostgres, intType } from "../db/client.js";
|
|
2
|
+
import { ensureTableExists } from "../db/ddl-guard.js";
|
|
2
3
|
|
|
3
4
|
let _initPromise: Promise<void> | undefined;
|
|
4
5
|
|
|
@@ -6,7 +7,7 @@ async function ensureTable(): Promise<void> {
|
|
|
6
7
|
if (!_initPromise) {
|
|
7
8
|
_initPromise = (async () => {
|
|
8
9
|
const client = getDbExec();
|
|
9
|
-
|
|
10
|
+
const createSql = `
|
|
10
11
|
CREATE TABLE IF NOT EXISTS integration_thread_mappings (
|
|
11
12
|
platform TEXT NOT NULL,
|
|
12
13
|
external_thread_id TEXT NOT NULL,
|
|
@@ -16,7 +17,15 @@ async function ensureTable(): Promise<void> {
|
|
|
16
17
|
updated_at ${intType()} NOT NULL,
|
|
17
18
|
PRIMARY KEY (platform, external_thread_id)
|
|
18
19
|
)
|
|
19
|
-
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
if (isPostgres()) {
|
|
23
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
24
|
+
await ensureTableExists("integration_thread_mappings", createSql);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// SQLite (local dev): keep existing behavior
|
|
28
|
+
await client.execute(createSql);
|
|
20
29
|
})().catch((err) => {
|
|
21
30
|
// Retry init on the next call after a failed startup.
|
|
22
31
|
_initPromise = undefined;
|
|
@@ -19,7 +19,13 @@
|
|
|
19
19
|
|
|
20
20
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
getDbExec,
|
|
24
|
+
isConnectionError,
|
|
25
|
+
intType,
|
|
26
|
+
isPostgres,
|
|
27
|
+
} from "../db/client.js";
|
|
28
|
+
import { ensureTableExists, ensureColumnExists } from "../db/ddl-guard.js";
|
|
23
29
|
|
|
24
30
|
let _initPromise: Promise<void> | undefined;
|
|
25
31
|
|
|
@@ -59,7 +65,7 @@ async function ensureTable(): Promise<void> {
|
|
|
59
65
|
const client = getDbExec();
|
|
60
66
|
// Additive only. Never DROP / ALTER — this DB is shared across every
|
|
61
67
|
// deploy context (preview/branch/prod) for hosted templates.
|
|
62
|
-
|
|
68
|
+
const createTokensSql = `
|
|
63
69
|
CREATE TABLE IF NOT EXISTS mcp_connect_tokens (
|
|
64
70
|
id TEXT PRIMARY KEY,
|
|
65
71
|
jti TEXT UNIQUE NOT NULL,
|
|
@@ -73,7 +79,50 @@ async function ensureTable(): Promise<void> {
|
|
|
73
79
|
last_used_at ${intType()},
|
|
74
80
|
revoked_at ${intType()}
|
|
75
81
|
)
|
|
76
|
-
|
|
82
|
+
`;
|
|
83
|
+
const createDeviceCodesSql = `
|
|
84
|
+
CREATE TABLE IF NOT EXISTS mcp_device_codes (
|
|
85
|
+
device_code TEXT PRIMARY KEY,
|
|
86
|
+
user_code TEXT NOT NULL,
|
|
87
|
+
owner_email TEXT,
|
|
88
|
+
org_id TEXT,
|
|
89
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
90
|
+
token_jti TEXT,
|
|
91
|
+
created_at ${intType()},
|
|
92
|
+
expires_at ${intType()},
|
|
93
|
+
consumed_at ${intType()}
|
|
94
|
+
)
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
if (isPostgres()) {
|
|
98
|
+
// PG-guard: probe information_schema first (no lock) and only issue
|
|
99
|
+
// DDL when the table/column is actually missing, wrapped in a
|
|
100
|
+
// transaction-scoped lock_timeout so a contended lock fails fast.
|
|
101
|
+
await ensureTableExists("mcp_connect_tokens", createTokensSql);
|
|
102
|
+
// Additive columns for org service tokens — added after initial
|
|
103
|
+
// deployment; ensureColumnExists probes before ALTERing.
|
|
104
|
+
await ensureColumnExists(
|
|
105
|
+
"mcp_connect_tokens",
|
|
106
|
+
"kind",
|
|
107
|
+
`ALTER TABLE mcp_connect_tokens ADD COLUMN IF NOT EXISTS kind TEXT NOT NULL DEFAULT 'personal'`,
|
|
108
|
+
);
|
|
109
|
+
await ensureColumnExists(
|
|
110
|
+
"mcp_connect_tokens",
|
|
111
|
+
"service_name",
|
|
112
|
+
`ALTER TABLE mcp_connect_tokens ADD COLUMN IF NOT EXISTS service_name TEXT`,
|
|
113
|
+
);
|
|
114
|
+
await ensureColumnExists(
|
|
115
|
+
"mcp_connect_tokens",
|
|
116
|
+
"created_by",
|
|
117
|
+
`ALTER TABLE mcp_connect_tokens ADD COLUMN IF NOT EXISTS created_by TEXT`,
|
|
118
|
+
);
|
|
119
|
+
await ensureTableExists("mcp_device_codes", createDeviceCodesSql);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// SQLite (local dev): no ACCESS EXCLUSIVE lock problem — keep existing
|
|
124
|
+
// create-then-additive-alter behaviour.
|
|
125
|
+
await client.execute(createTokensSql);
|
|
77
126
|
// Additive columns for org service tokens (deployments that created the
|
|
78
127
|
// table before these columns existed; fresh DBs get them via the CREATE
|
|
79
128
|
// TABLE above). kind='personal' (default) preserves the original
|
|
@@ -107,19 +156,7 @@ async function ensureTable(): Promise<void> {
|
|
|
107
156
|
}
|
|
108
157
|
}
|
|
109
158
|
}
|
|
110
|
-
await client.execute(
|
|
111
|
-
CREATE TABLE IF NOT EXISTS mcp_device_codes (
|
|
112
|
-
device_code TEXT PRIMARY KEY,
|
|
113
|
-
user_code TEXT NOT NULL,
|
|
114
|
-
owner_email TEXT,
|
|
115
|
-
org_id TEXT,
|
|
116
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
117
|
-
token_jti TEXT,
|
|
118
|
-
created_at ${intType()},
|
|
119
|
-
expires_at ${intType()},
|
|
120
|
-
consumed_at ${intType()}
|
|
121
|
-
)
|
|
122
|
-
`);
|
|
159
|
+
await client.execute(createDeviceCodesSql);
|
|
123
160
|
})().catch((err) => {
|
|
124
161
|
// Don't cache a rejected init. A transient DB blip should let the next
|
|
125
162
|
// connect/mint/revoke call retry rather than wedging the process.
|