@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
|
@@ -5,6 +5,11 @@ import { and, eq, gte, isNull } from "drizzle-orm";
|
|
|
5
5
|
import { appStatePut } from "../application-state/store.js";
|
|
6
6
|
import { getDbExec, isPostgres, retryOnDdlRace } from "../db/client.js";
|
|
7
7
|
import { createGetDb } from "../db/create-get-db.js";
|
|
8
|
+
import {
|
|
9
|
+
ensureTableExists,
|
|
10
|
+
ensureColumnExists,
|
|
11
|
+
ensureIndexExists,
|
|
12
|
+
} from "../db/ddl-guard.js";
|
|
8
13
|
import { recordChange } from "../server/poll.js";
|
|
9
14
|
import {
|
|
10
15
|
getRequestUserEmail,
|
|
@@ -77,6 +82,70 @@ export async function ensureExtensionsTables(): Promise<void> {
|
|
|
77
82
|
_initPromise = (async () => {
|
|
78
83
|
const client = getDbExec();
|
|
79
84
|
const pg = isPostgres();
|
|
85
|
+
if (pg) {
|
|
86
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
87
|
+
await ensureTableExists("tools", EXTENSIONS_CREATE_SQL_PG);
|
|
88
|
+
await migrateMisnamedExtensionsTable(client, pg); // data migration, not DDL — unchanged
|
|
89
|
+
await ensureTableExists("tool_shares", EXTENSION_SHARES_CREATE_SQL_PG);
|
|
90
|
+
await ensureTableExists("tool_data", EXTENSION_DATA_CREATE_SQL_PG);
|
|
91
|
+
await ensureExtensionDataItemId(client, pg); // ADD COLUMN — guarded inside
|
|
92
|
+
await ensureExtensionDataScope(client, pg); // ADD COLUMN — guarded inside
|
|
93
|
+
// DROP INDEX (for old index) — safe DDL, runs via client.execute; keep on both paths
|
|
94
|
+
await client.execute(EXTENSION_DATA_DROP_OLD_INDEX_SQL_PG);
|
|
95
|
+
await ensureIndexExists(
|
|
96
|
+
"tool_data_scoped_item_idx",
|
|
97
|
+
EXTENSION_DATA_ITEM_INDEX_SQL_PG,
|
|
98
|
+
);
|
|
99
|
+
await ensureIndexExists("tools_owner_idx", EXTENSIONS_OWNER_INDEX_SQL);
|
|
100
|
+
await ensureIndexExists("tools_org_idx", EXTENSIONS_ORG_INDEX_SQL);
|
|
101
|
+
await ensureIndexExists(
|
|
102
|
+
"tools_updated_at_idx",
|
|
103
|
+
EXTENSIONS_UPDATED_INDEX_SQL,
|
|
104
|
+
);
|
|
105
|
+
await ensureExtensionsGlobalHideColumns(client, pg); // ADD COLUMN — guarded inside
|
|
106
|
+
await ensureIndexExists(
|
|
107
|
+
"tools_hidden_at_idx",
|
|
108
|
+
EXTENSIONS_HIDDEN_AT_INDEX_SQL,
|
|
109
|
+
);
|
|
110
|
+
await ensureIndexExists(
|
|
111
|
+
"tool_shares_resource_idx",
|
|
112
|
+
EXTENSION_SHARES_RESOURCE_INDEX_SQL,
|
|
113
|
+
);
|
|
114
|
+
await ensureTableExists(
|
|
115
|
+
"tool_hidden_extensions",
|
|
116
|
+
EXTENSION_HIDES_CREATE_SQL_PG,
|
|
117
|
+
);
|
|
118
|
+
await ensureIndexExists(
|
|
119
|
+
"tool_hidden_extensions_user_tool_idx",
|
|
120
|
+
EXTENSION_HIDES_UNIQUE_INDEX_SQL,
|
|
121
|
+
);
|
|
122
|
+
await ensureIndexExists(
|
|
123
|
+
"tool_hidden_extensions_owner_idx",
|
|
124
|
+
EXTENSION_HIDES_OWNER_INDEX_SQL,
|
|
125
|
+
);
|
|
126
|
+
await ensureTableExists(
|
|
127
|
+
"tool_history",
|
|
128
|
+
EXTENSION_HISTORY_CREATE_SQL_PG,
|
|
129
|
+
);
|
|
130
|
+
await ensureIndexExists(
|
|
131
|
+
"tool_history_tool_version_idx",
|
|
132
|
+
EXTENSION_HISTORY_VERSION_INDEX_SQL,
|
|
133
|
+
);
|
|
134
|
+
await ensureIndexExists(
|
|
135
|
+
"tool_history_tool_created_idx",
|
|
136
|
+
EXTENSION_HISTORY_CREATED_INDEX_SQL,
|
|
137
|
+
);
|
|
138
|
+
await ensureTableExists(
|
|
139
|
+
"tool_consents",
|
|
140
|
+
EXTENSION_CONSENTS_CREATE_SQL_PG,
|
|
141
|
+
);
|
|
142
|
+
await ensureIndexExists(
|
|
143
|
+
"tool_consents_viewer_idx",
|
|
144
|
+
EXTENSION_CONSENTS_VIEWER_INDEX_SQL,
|
|
145
|
+
);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
// SQLite (local dev): keep existing behavior
|
|
80
149
|
await retryOnDdlRace(() =>
|
|
81
150
|
client.execute(pg ? EXTENSIONS_CREATE_SQL_PG : EXTENSIONS_CREATE_SQL),
|
|
82
151
|
);
|
|
@@ -192,7 +261,9 @@ async function ensureExtensionDataItemId(
|
|
|
192
261
|
pg: boolean,
|
|
193
262
|
): Promise<void> {
|
|
194
263
|
if (pg) {
|
|
195
|
-
await
|
|
264
|
+
await ensureColumnExists(
|
|
265
|
+
"tool_data",
|
|
266
|
+
"item_id",
|
|
196
267
|
`ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS item_id TEXT`,
|
|
197
268
|
);
|
|
198
269
|
return;
|
|
@@ -219,7 +290,9 @@ async function ensureExtensionDataScope(
|
|
|
219
290
|
): Promise<void> {
|
|
220
291
|
const addCol = (name: string, def: string) => {
|
|
221
292
|
if (pg) {
|
|
222
|
-
return
|
|
293
|
+
return ensureColumnExists(
|
|
294
|
+
"tool_data",
|
|
295
|
+
name,
|
|
223
296
|
`ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS ${name} ${def}`,
|
|
224
297
|
);
|
|
225
298
|
}
|
|
@@ -255,7 +328,7 @@ async function ensureExtensionsGlobalHideColumns(
|
|
|
255
328
|
// does not, so we drop the clause and swallow the duplicate-column error.
|
|
256
329
|
const addCol = (pgSql: string, name: string, def: string) => {
|
|
257
330
|
if (pg) {
|
|
258
|
-
return
|
|
331
|
+
return ensureColumnExists("tools", name, pgSql);
|
|
259
332
|
}
|
|
260
333
|
return client
|
|
261
334
|
.execute(`ALTER TABLE tools ADD COLUMN ${name} ${def}`)
|
|
@@ -4,6 +4,11 @@ import {
|
|
|
4
4
|
intType,
|
|
5
5
|
retryOnDdlRace,
|
|
6
6
|
} from "../db/client.js";
|
|
7
|
+
import {
|
|
8
|
+
ensureTableExists,
|
|
9
|
+
ensureColumnExists,
|
|
10
|
+
ensureIndexExists,
|
|
11
|
+
} from "../db/ddl-guard.js";
|
|
7
12
|
import { isDuplicateColumnError } from "../db/migrations.js";
|
|
8
13
|
import type { IncomingMessage } from "./types.js";
|
|
9
14
|
|
|
@@ -11,36 +16,74 @@ let _initPromise: Promise<void> | undefined;
|
|
|
11
16
|
const PROCESSING_STUCK_AFTER_MS = 5 * 60 * 1000;
|
|
12
17
|
const PROCESSING_NEXT_CHECK_STALE_AFTER_MS = 60 * 1000;
|
|
13
18
|
|
|
19
|
+
// Build the CREATE SQL lazily (not at module scope) so intType() runs at
|
|
20
|
+
// RUNTIME, not import time — a module-scope call breaks any consumer whose
|
|
21
|
+
// db/client mock doesn't stub intType (e.g. db-admin specs).
|
|
22
|
+
function buildCreateSql(): string {
|
|
23
|
+
return `
|
|
24
|
+
CREATE TABLE IF NOT EXISTS integration_a2a_continuations (
|
|
25
|
+
id TEXT PRIMARY KEY,
|
|
26
|
+
integration_task_id TEXT NOT NULL,
|
|
27
|
+
platform TEXT NOT NULL,
|
|
28
|
+
external_thread_id TEXT NOT NULL,
|
|
29
|
+
incoming_payload TEXT NOT NULL,
|
|
30
|
+
placeholder_ref TEXT,
|
|
31
|
+
owner_email TEXT NOT NULL,
|
|
32
|
+
org_id TEXT,
|
|
33
|
+
agent_name TEXT NOT NULL,
|
|
34
|
+
agent_url TEXT NOT NULL,
|
|
35
|
+
dedupe_key TEXT,
|
|
36
|
+
a2a_task_id TEXT NOT NULL,
|
|
37
|
+
a2a_auth_token TEXT,
|
|
38
|
+
status TEXT NOT NULL,
|
|
39
|
+
attempts ${intType()} NOT NULL DEFAULT 0,
|
|
40
|
+
next_check_at ${intType()} NOT NULL,
|
|
41
|
+
error_message TEXT,
|
|
42
|
+
created_at ${intType()} NOT NULL,
|
|
43
|
+
updated_at ${intType()} NOT NULL,
|
|
44
|
+
completed_at ${intType()}
|
|
45
|
+
)
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
|
|
14
49
|
async function ensureTable(): Promise<void> {
|
|
15
50
|
if (!_initPromise) {
|
|
16
51
|
_initPromise = (async () => {
|
|
17
52
|
const client = getDbExec();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
const createSql = buildCreateSql();
|
|
54
|
+
if (isPostgres()) {
|
|
55
|
+
// PG guard: probe via information_schema, only issue DDL if missing, bounded lock_timeout
|
|
56
|
+
await ensureTableExists("integration_a2a_continuations", createSql);
|
|
57
|
+
await ensureIndexExists(
|
|
58
|
+
"idx_a2a_continuations_status_next",
|
|
59
|
+
`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_status_next ON integration_a2a_continuations(status, next_check_at)`,
|
|
60
|
+
);
|
|
61
|
+
await ensureIndexExists(
|
|
62
|
+
"idx_a2a_continuations_integration_task",
|
|
63
|
+
`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_integration_task ON integration_a2a_continuations(integration_task_id)`,
|
|
64
|
+
);
|
|
65
|
+
await ensureIndexExists(
|
|
66
|
+
"idx_a2a_continuations_remote_task",
|
|
67
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_a2a_continuations_remote_task ON integration_a2a_continuations(integration_task_id, agent_url, a2a_task_id)`,
|
|
68
|
+
);
|
|
69
|
+
await ensureColumnExists(
|
|
70
|
+
"integration_a2a_continuations",
|
|
71
|
+
"a2a_auth_token",
|
|
72
|
+
`ALTER TABLE integration_a2a_continuations ADD COLUMN IF NOT EXISTS a2a_auth_token TEXT`,
|
|
73
|
+
);
|
|
74
|
+
await ensureColumnExists(
|
|
75
|
+
"integration_a2a_continuations",
|
|
76
|
+
"dedupe_key",
|
|
77
|
+
`ALTER TABLE integration_a2a_continuations ADD COLUMN IF NOT EXISTS dedupe_key TEXT`,
|
|
78
|
+
);
|
|
79
|
+
await ensureIndexExists(
|
|
80
|
+
"idx_a2a_continuations_dedupe_key",
|
|
81
|
+
`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_dedupe_key ON integration_a2a_continuations(integration_task_id, agent_url, dedupe_key)`,
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// SQLite (local dev): keep existing behavior
|
|
86
|
+
await retryOnDdlRace(() => client.execute(createSql));
|
|
44
87
|
await retryOnDdlRace(() =>
|
|
45
88
|
client.execute(
|
|
46
89
|
`CREATE INDEX IF NOT EXISTS idx_a2a_continuations_status_next ON integration_a2a_continuations(status, next_check_at)`,
|
|
@@ -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)`,
|