@agent-native/core 0.77.8 → 0.77.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +35 -0
- package/corpus/core/package.json +3 -3
- package/corpus/core/src/a2a/task-store.ts +25 -3
- package/corpus/core/src/agent/harness/store.ts +89 -55
- package/corpus/core/src/agent/observational-memory/store.ts +40 -14
- package/corpus/core/src/agent/run-store.ts +116 -59
- package/corpus/core/src/application-state/store.ts +36 -2
- package/corpus/core/src/audit/store.ts +37 -6
- package/corpus/core/src/browser-sessions/store.ts +31 -12
- package/corpus/core/src/chat-threads/store.ts +67 -3
- package/corpus/core/src/checkpoints/store.ts +14 -3
- package/corpus/core/src/cli/create.ts +9 -0
- package/corpus/core/src/collab/awareness.ts +12 -9
- package/corpus/core/src/collab/client.ts +4 -2
- package/corpus/core/src/collab/storage.ts +20 -2
- package/corpus/core/src/db/ddl-guard.ts +112 -0
- package/corpus/core/src/extensions/store.ts +76 -3
- package/corpus/core/src/integrations/a2a-continuations-store.ts +69 -26
- package/corpus/core/src/integrations/config-store.ts +19 -18
- package/corpus/core/src/integrations/pending-tasks-store.ts +40 -16
- package/corpus/core/src/integrations/remote-commands-store.ts +37 -23
- package/corpus/core/src/integrations/remote-devices-store.ts +64 -20
- package/corpus/core/src/integrations/remote-push-store.ts +75 -35
- package/corpus/core/src/integrations/remote-run-events-store.ts +38 -12
- package/corpus/core/src/integrations/thread-mapping-store.ts +11 -2
- package/corpus/core/src/mcp/connect-store.ts +53 -16
- package/corpus/core/src/mcp/oauth-store.ts +32 -7
- package/corpus/core/src/notifications/store.ts +20 -4
- package/corpus/core/src/oauth-tokens/store.ts +45 -2
- package/corpus/core/src/observability/store.ts +154 -47
- package/corpus/core/src/progress/store.ts +36 -21
- package/corpus/core/src/provider-api/corpus-jobs-store.ts +25 -5
- package/corpus/core/src/provider-api/custom-registry.ts +15 -4
- package/corpus/core/src/provider-api/quota-governor.ts +15 -3
- package/corpus/core/src/provider-api/staged-datasets-store.ts +22 -5
- package/corpus/core/src/resources/store.ts +66 -31
- package/corpus/core/src/secrets/storage.ts +18 -22
- package/corpus/core/src/server/agent-teams-run-queue.ts +22 -10
- package/corpus/core/src/server/auth.ts +22 -4
- package/corpus/core/src/server/better-auth-instance.ts +49 -15
- package/corpus/core/src/server/embed-session.ts +19 -4
- package/corpus/core/src/server/identity-sso-store.ts +40 -11
- package/corpus/core/src/server/recap-image-store.ts +28 -9
- package/corpus/core/src/settings/store.ts +14 -19
- package/corpus/core/src/usage/store.ts +51 -16
- package/corpus/core/src/workspace-connections/store.ts +200 -22
- package/corpus/templates/calendar/changelog/2026-06-25-booking-link-previews-now-show-the-content-directly-on-the-g.md +6 -0
- package/corpus/templates/calendar/server/lib/booking-og-image.ts +0 -2
- package/corpus/templates/clips/chrome-extension/package.json +1 -1
- package/corpus/templates/content/actions/list-trashed-content-databases.ts +36 -2
- package/corpus/templates/content/actions/move-document.ts +79 -33
- package/corpus/templates/content/actions/restore-content-database.ts +40 -3
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +84 -2
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +177 -49
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +393 -219
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +632 -467
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +114 -14
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +56 -15
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +6 -5
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +12 -4
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/hooks/use-create-page.ts +36 -7
- package/corpus/templates/content/app/i18n-data.ts +140 -10
- package/corpus/templates/content/changelog/2026-06-25-comment-cards-now-track-their-highlighted-text-while-scrolli.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-comments-now-scroll-with-the-document-and-stay-below-the-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-creating-a-database-from-the-slash-menu-no-longer-leaves-sta.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-sidebar-hover-controls-no-longer-leave-a-lingering-fade-when.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-sidebar-page-actions-are-now-easier-to-see-when-hovering-ina.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-text-selections-in-the-editor-no-longer-show-white-gaps-when.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-has-a-one-click-page-link-copy-button.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-the-editor-toolbar-now-shows-page-breadcrumbs-and-the-latest.md +6 -0
- package/corpus/templates/content/changelog/2026-06-25-the-page-command-now-leaves-a-notion-style-page-reference-an.md +6 -0
- package/corpus/templates/content/shared/nfm.ts +16 -0
- package/corpus/templates/forms/changelog/2026-06-25-form-previews-now-show-the-content-directly-on-the-grid-back.md +6 -0
- package/corpus/templates/forms/server/lib/form-og-image.ts +0 -2
- package/corpus/templates/plan/app/global.css +6 -11
- package/corpus/templates/plan/app/pages/PlansPage.tsx +12 -10
- package/corpus/templates/plan/changelog/2026-06-25-plan-access-request-pages-stay-visible-during-background-ref.md +6 -0
- package/corpus/templates/plan/changelog/2026-06-25-plan-documents-keep-their-full-reading-width-below-1200px-an.md +6 -0
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +19 -3
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/agent/harness/store.d.ts.map +1 -1
- package/dist/agent/harness/store.js +63 -34
- package/dist/agent/harness/store.js.map +1 -1
- package/dist/agent/observational-memory/store.d.ts.map +1 -1
- package/dist/agent/observational-memory/store.js +30 -8
- package/dist/agent/observational-memory/store.js.map +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +103 -46
- package/dist/agent/run-store.js.map +1 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +28 -2
- package/dist/application-state/store.js.map +1 -1
- package/dist/audit/store.d.ts.map +1 -1
- package/dist/audit/store.js +18 -3
- package/dist/audit/store.js.map +1 -1
- package/dist/browser-sessions/store.d.ts.map +1 -1
- package/dist/browser-sessions/store.js +22 -7
- package/dist/browser-sessions/store.js.map +1 -1
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +51 -3
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/checkpoints/store.d.ts.map +1 -1
- package/dist/checkpoints/store.js +12 -3
- package/dist/checkpoints/store.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +9 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/collab/awareness.d.ts +1 -1
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/awareness.js +12 -8
- package/dist/collab/awareness.js.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +4 -3
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts.map +1 -1
- package/dist/collab/storage.js +14 -2
- package/dist/collab/storage.js.map +1 -1
- package/dist/db/ddl-guard.d.ts +63 -0
- package/dist/db/ddl-guard.d.ts.map +1 -1
- package/dist/db/ddl-guard.js +85 -0
- package/dist/db/ddl-guard.js.map +1 -1
- package/dist/extensions/store.d.ts.map +1 -1
- package/dist/extensions/store.js +32 -3
- package/dist/extensions/store.js.map +1 -1
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +44 -24
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/config-store.d.ts.map +1 -1
- package/dist/integrations/config-store.js +17 -11
- package/dist/integrations/config-store.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +24 -16
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/remote-commands-store.d.ts.map +1 -1
- package/dist/integrations/remote-commands-store.js +29 -21
- package/dist/integrations/remote-commands-store.js.map +1 -1
- package/dist/integrations/remote-devices-store.d.ts.map +1 -1
- package/dist/integrations/remote-devices-store.js +33 -18
- package/dist/integrations/remote-devices-store.js.map +1 -1
- package/dist/integrations/remote-push-store.d.ts.map +1 -1
- package/dist/integrations/remote-push-store.js +53 -31
- package/dist/integrations/remote-push-store.js.map +1 -1
- package/dist/integrations/remote-run-events-store.d.ts.map +1 -1
- package/dist/integrations/remote-run-events-store.js +26 -10
- package/dist/integrations/remote-run-events-store.js.map +1 -1
- package/dist/integrations/thread-mapping-store.d.ts.map +1 -1
- package/dist/integrations/thread-mapping-store.js +10 -2
- package/dist/integrations/thread-mapping-store.js.map +1 -1
- package/dist/mcp/connect-store.d.ts.map +1 -1
- package/dist/mcp/connect-store.js +34 -16
- package/dist/mcp/connect-store.js.map +1 -1
- package/dist/mcp/oauth-store.d.ts.map +1 -1
- package/dist/mcp/oauth-store.js +22 -7
- package/dist/mcp/oauth-store.js.map +1 -1
- package/dist/notifications/store.d.ts.map +1 -1
- package/dist/notifications/store.js +15 -3
- package/dist/notifications/store.js.map +1 -1
- package/dist/oauth-tokens/store.d.ts.map +1 -1
- package/dist/oauth-tokens/store.js +33 -2
- package/dist/oauth-tokens/store.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +72 -29
- package/dist/observability/store.js.map +1 -1
- package/dist/progress/store.d.ts.map +1 -1
- package/dist/progress/store.js +31 -16
- package/dist/progress/store.js.map +1 -1
- package/dist/provider-api/corpus-jobs-store.d.ts.map +1 -1
- package/dist/provider-api/corpus-jobs-store.js +16 -5
- package/dist/provider-api/corpus-jobs-store.js.map +1 -1
- package/dist/provider-api/custom-registry.d.ts.map +1 -1
- package/dist/provider-api/custom-registry.js +14 -4
- package/dist/provider-api/custom-registry.js.map +1 -1
- package/dist/provider-api/quota-governor.d.ts.map +1 -1
- package/dist/provider-api/quota-governor.js +12 -3
- package/dist/provider-api/quota-governor.js.map +1 -1
- package/dist/provider-api/staged-datasets-store.d.ts.map +1 -1
- package/dist/provider-api/staged-datasets-store.js +16 -5
- package/dist/provider-api/staged-datasets-store.js.map +1 -1
- package/dist/resources/store.d.ts.map +1 -1
- package/dist/resources/store.js +56 -25
- package/dist/resources/store.js.map +1 -1
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +10 -14
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/agent-teams-run-queue.d.ts.map +1 -1
- package/dist/server/agent-teams-run-queue.js +15 -4
- package/dist/server/agent-teams-run-queue.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +16 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +55 -21
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/embed-session.d.ts.map +1 -1
- package/dist/server/embed-session.js +15 -4
- package/dist/server/embed-session.js.map +1 -1
- package/dist/server/identity-sso-store.d.ts.map +1 -1
- package/dist/server/identity-sso-store.js +30 -11
- package/dist/server/identity-sso-store.js.map +1 -1
- package/dist/server/recap-image-store.d.ts.map +1 -1
- package/dist/server/recap-image-store.js +21 -7
- package/dist/server/recap-image-store.js.map +1 -1
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +11 -13
- package/dist/settings/store.js.map +1 -1
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +36 -11
- package/dist/usage/store.js.map +1 -1
- package/dist/workspace-connections/store.d.ts.map +1 -1
- package/dist/workspace-connections/store.js +57 -7
- package/dist/workspace-connections/store.js.map +1 -1
- package/package.json +3 -3
|
@@ -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)`,
|
|
@@ -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;
|