@agent-native/core 0.116.0 → 0.117.0

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.
Files changed (96) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +15 -0
  3. package/corpus/core/package.json +4 -1
  4. package/corpus/core/src/client/analytics.ts +7 -0
  5. package/corpus/core/src/client/use-db-sync.ts +354 -15
  6. package/corpus/core/src/collab/client.ts +26 -2
  7. package/corpus/core/src/db/ddl-guard.ts +49 -10
  8. package/corpus/core/src/deploy/build.ts +25 -2
  9. package/corpus/core/src/realtime-protocol.ts +92 -0
  10. package/corpus/core/src/server/core-routes-plugin.ts +7 -0
  11. package/corpus/core/src/server/poll-events.ts +29 -8
  12. package/corpus/core/src/server/poll.ts +1123 -865
  13. package/corpus/core/src/server/realtime-token.ts +106 -0
  14. package/corpus/core/src/server/sentry-config.ts +40 -0
  15. package/corpus/core/src/server/short-lived-token.ts +156 -0
  16. package/corpus/core/src/server/sse.ts +15 -0
  17. package/corpus/core/src/server/ssr-handler.ts +9 -3
  18. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +12 -0
  19. package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
  20. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +566 -299
  21. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +14 -0
  22. package/corpus/templates/content/app/i18n-data.ts +90 -0
  23. package/dist/client/analytics.d.ts +10 -0
  24. package/dist/client/analytics.d.ts.map +1 -1
  25. package/dist/client/analytics.js.map +1 -1
  26. package/dist/client/use-db-sync.d.ts +1 -1
  27. package/dist/client/use-db-sync.d.ts.map +1 -1
  28. package/dist/client/use-db-sync.js +315 -15
  29. package/dist/client/use-db-sync.js.map +1 -1
  30. package/dist/collab/client.d.ts.map +1 -1
  31. package/dist/collab/client.js +26 -2
  32. package/dist/collab/client.js.map +1 -1
  33. package/dist/db/ddl-guard.d.ts +7 -2
  34. package/dist/db/ddl-guard.d.ts.map +1 -1
  35. package/dist/db/ddl-guard.js +21 -9
  36. package/dist/db/ddl-guard.js.map +1 -1
  37. package/dist/deploy/build.d.ts.map +1 -1
  38. package/dist/deploy/build.js +25 -2
  39. package/dist/deploy/build.js.map +1 -1
  40. package/dist/notifications/routes.d.ts +3 -3
  41. package/dist/observability/routes.d.ts +5 -5
  42. package/dist/progress/routes.d.ts +1 -1
  43. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  44. package/dist/provider-api/actions/provider-api.d.ts +6 -6
  45. package/dist/realtime-protocol.d.ts +40 -0
  46. package/dist/realtime-protocol.d.ts.map +1 -0
  47. package/dist/realtime-protocol.js +69 -0
  48. package/dist/realtime-protocol.js.map +1 -0
  49. package/dist/resources/handlers.d.ts +1 -1
  50. package/dist/secrets/routes.d.ts +3 -3
  51. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  52. package/dist/server/core-routes-plugin.js +3 -0
  53. package/dist/server/core-routes-plugin.js.map +1 -1
  54. package/dist/server/poll-events.d.ts +7 -1
  55. package/dist/server/poll-events.d.ts.map +1 -1
  56. package/dist/server/poll-events.js +24 -7
  57. package/dist/server/poll-events.js.map +1 -1
  58. package/dist/server/poll.d.ts +223 -42
  59. package/dist/server/poll.d.ts.map +1 -1
  60. package/dist/server/poll.js +849 -737
  61. package/dist/server/poll.js.map +1 -1
  62. package/dist/server/realtime-token.d.ts +34 -0
  63. package/dist/server/realtime-token.d.ts.map +1 -0
  64. package/dist/server/realtime-token.js +85 -0
  65. package/dist/server/realtime-token.js.map +1 -0
  66. package/dist/server/sentry-config.d.ts +12 -0
  67. package/dist/server/sentry-config.d.ts.map +1 -1
  68. package/dist/server/sentry-config.js +34 -0
  69. package/dist/server/sentry-config.js.map +1 -1
  70. package/dist/server/short-lived-token.d.ts +46 -0
  71. package/dist/server/short-lived-token.d.ts.map +1 -1
  72. package/dist/server/short-lived-token.js +104 -0
  73. package/dist/server/short-lived-token.js.map +1 -1
  74. package/dist/server/sse.d.ts +1 -1
  75. package/dist/server/sse.d.ts.map +1 -1
  76. package/dist/server/sse.js +4 -0
  77. package/dist/server/sse.js.map +1 -1
  78. package/dist/server/ssr-handler.d.ts.map +1 -1
  79. package/dist/server/ssr-handler.js +5 -3
  80. package/dist/server/ssr-handler.js.map +1 -1
  81. package/dist/server/transcribe-voice.d.ts +1 -1
  82. package/package.json +4 -1
  83. package/src/client/analytics.ts +7 -0
  84. package/src/client/use-db-sync.ts +354 -15
  85. package/src/collab/client.ts +26 -2
  86. package/src/db/ddl-guard.ts +49 -10
  87. package/src/deploy/build.ts +25 -2
  88. package/src/realtime-protocol.ts +92 -0
  89. package/src/server/core-routes-plugin.ts +7 -0
  90. package/src/server/poll-events.ts +29 -8
  91. package/src/server/poll.ts +1123 -865
  92. package/src/server/realtime-token.ts +106 -0
  93. package/src/server/sentry-config.ts +40 -0
  94. package/src/server/short-lived-token.ts +156 -0
  95. package/src/server/sse.ts +15 -0
  96. package/src/server/ssr-handler.ts +9 -3
@@ -1 +1 @@
1
- {"version":3,"file":"poll.js","sourceRoot":"","sources":["../../src/server/poll.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Polling-based change notification.\n *\n * Replaces SSE with a simple version counter. Each DB mutation (app-state,\n * settings, resources) increments the version. Clients poll `/_agent-native/poll?since=N`\n * and receive any events that occurred after version N.\n *\n * Works in all deployment environments (serverless, edge, long-lived).\n *\n * Also detects cross-process DB writes by periodically checking the\n * application_state and settings tables' updated_at timestamps. This ensures\n * that changes made by external processes (e.g., CLI actions, cron jobs)\n * are picked up even though they don't call recordChange() in this process.\n */\n\nimport { EventEmitter } from \"node:events\";\n\nimport { defineEventHandler, getQuery, setResponseStatus } from \"h3\";\n\nimport {\n ACTION_CHANGE_MARKER_KEY,\n parseActionChangeMarker,\n type ActionChangeTarget,\n} from \"../action-change-marker.js\";\nimport { getAppStateEmitter } from \"../application-state/emitter.js\";\nimport { getDbExec, isPostgres } from \"../db/client.js\";\nimport { ensureIndexExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport {\n EXTENSION_CHANGE_MARKER_KEY,\n parseExtensionChangeMarker,\n type ExtensionChangeTarget,\n} from \"../extensions/change-marker.js\";\nimport { getSettingsEmitter } from \"../settings/store.js\";\nimport { getSession } from \"./auth.js\";\n\nexport interface ChangeEvent {\n version: number;\n source: string;\n type: string;\n key?: string;\n /**\n * Owner email for tenant-scoped events. When absent, the event is treated\n * as deployment-global (e.g. table-level \"something changed\" pings) and\n * delivered to every authenticated poller. Specific events that should\n * only fan out to one user MUST set this — otherwise polling clients\n * across tenants see each other's signals.\n */\n owner?: string;\n /** Optional org ID for org-scoped events. */\n orgId?: string;\n /**\n * Shareable resource type this event belongs to (e.g. \"document\"). When\n * present together with `resourceId`, the per-user delivery filter\n * (`canSeeChangeForUser`) can run an access-aware check so non-owner sharees\n * with explicit viewer+ access receive the push instead of only the poll\n * fallback. See the SYNC-CACHE note above `canSeeChangeForUser`.\n */\n resourceType?: string;\n /**\n * Shareable resource id this event belongs to. Paired with `resourceType`\n * to drive the access-aware delivery check in `canSeeChangeForUser`.\n */\n resourceId?: string;\n [k: string]: unknown;\n}\n\n// In-memory ring buffer of recent changes. Kept small since clients\n// poll frequently (every 2-3s) and only need events since their last poll.\nconst MAX_BUFFER = 200;\nconst DURABLE_READ_LIMIT = 1000;\nconst DURABLE_RETENTION_MS = 24 * 60 * 60 * 1000;\nconst LEGACY_DB_CHECK_INTERVAL_MS = 1000;\nconst DURABLE_LEGACY_DB_CHECK_INTERVAL_MS = 30_000;\nlet _version = 0;\nconst _buffer: ChangeEvent[] = [];\nexport const POLL_CHANGE_EVENT = \"poll-change\";\nconst _pollEmitter = new EventEmitter();\n_pollEmitter.setMaxListeners(0);\nlet _syncEventsInitPromise: Promise<boolean> | undefined;\nlet _lastDurablePrune = 0;\n\n/**\n * Whether we've seeded _version from the DB. In serverless (Netlify,\n * Vercel, etc.) each invocation starts fresh — without seeding, _version\n * resets to 0 and polling clients see the version jump backwards, causing\n * duplicate events and stuck UI.\n */\nlet _versionSeeded = false;\n\n/** Tracks the latest updated_at we've seen from the DB, per table. */\nlet _lastDbCheck = 0;\n// Coalesces concurrent checkExternalDbChanges runs. The 1s throttle alone does\n// not prevent overlap when a single check takes longer than 1s — two overlapping\n// runs would each read+advance the shared watermarks and double-emit events.\nlet _checkPromise: Promise<void> | null = null;\nlet _lastAppStateTs = 0;\nlet _lastSettingsTs = 0;\nlet _lastExtensionsTs = 0;\nlet _lastExtensionsUpdatedAt: string | number | undefined;\nlet _lastExtensionMarkerTs = 0;\nlet _lastActionMarkerTs = 0;\n\n/**\n * Tracks the latest updated_at seen on the `__screen_refresh__` key in\n * application_state. Bumped when the agent calls the `refresh-screen` tool,\n * and surfaced as a distinct `screen-refresh` event so clients can remount\n * the main content subtree via React key.\n *\n * `_screenRefreshInitialized` guards against spurious emits on the first\n * poll after a restart (where an existing row would look like a fresh bump).\n * Once we've taken a baseline reading, any subsequent increase emits.\n */\nlet _lastScreenRefreshTs = 0;\nlet _screenRefreshInitialized = false;\n// Per-session high-water marks for `__screen_refresh__`. Each user's row is\n// tracked independently so a refresh triggered by one user only remounts that\n// user's screen (owner-scoped), never every authenticated poller.\nconst _lastScreenRefreshTsBySession = new Map<string, number>();\nconst SCREEN_REFRESH_KEY = \"__screen_refresh__\";\nlet _localEmittersWired = false;\n\nfunction wireLocalEmitters(): void {\n if (_localEmittersWired) return;\n _localEmittersWired = true;\n getAppStateEmitter().on(\"app-state\", (event) => {\n if (\n event.key === EXTENSION_CHANGE_MARKER_KEY ||\n event.key === ACTION_CHANGE_MARKER_KEY\n ) {\n return;\n }\n recordChange(event);\n });\n getSettingsEmitter().on(\"settings\", (event) => {\n recordChange(event);\n });\n}\n\nfunction timestampValue(value: unknown): number {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value !== \"string\") return 0;\n const numeric = Number(value);\n if (Number.isFinite(numeric)) return numeric;\n const parsed = Date.parse(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nfunction sqlWatermarkValue(value: unknown): string | number | undefined {\n if (typeof value === \"string\" && value.length > 0) return value;\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n return undefined;\n}\n\nfunction syncEventsDisabled(): boolean {\n return (\n process.env.AGENT_NATIVE_SYNC_EVENTS_DISABLE === \"1\" ||\n (process.env.VITEST === \"true\" &&\n process.env.AGENT_NATIVE_SYNC_EVENTS_ENABLE_IN_TESTS !== \"1\")\n );\n}\n\nasync function ensureSyncEventsTable(): Promise<boolean> {\n if (syncEventsDisabled()) return false;\n if (!_syncEventsInitPromise) {\n _syncEventsInitPromise = (async () => {\n const client = getDbExec();\n const createSql = `\n CREATE TABLE IF NOT EXISTS sync_events (\n id TEXT PRIMARY KEY,\n version BIGINT NOT NULL,\n event_json TEXT NOT NULL,\n source TEXT NOT NULL,\n type TEXT NOT NULL,\n event_key TEXT,\n owner TEXT,\n org_id TEXT,\n resource_type TEXT,\n resource_id TEXT,\n created_at BIGINT NOT NULL\n )\n `;\n\n if (isPostgres()) {\n await ensureTableExists(\"sync_events\", createSql);\n await ensureIndexExists(\n \"sync_events_version_idx\",\n \"CREATE INDEX IF NOT EXISTS sync_events_version_idx ON sync_events (version)\",\n );\n await ensureIndexExists(\n \"sync_events_owner_version_idx\",\n \"CREATE INDEX IF NOT EXISTS sync_events_owner_version_idx ON sync_events (owner, version)\",\n );\n await ensureIndexExists(\n \"sync_events_org_version_idx\",\n \"CREATE INDEX IF NOT EXISTS sync_events_org_version_idx ON sync_events (org_id, version)\",\n );\n return true;\n }\n\n await client.execute(createSql);\n for (const ddl of [\n \"CREATE INDEX IF NOT EXISTS sync_events_version_idx ON sync_events (version)\",\n \"CREATE INDEX IF NOT EXISTS sync_events_owner_version_idx ON sync_events (owner, version)\",\n \"CREATE INDEX IF NOT EXISTS sync_events_org_version_idx ON sync_events (org_id, version)\",\n ]) {\n try {\n await client.execute(ddl);\n } catch {\n // Index already exists or the dialect rejected a duplicate.\n }\n }\n return true;\n })().catch(() => {\n _syncEventsInitPromise = undefined;\n return false;\n });\n }\n return _syncEventsInitPromise;\n}\n\nfunction durableEventId(version: number): string {\n return `${version}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nasync function pruneDurableEvents(client: ReturnType<typeof getDbExec>) {\n const now = Date.now();\n if (now - _lastDurablePrune < 5 * 60 * 1000) return;\n _lastDurablePrune = now;\n await client\n .execute({\n sql: \"DELETE FROM sync_events WHERE created_at < ?\",\n args: [now - DURABLE_RETENTION_MS],\n })\n .catch(() => {});\n}\n\nasync function persistSyncEvent(event: ChangeEvent): Promise<void> {\n if (!(await ensureSyncEventsTable())) return;\n const client = getDbExec();\n await client\n .execute({\n sql: isPostgres()\n ? `INSERT INTO sync_events (id, version, event_json, source, type, event_key, owner, org_id, resource_type, resource_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO NOTHING`\n : `INSERT OR IGNORE INTO sync_events (id, version, event_json, source, type, event_key, owner, org_id, resource_type, resource_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n durableEventId(event.version),\n event.version,\n JSON.stringify(event),\n event.source,\n event.type,\n event.key ?? null,\n event.owner ?? null,\n event.orgId ?? null,\n event.resourceType ?? null,\n event.resourceId ?? null,\n Date.now(),\n ],\n })\n .catch(() => {});\n await pruneDurableEvents(client);\n}\n\nasync function readMaxSyncEventVersion(): Promise<number> {\n if (!(await ensureSyncEventsTable())) return 0;\n try {\n const result = await getDbExec().execute(\n \"SELECT MAX(version) as max_version FROM sync_events\",\n );\n return timestampValue(result.rows[0]?.max_version);\n } catch {\n return 0;\n }\n}\n\nasync function readMaxUpdatedAtRaw(\n db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n },\n table: \"application_state\" | \"settings\" | \"tools\",\n): Promise<unknown> {\n try {\n const result = await db.execute(\n `SELECT MAX(updated_at) as max_ts FROM ${table}`,\n );\n return result.rows[0]?.max_ts;\n } catch {\n // Optional framework tables may not exist in every app yet.\n return undefined;\n }\n}\n\nasync function readMaxUpdatedAt(\n db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n },\n table: \"application_state\" | \"settings\" | \"tools\",\n): Promise<number> {\n return timestampValue(await readMaxUpdatedAtRaw(db, table));\n}\n\nasync function readExtensionMarkerMaxUpdatedAt(db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n}): Promise<number> {\n try {\n const result = await db.execute({\n sql: \"SELECT MAX(updated_at) as max_ts FROM application_state WHERE key = ?\",\n args: [EXTENSION_CHANGE_MARKER_KEY],\n });\n return timestampValue(result.rows[0]?.max_ts);\n } catch {\n return 0;\n }\n}\n\nasync function readActionMarkerMaxUpdatedAt(db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n}): Promise<number> {\n try {\n const result = await db.execute({\n sql: \"SELECT MAX(updated_at) as max_ts FROM application_state WHERE key = ?\",\n args: [ACTION_CHANGE_MARKER_KEY],\n });\n return timestampValue(result.rows[0]?.max_ts);\n } catch {\n return 0;\n }\n}\n\n/** Get the current global version counter. */\nexport function getVersion(): number {\n return _version;\n}\n\nexport function getPollEmitter(): EventEmitter {\n return _pollEmitter;\n}\n\n/**\n * In-memory, TTL'd access cache for the access-aware branch of\n * `canSeeChangeForUser`. Keyed by `${userEmail}|${resourceType}|${resourceId}`.\n *\n * Insertion order doubles as FIFO for eviction (JS Maps preserve insertion\n * order), so we can evict the oldest entries when we exceed the cap.\n */\nconst _accessCache = new Map<string, { allowed: boolean; checkedAt: number }>();\n/** In-flight background access checks, keyed identically, to dedupe bursts. */\nconst _accessInFlight = new Set<string>();\n/** Per-resource generation bumped when shares/visibility change. */\nconst _accessInvalidationEpoch = new Map<string, number>();\n/** TTL for an allowed (true) cache entry. */\nconst ACCESS_CACHE_TTL_MS = 30_000;\n/**\n * Shorter TTL for a denied (false) entry so a transient DB error (which we\n * fail-closed on) doesn't lock a legitimate user out of the push path for the\n * full 30s — they recover on their next event after this window.\n */\nconst ACCESS_CACHE_DENY_TTL_MS = 5_000;\n/** Max cache entries before FIFO eviction kicks in. */\nconst ACCESS_CACHE_MAX = 500;\n\nfunction accessCacheKey(\n userEmail: string,\n resourceType: string,\n resourceId: string,\n): string {\n return `${userEmail}|${resourceType}|${resourceId}`;\n}\n\nfunction accessResourceKey(resourceType: string, resourceId: string): string {\n return `${resourceType}|${resourceId}`;\n}\n\nfunction accessCacheTtl(allowed: boolean): number {\n return allowed ? ACCESS_CACHE_TTL_MS : ACCESS_CACHE_DENY_TTL_MS;\n}\n\nexport function invalidateCollabAccessCache(\n resourceType: string,\n resourceId: string,\n): void {\n const resourceKey = accessResourceKey(resourceType, resourceId);\n _accessInvalidationEpoch.set(\n resourceKey,\n (_accessInvalidationEpoch.get(resourceKey) ?? 0) + 1,\n );\n const suffix = `|${resourceKey}`;\n for (const key of Array.from(_accessCache.keys())) {\n if (key.endsWith(suffix)) _accessCache.delete(key);\n }\n for (const key of Array.from(_accessInFlight)) {\n if (key.endsWith(suffix)) _accessInFlight.delete(key);\n }\n}\n\nfunction setAccessCache(key: string, allowed: boolean, now: number): void {\n // Re-insert so the key moves to the end (most-recent) for FIFO ordering.\n _accessCache.delete(key);\n _accessCache.set(key, { allowed, checkedAt: now });\n if (_accessCache.size > ACCESS_CACHE_MAX) {\n // Evict the oldest entries (front of insertion order) back under the cap.\n const overflow = _accessCache.size - ACCESS_CACHE_MAX;\n let removed = 0;\n for (const oldestKey of _accessCache.keys()) {\n _accessCache.delete(oldestKey);\n if (++removed >= overflow) break;\n }\n }\n}\n\n/**\n * Fire a background access check for a cache-miss key. Never awaited by the\n * caller — the current event is NOT delivered (we returned false), but the\n * result is cached so the user's NEXT event within the TTL is pushed. Dedupes\n * concurrent checks for the same key via `_accessInFlight`.\n */\nfunction scheduleAccessCheck(\n key: string,\n resourceType: string,\n resourceId: string,\n userEmail: string,\n orgId: string | undefined,\n): void {\n if (_accessInFlight.has(key)) return;\n _accessInFlight.add(key);\n const resourceKey = accessResourceKey(resourceType, resourceId);\n const epoch = _accessInvalidationEpoch.get(resourceKey) ?? 0;\n void (async () => {\n try {\n // Dynamic import to avoid a load-order/circular-import hazard: poll.ts is\n // imported very widely, and the sharing/access module pulls in the\n // resource registry. Importing it lazily inside this background function\n // keeps the module graph acyclic at load time.\n const { resolveAccess } = await import(\"../sharing/access.js\");\n const access = await resolveAccess(resourceType, resourceId, {\n userEmail,\n orgId,\n });\n if ((_accessInvalidationEpoch.get(resourceKey) ?? 0) !== epoch) return;\n setAccessCache(key, access != null, Date.now());\n } catch {\n // Fail closed on any error (DB not ready, missing registration, etc.),\n // but with the short deny TTL so a transient failure self-heals quickly.\n if ((_accessInvalidationEpoch.get(resourceKey) ?? 0) !== epoch) return;\n setAccessCache(key, false, Date.now());\n } finally {\n _accessInFlight.delete(key);\n }\n })();\n}\n\n/**\n * Test-only: clear the access cache and in-flight set so cases don't bleed\n * into each other. Underscore-prefixed and intentionally NOT part of the\n * public API — do not rely on it outside tests.\n */\nexport function __resetCollabAccessCacheForTests(): void {\n _accessCache.clear();\n _accessInFlight.clear();\n _accessInvalidationEpoch.clear();\n}\n\ntype ChangeVisibility = \"visible\" | \"hidden\" | \"pending\";\ntype ChangeReadResult = {\n version: number;\n events: ChangeEvent[];\n /**\n * True when the returned version is an intentional cursor stop, not the\n * source high-water mark. This happens when access is still pending or when a\n * durable page hit the read limit and more rows may remain unread.\n */\n cursorLimited?: boolean;\n};\n\n/**\n * Decide whether a poll/SSE change event should be delivered to a user.\n *\n * SYNC-CACHE VARIANT — WHY THIS IS SYNCHRONOUS:\n * This function is called on hot, synchronous paths: the SSE emitter callback\n * `push(change)` in poll-events.ts (fires per event) and the\n * `getChangesSinceForUser` loop in this file. Making it async would be\n * invasive (it would ripple through both call sites and their emitters).\n * Instead, for the access-aware branch we consult an in-memory cache and, on a\n * miss, fire a NON-BLOCKING background access check and return `false` for the\n * current event. Because the poll fallback (`getChangesSinceForUser` on the\n * next `/poll` cycle) re-evaluates with the now-populated cache, delivery is\n * eventually guaranteed — the only cost is that the very first event for a\n * fresh (user, resource) pair goes over poll instead of push, and every\n * subsequent event within the TTL is pushed.\n *\n * Security: a cache MISS returns `false`, so we NEVER deliver to a user before\n * their access has been affirmatively confirmed by `resolveAccess` — the same\n * authority that gates the HTTP routes. Errors fail closed (cached deny). The\n * owner/org fast paths below are unchanged and evaluated first.\n */\nexport function canSeeChangeForUser(\n event: Pick<ChangeEvent, \"owner\" | \"orgId\" | \"resourceType\" | \"resourceId\">,\n userEmail: string,\n orgId: string | undefined,\n): boolean {\n return getChangeVisibilityForUser(event, userEmail, orgId) === \"visible\";\n}\n\nfunction getChangeVisibilityForUser(\n event: Pick<ChangeEvent, \"owner\" | \"orgId\" | \"resourceType\" | \"resourceId\">,\n userEmail: string,\n orgId: string | undefined,\n): ChangeVisibility {\n // Global / unowned events: every authenticated user gets them. Events that\n // predate resource tagging (owner/org only, no resourceType) keep the exact\n // conservative contract they had before.\n if (!event.owner && !event.orgId && !event.resourceType) return \"visible\";\n if (event.owner && event.owner === userEmail) return \"visible\";\n if (event.orgId && orgId && event.orgId === orgId) return \"visible\";\n\n // Access-aware branch: only when the event carries BOTH resourceType and\n // resourceId and the owner/org fast paths above did not already grant.\n if (event.resourceType && event.resourceId) {\n const key = accessCacheKey(userEmail, event.resourceType, event.resourceId);\n const cached = _accessCache.get(key);\n const now = Date.now();\n if (cached && now - cached.checkedAt < accessCacheTtl(cached.allowed)) {\n // Fresh, non-expired cache hit → trust the cached decision.\n return cached.allowed ? \"visible\" : \"hidden\";\n }\n // Miss or expired: do NOT deliver this event, but schedule the async check\n // so the user's next event (or poll cycle) resolves correctly.\n scheduleAccessCheck(\n key,\n event.resourceType,\n event.resourceId,\n userEmail,\n orgId,\n );\n return \"pending\";\n }\n\n return \"hidden\";\n}\n\n/** Record a change event. Called by emitter listeners. */\nexport function recordChange(event: {\n source: string;\n type: string;\n key?: string;\n [k: string]: unknown;\n}): void {\n // Use timestamp-aligned versions so all serverless instances produce\n // values in the same range (seeded from DB, then incremented via\n // Date.now). Plain ++counter diverges across cold starts.\n _version = Math.max(_version + 1, Date.now());\n const entry: ChangeEvent = { ...event, version: _version };\n _buffer.push(entry);\n if (_buffer.length > MAX_BUFFER) {\n _buffer.splice(0, _buffer.length - MAX_BUFFER);\n }\n _pollEmitter.emit(POLL_CHANGE_EVENT, entry);\n void persistSyncEvent(entry);\n}\n\nfunction extensionTargetKey(target: ExtensionChangeTarget): string | null {\n if (target.owner) return `owner:${target.owner}`;\n if (target.orgId) return `org:${target.orgId}`;\n return null;\n}\n\nfunction addExtensionTarget(\n targets: Map<string, ExtensionChangeTarget>,\n target: ExtensionChangeTarget,\n): void {\n const key = extensionTargetKey(target);\n if (key) targets.set(key, target);\n}\n\nfunction recordExtensionChanges(targets: ExtensionChangeTarget[]): void {\n const uniqueTargets = new Map<string, ExtensionChangeTarget>();\n for (const target of targets) addExtensionTarget(uniqueTargets, target);\n for (const target of uniqueTargets.values()) {\n recordChange({\n source: \"extensions\",\n type: \"change\",\n key: \"*\",\n ...(target.owner ? { owner: target.owner } : {}),\n ...(target.orgId ? { orgId: target.orgId } : {}),\n });\n }\n}\n\nfunction recordActionChanges(targets: ActionChangeTarget[]): void {\n for (const target of targets) {\n recordChange({\n source: \"action\",\n type: \"change\",\n key: target.actionName ?? \"*\",\n ...(target.owner ? { owner: target.owner } : {}),\n ...(target.orgId ? { orgId: target.orgId } : {}),\n ...(target.requestSource ? { requestSource: target.requestSource } : {}),\n });\n }\n}\n\nfunction extensionTargetsForRow(\n row: Record<string, unknown>,\n shareRows: Array<Record<string, unknown>>,\n): ExtensionChangeTarget[] {\n const targets = new Map<string, ExtensionChangeTarget>();\n const owner = typeof row.owner_email === \"string\" ? row.owner_email : \"\";\n const orgId = typeof row.org_id === \"string\" ? row.org_id : \"\";\n const visibility =\n typeof row.visibility === \"string\" ? row.visibility : \"private\";\n\n if (owner) addExtensionTarget(targets, { owner });\n if (visibility === \"org\" && orgId) addExtensionTarget(targets, { orgId });\n\n for (const share of shareRows) {\n const principalType =\n typeof share.principal_type === \"string\" ? share.principal_type : \"\";\n const principalId =\n typeof share.principal_id === \"string\" ? share.principal_id : \"\";\n if (principalType === \"user\" && principalId) {\n addExtensionTarget(targets, { owner: principalId });\n } else if (principalType === \"org\" && principalId) {\n addExtensionTarget(targets, { orgId: principalId });\n }\n }\n\n return Array.from(targets.values());\n}\n\nasync function readExtensionTargetsForRows(\n db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n },\n rows: Array<Record<string, unknown>>,\n): Promise<ExtensionChangeTarget[][]> {\n const ids = rows\n .map((row) => (typeof row.id === \"string\" ? row.id : \"\"))\n .filter(Boolean);\n const sharesByResourceId = new Map<string, Array<Record<string, unknown>>>();\n\n if (ids.length > 0) {\n try {\n const placeholders = ids.map(() => \"?\").join(\", \");\n const shareResult = await db.execute({\n sql: `SELECT resource_id, principal_type, principal_id FROM tool_shares WHERE resource_id IN (${placeholders})`,\n args: ids,\n });\n for (const share of shareResult.rows) {\n const resourceId =\n typeof share.resource_id === \"string\" ? share.resource_id : \"\";\n if (!resourceId) continue;\n const bucket = sharesByResourceId.get(resourceId) ?? [];\n bucket.push(share);\n sharesByResourceId.set(resourceId, bucket);\n }\n } catch {\n // Sharing tables are optional during early app initialization.\n }\n }\n\n return rows.map((row) =>\n extensionTargetsForRow(\n row,\n sharesByResourceId.get(typeof row.id === \"string\" ? row.id : \"\") ?? [],\n ),\n );\n}\n\n/** Get all changes after a given version. */\nexport function getChangesSince(since: number): {\n version: number;\n events: ChangeEvent[];\n} {\n if (since >= _version) {\n return { version: _version, events: [] };\n }\n const events = _buffer.filter((e) => e.version > since);\n return { version: _version, events };\n}\n\n/**\n * Get changes after a given version, filtered to events the caller is\n * allowed to see.\n *\n * Filtering rules:\n * - Events without an `owner`/`orgId`/`resourceType` are deployment-global\n * (table-level pings, screen-refresh, etc.) and visible to every\n * authenticated user.\n * - Events with `owner === userEmail` go to that user.\n * - Events with `orgId === orgId` go to anyone in that org.\n * - Events carrying `resourceType` + `resourceId` additionally reach explicit\n * viewer+ sharees via the access-aware cache in `canSeeChangeForUser`.\n * - All other owned events are filtered out.\n */\nexport function getChangesSinceForUser(\n since: number,\n userEmail: string,\n orgId: string | undefined,\n): ChangeReadResult {\n if (since >= _version) {\n return { version: _version, events: [] };\n }\n const events: ChangeEvent[] = [];\n let version = _version;\n for (const event of _buffer) {\n if (event.version <= since) continue;\n const visibility = getChangeVisibilityForUser(event, userEmail, orgId);\n if (visibility === \"visible\") {\n events.push(event);\n continue;\n }\n if (visibility === \"pending\") {\n version = Math.max(since, event.version - 1);\n return { version, events, cursorLimited: true };\n }\n }\n return { version, events };\n}\n\nasync function getDurableChangesSinceForUser(\n since: number,\n userEmail: string,\n orgId: string | undefined,\n): Promise<ChangeReadResult> {\n if (since <= 0 || !(await ensureSyncEventsTable())) {\n return { version: _version, events: [] };\n }\n\n try {\n // Scope the fetch to rows that could ever be visible to this caller\n // before paying to JSON.parse and visibility-check every deployment-wide\n // event: deployment-global rows (no owner, no org), the caller's own\n // rows, the caller's org's rows, and resource-scoped rows (owner/org\n // don't gate those — access is decided below by\n // `getChangeVisibilityForUser`'s access-aware branch, which can grant a\n // non-owner sharee, so resource-scoped rows must still flow through that\n // check regardless of who owns them). This lets Postgres/SQLite use the\n // `sync_events_owner_version_idx` / `sync_events_org_version_idx` indexes\n // instead of scanning every tenant's activity on every poll. The OR group\n // is parenthesized so `version > ?` ANDs against the whole group, not\n // just the first term. A caller with no org passes a null `orgId` bind\n // param, which makes `org_id = ?` evaluate to no match for every row\n // (including null-org rows) in both dialects — mirroring the\n // `event.orgId && orgId` truthy check in `getChangeVisibilityForUser`.\n const result = await getDbExec().execute({\n sql: `SELECT version, event_json FROM sync_events WHERE version > ?\n AND (\n (owner IS NULL AND org_id IS NULL)\n OR owner = ?\n OR org_id = ?\n OR resource_type IS NOT NULL\n )\n ORDER BY version ASC LIMIT ?`,\n args: [since, userEmail, orgId ?? null, DURABLE_READ_LIMIT + 1],\n });\n const events: ChangeEvent[] = [];\n let version = Math.max(_version, since);\n let lastDurableVersion = since;\n const rows = result.rows.slice(0, DURABLE_READ_LIMIT);\n const overflowVersion = timestampValue(\n result.rows[DURABLE_READ_LIMIT]?.version,\n );\n\n for (const row of rows) {\n const rawVersion = timestampValue(row.version);\n if (rawVersion > lastDurableVersion) lastDurableVersion = rawVersion;\n if (rawVersion > version) version = rawVersion;\n let event: ChangeEvent | null = null;\n try {\n const parsed = JSON.parse(String(row.event_json));\n if (\n parsed &&\n typeof parsed === \"object\" &&\n typeof parsed.source === \"string\" &&\n typeof parsed.type === \"string\"\n ) {\n event = {\n ...(parsed as ChangeEvent),\n version: rawVersion || (parsed as ChangeEvent).version,\n };\n }\n } catch {\n event = null;\n }\n if (!event) continue;\n\n const visibility = getChangeVisibilityForUser(event, userEmail, orgId);\n if (visibility === \"visible\") {\n events.push(event);\n continue;\n }\n if (visibility === \"pending\") {\n return {\n version: Math.max(since, event.version - 1),\n events,\n cursorLimited: true,\n };\n }\n }\n\n if (rows.length >= DURABLE_READ_LIMIT) {\n if (overflowVersion === lastDurableVersion) {\n const boundaryVersion = lastDurableVersion;\n return {\n version: Math.max(since, boundaryVersion - 1),\n events: events.filter((event) => event.version < boundaryVersion),\n cursorLimited: true,\n };\n }\n return {\n version: Math.max(since, lastDurableVersion),\n events,\n cursorLimited: true,\n };\n }\n\n return { version, events };\n } catch {\n return { version: _version, events: [] };\n }\n}\n\nasync function getCombinedChangesSinceForUser(\n since: number,\n userEmail: string,\n orgId: string | undefined,\n useDurableEvents: boolean,\n): Promise<{ version: number; events: ChangeEvent[] }> {\n const memory = getChangesSinceForUser(since, userEmail, orgId);\n if (!useDurableEvents) return memory;\n\n const durable = await getDurableChangesSinceForUser(since, userEmail, orgId);\n const byIdentity = new Map<string, ChangeEvent>();\n for (const event of [...durable.events, ...memory.events]) {\n byIdentity.set(\n JSON.stringify([\n event.version,\n event.source,\n event.type,\n event.key,\n event.owner,\n event.orgId,\n event.resourceType,\n event.resourceId,\n ]),\n event,\n );\n }\n const events = Array.from(byIdentity.values()).sort(\n (a, b) => a.version - b.version,\n );\n const limitedVersions = [memory, durable]\n .filter((result) => result.cursorLimited)\n .map((result) => result.version);\n return {\n version:\n limitedVersions.length > 0\n ? Math.min(...limitedVersions)\n : Math.max(memory.version, durable.version, since),\n events:\n limitedVersions.length > 0\n ? events.filter(\n (event) => event.version <= Math.min(...limitedVersions),\n )\n : events,\n };\n}\n\n/**\n * Seed _version from DB timestamps on the first call so serverless\n * cold starts don't return version 0 and confuse polling clients.\n */\nasync function seedVersionFromDb(): Promise<void> {\n if (_versionSeeded) return;\n _versionSeeded = true;\n\n try {\n const db = getDbExec();\n\n const [\n syncEventsTs,\n appTs,\n settingsTs,\n extensionsMaxUpdatedAt,\n extensionMarkerTs,\n actionMarkerTs,\n refreshResult,\n ] = await Promise.all([\n readMaxSyncEventVersion(),\n readMaxUpdatedAt(db, \"application_state\"),\n readMaxUpdatedAt(db, \"settings\"),\n readMaxUpdatedAtRaw(db, \"tools\"),\n readExtensionMarkerMaxUpdatedAt(db),\n readActionMarkerMaxUpdatedAt(db),\n db\n .execute({\n sql: \"SELECT session_id, updated_at FROM application_state WHERE key = ?\",\n args: [SCREEN_REFRESH_KEY],\n })\n .catch(() => ({ rows: [] as Record<string, unknown>[] })),\n ]);\n\n const extensionsTs = timestampValue(extensionsMaxUpdatedAt);\n let refreshTs = 0;\n for (const row of refreshResult.rows) {\n refreshTs = Math.max(refreshTs, timestampValue(row.updated_at));\n }\n\n // Seed version — never decrease an already-set value\n _version = Math.max(\n _version,\n syncEventsTs,\n appTs,\n settingsTs,\n extensionsTs,\n extensionMarkerTs,\n actionMarkerTs,\n );\n\n // Set baselines so checkExternalDbChanges detects future writes\n _lastAppStateTs = appTs;\n _lastSettingsTs = settingsTs;\n _lastExtensionsTs = extensionsTs;\n _lastExtensionsUpdatedAt = sqlWatermarkValue(extensionsMaxUpdatedAt);\n _lastExtensionMarkerTs = extensionMarkerTs;\n // Action markers are durable specifically so a web server can observe work\n // performed by a separate action process. Do not baseline past an existing\n // marker on cold start, or the first poll after the action will miss it.\n _lastActionMarkerTs = 0;\n _lastScreenRefreshTs = refreshTs;\n _lastScreenRefreshTsBySession.clear();\n for (const row of refreshResult.rows) {\n if (typeof row.session_id === \"string\") {\n _lastScreenRefreshTsBySession.set(\n row.session_id,\n timestampValue(row.updated_at),\n );\n }\n }\n _screenRefreshInitialized = true;\n // Skip the redundant cold-start recheck unless there is an existing durable\n // action marker that the first poll still needs to emit.\n _lastDbCheck = actionMarkerTs > 0 ? 0 : Date.now();\n } catch {\n // Tables may not exist yet — ignore\n }\n}\n\n/**\n * Check for cross-process DB writes by comparing updated_at timestamps.\n * Runs at most once per second to avoid excessive queries.\n */\nasync function checkExternalDbChanges(options: {\n durableEvents: boolean;\n}): Promise<void> {\n const now = Date.now();\n const interval = options.durableEvents\n ? DURABLE_LEGACY_DB_CHECK_INTERVAL_MS\n : LEGACY_DB_CHECK_INTERVAL_MS;\n if (now - _lastDbCheck < interval) return;\n // Coalesce: if a check is already running, await it instead of starting a\n // second overlapping run that would double-advance the shared watermarks\n // (and double-emit change events).\n if (_checkPromise) return _checkPromise;\n _lastDbCheck = now;\n _checkPromise = doCheckExternalDbChanges().finally(() => {\n _checkPromise = null;\n });\n return _checkPromise;\n}\n\nasync function doCheckExternalDbChanges(): Promise<void> {\n try {\n const db = getDbExec();\n\n // These reads are independent — each compares the DB against module-level\n // high-water marks (`_lastAppStateTs`, etc.) rather than another query's\n // result, and none of them mutate state before processing below. On a\n // serverless SQL backend every `await` is a network round-trip, so running\n // them concurrently shaves stacked latency off every poll cycle. Results\n // are still processed in the original sequential order, and conditional\n // follow-up queries (action/extension marker detail rows, tool-shares) stay\n // sequential within their branch where they depend on these results.\n const [\n appResult,\n actionMarkerTs,\n refreshResult,\n extensionMarkerTs,\n settingsTs,\n extensionsMaxUpdatedAt,\n ] = await Promise.all([\n db.execute({\n sql: \"SELECT session_id, key, updated_at FROM application_state WHERE updated_at > ? ORDER BY updated_at ASC\",\n args: [_lastAppStateTs],\n }),\n readActionMarkerMaxUpdatedAt(db),\n db.execute({\n sql: \"SELECT session_id, updated_at, value FROM application_state WHERE key = ?\",\n args: [SCREEN_REFRESH_KEY],\n }),\n readExtensionMarkerMaxUpdatedAt(db),\n readMaxUpdatedAt(db, \"settings\"),\n readMaxUpdatedAtRaw(db, \"tools\"),\n ]);\n\n // Check application_state for external writes. Preserve the changed key so\n // clients can invalidate one-shot command queries (`navigate`, `__set_url__`)\n // only when those command rows actually change; noisy keys such as\n // `slide-fit-check` should not wake navigation readers.\n if (appResult.rows.length > 0) {\n const appTs = appResult.rows.reduce(\n (max, row) => Math.max(max, timestampValue(row.updated_at)),\n _lastAppStateTs,\n );\n if (_lastAppStateTs > 0) {\n for (const row of appResult.rows) {\n const key = typeof row.key === \"string\" ? row.key : \"*\";\n if (\n key === EXTENSION_CHANGE_MARKER_KEY ||\n key === ACTION_CHANGE_MARKER_KEY\n ) {\n continue;\n }\n const owner =\n typeof row.session_id === \"string\" ? row.session_id : undefined;\n recordChange({\n source: \"app-state\",\n type: \"change\",\n key,\n ...(owner ? { owner } : {}),\n });\n }\n }\n _lastAppStateTs = appTs;\n }\n\n // Mutating actions write a durable marker in addition to the in-process\n // event. This lets dev-mode `pnpm action ...` child processes and\n // serverless action invocations wake the web server's SSE/poll loop as a\n // first-class source:\"action\" event rather than a generic app-state bump.\n // `actionMarkerTs` was read above; the detail-row query below is conditional\n // on it and depends on its result, so it stays sequential.\n if (actionMarkerTs > _lastActionMarkerTs) {\n const actionMarkerResult = await db.execute({\n sql: \"SELECT session_id, value, updated_at FROM application_state WHERE key = ? ORDER BY updated_at ASC\",\n args: [ACTION_CHANGE_MARKER_KEY],\n });\n const changedActionMarkers = actionMarkerResult.rows.filter(\n (row) => timestampValue(row.updated_at) > _lastActionMarkerTs,\n );\n recordActionChanges(\n changedActionMarkers\n .map((row) => parseActionChangeMarker(row.session_id, row.value))\n .filter((target): target is ActionChangeTarget => !!target),\n );\n _lastActionMarkerTs = actionMarkerTs;\n }\n\n // Check for screen-refresh requests from the agent. The `refresh-screen`\n // tool writes to application_state under a well-known key; when its\n // updated_at bumps, emit a distinct event so the client invalidates\n // all queries (not just the ones matching its default queryKey prefix).\n // `refreshResult` was read above.\n const refreshTs = refreshResult.rows.reduce(\n (max, row) => Math.max(max, timestampValue(row.updated_at)),\n 0,\n );\n if (!_screenRefreshInitialized) {\n _lastScreenRefreshTs = refreshTs;\n for (const row of refreshResult.rows) {\n if (typeof row.session_id === \"string\") {\n _lastScreenRefreshTsBySession.set(\n row.session_id,\n timestampValue(row.updated_at),\n );\n }\n }\n _screenRefreshInitialized = true;\n } else if (refreshTs > _lastScreenRefreshTs) {\n // Emit a per-user event only for the session(s) whose row actually\n // advanced, scoped with `owner` so canSeeChangeForUser delivers it only\n // to that user — not every authenticated poller.\n for (const row of refreshResult.rows) {\n const owner =\n typeof row.session_id === \"string\" ? row.session_id : undefined;\n if (!owner) continue;\n const rowTs = timestampValue(row.updated_at);\n if (rowTs <= (_lastScreenRefreshTsBySession.get(owner) ?? 0)) continue;\n let scope: string | undefined;\n try {\n const raw = row.value;\n if (typeof raw === \"string\") {\n const parsed = JSON.parse(raw);\n if (typeof parsed?.scope === \"string\") scope = parsed.scope;\n }\n } catch {}\n recordChange({\n source: \"screen-refresh\",\n type: \"change\",\n key: SCREEN_REFRESH_KEY,\n owner,\n ...(scope ? { scope } : {}),\n });\n _lastScreenRefreshTsBySession.set(owner, rowTs);\n }\n _lastScreenRefreshTs = refreshTs;\n }\n\n // Extension mutations write a durable marker row so delete and hide/unhide\n // operations are visible across serverless invocations. Translate those\n // marker rows back into extension-source events for targeted client\n // invalidation while preserving user/org scope. `extensionMarkerTs` was read\n // above; the detail-row query below depends on it and stays sequential.\n if (extensionMarkerTs > _lastExtensionMarkerTs) {\n const extensionMarkerResult = await db.execute({\n sql: \"SELECT session_id, value, updated_at FROM application_state WHERE key = ? ORDER BY updated_at ASC\",\n args: [EXTENSION_CHANGE_MARKER_KEY],\n });\n const changedExtensionMarkers = extensionMarkerResult.rows.filter(\n (row) => timestampValue(row.updated_at) > _lastExtensionMarkerTs,\n );\n if (_lastExtensionMarkerTs > 0) {\n recordExtensionChanges(\n changedExtensionMarkers\n .map((row) => parseExtensionChangeMarker(row.session_id, row.value))\n .filter((target): target is ExtensionChangeTarget => !!target),\n );\n }\n _lastExtensionMarkerTs = extensionMarkerTs;\n }\n\n // Check settings for external writes. `settingsTs` was read above.\n if (settingsTs > _lastSettingsTs) {\n if (_lastSettingsTs > 0) {\n recordChange({ source: \"settings\", type: \"change\", key: \"*\" });\n }\n _lastSettingsTs = settingsTs;\n }\n\n // Extension rows live in the legacy physical `tools` table. Keep this as a\n // compatibility fallback for direct table writes, but scope events to the\n // resource owner/share targets instead of broadcasting deployment-wide.\n // `extensionsMaxUpdatedAt` was read above; the per-row query below is\n // conditional on `extensionsTs` and stays sequential.\n const extensionsTs = timestampValue(extensionsMaxUpdatedAt);\n if (extensionsTs > _lastExtensionsTs) {\n const since = _lastExtensionsUpdatedAt;\n const extensionResult =\n since === undefined\n ? await db.execute({\n sql: \"SELECT id, owner_email, org_id, visibility, updated_at FROM tools ORDER BY updated_at ASC\",\n args: [],\n })\n : await db.execute({\n sql: \"SELECT id, owner_email, org_id, visibility, updated_at FROM tools WHERE updated_at > ? ORDER BY updated_at ASC\",\n args: [since],\n });\n const changedExtensionRows = extensionResult.rows.filter(\n (row) => timestampValue(row.updated_at) > _lastExtensionsTs,\n );\n if (_lastExtensionsTs > 0) {\n const targetsByRow = await readExtensionTargetsForRows(\n db,\n changedExtensionRows,\n );\n for (const targets of targetsByRow) recordExtensionChanges(targets);\n }\n _lastExtensionsTs = extensionsTs;\n _lastExtensionsUpdatedAt = sqlWatermarkValue(extensionsMaxUpdatedAt);\n }\n } catch {\n // Tables may not exist yet — ignore\n }\n}\n\n/**\n * Create an H3 handler for the poll endpoint.\n *\n * GET /_agent-native/poll?since=N → { version, events[] }\n *\n * Requires an authenticated session. Events are filtered to the caller's\n * tenant — global events (owner-less, table-level pings) reach every\n * authenticated caller; owned events reach only the matching user/org.\n * Without auth + filtering, an anonymous attacker could poll the deployment\n * and infer cross-tenant activity from the global event stream.\n */\nexport function createPollHandler() {\n wireLocalEmitters();\n return defineEventHandler(async (event) => {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { error: \"Unauthenticated\" };\n }\n // On cold start, seed _version from DB so we don't return version: 0\n await seedVersionFromDb();\n const durableEvents = await ensureSyncEventsTable();\n // Durable sync_events rows are the cheap cross-process path. Keep the\n // legacy watermark scan as a slower safety net for direct SQL writes and\n // older processes that have not started writing durable events yet.\n await checkExternalDbChanges({ durableEvents });\n\n const query = getQuery(event);\n const since = parseInt(String(query.since ?? \"0\"), 10) || 0;\n return getCombinedChangesSinceForUser(\n since,\n session.email,\n session.orgId,\n durableEvents,\n );\n });\n}\n"]}
1
+ {"version":3,"file":"poll.js","sourceRoot":"","sources":["../../src/server/poll.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Polling-based change notification.\n *\n * Replaces SSE with a simple version counter. Each DB mutation (app-state,\n * settings, resources) increments the version. Clients poll `/_agent-native/poll?since=N`\n * and receive any events that occurred after version N.\n *\n * Works in all deployment environments (serverless, edge, long-lived).\n *\n * Also detects cross-process DB writes by periodically checking the\n * application_state and settings tables' updated_at timestamps. This ensures\n * that changes made by external processes (e.g., CLI actions, cron jobs)\n * are picked up even though they don't call recordChange() in this process.\n *\n * All change-tracking state lives on an {@link AppSyncState} instance rather\n * than in module-level singletons, so a single process can hold one isolated\n * instance per app (the hosted Realtime Gateway serves many apps at once). The\n * module-level exports below delegate to a lazily-created default instance\n * bound to the process-global DB, so self-hosted apps run exactly one code\n * path with no behavioral change.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { EventEmitter } from \"node:events\";\n\nimport { defineEventHandler, getQuery, setResponseStatus } from \"h3\";\n\nimport {\n ACTION_CHANGE_MARKER_KEY,\n parseActionChangeMarker,\n type ActionChangeTarget,\n} from \"../action-change-marker.js\";\nimport { getAppStateEmitter } from \"../application-state/emitter.js\";\nimport { type DbExec, getDbExec, isPostgres } from \"../db/client.js\";\nimport { ensureIndexExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport {\n EXTENSION_CHANGE_MARKER_KEY,\n parseExtensionChangeMarker,\n type ExtensionChangeTarget,\n} from \"../extensions/change-marker.js\";\nimport { getSettingsEmitter } from \"../settings/store.js\";\nimport { getSession } from \"./auth.js\";\n\nexport interface ChangeEvent {\n version: number;\n source: string;\n type: string;\n key?: string;\n /**\n * Owner email for tenant-scoped events. When absent, the event is treated\n * as deployment-global (e.g. table-level \"something changed\" pings) and\n * delivered to every authenticated poller. Specific events that should\n * only fan out to one user MUST set this — otherwise polling clients\n * across tenants see each other's signals.\n */\n owner?: string;\n /** Optional org ID for org-scoped events. */\n orgId?: string;\n /**\n * Shareable resource type this event belongs to (e.g. \"document\"). When\n * present together with `resourceId`, the per-user delivery filter\n * (`canSeeChangeForUser`) can run an access-aware check so non-owner sharees\n * with explicit viewer+ access receive the push instead of only the poll\n * fallback. See the SYNC-CACHE note above `canSeeChangeForUser`.\n */\n resourceType?: string;\n /**\n * Shareable resource id this event belongs to. Paired with `resourceType`\n * to drive the access-aware delivery check in `canSeeChangeForUser`.\n */\n resourceId?: string;\n [k: string]: unknown;\n}\n\n// In-memory ring buffer of recent changes. Kept small since clients\n// poll frequently (every 2-3s) and only need events since their last poll.\nconst MAX_BUFFER = 200;\nconst DURABLE_READ_LIMIT = 1000;\nconst DURABLE_RETENTION_MS = 24 * 60 * 60 * 1000;\nconst LEGACY_DB_CHECK_INTERVAL_MS = 1000;\nexport const DURABLE_LEGACY_DB_CHECK_INTERVAL_MS = 30_000;\nexport const POLL_CHANGE_EVENT = \"poll-change\";\n\n/** TTL for an allowed (true) cache entry. */\nconst ACCESS_CACHE_TTL_MS = 30_000;\n/**\n * Shorter TTL for a denied (false) entry so a transient DB error (which we\n * fail-closed on) doesn't lock a legitimate user out of the push path for the\n * full 30s — they recover on their next event after this window.\n */\nconst ACCESS_CACHE_DENY_TTL_MS = 5_000;\n/** Max cache entries before FIFO eviction kicks in. */\nconst ACCESS_CACHE_MAX = 500;\nconst SCREEN_REFRESH_KEY = \"__screen_refresh__\";\n\nfunction timestampValue(value: unknown): number {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value !== \"string\") return 0;\n const numeric = Number(value);\n if (Number.isFinite(numeric)) return numeric;\n const parsed = Date.parse(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nfunction sqlWatermarkValue(value: unknown): string | number | undefined {\n if (typeof value === \"string\" && value.length > 0) return value;\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n return undefined;\n}\n\nfunction syncEventsDisabled(): boolean {\n return (\n process.env.AGENT_NATIVE_SYNC_EVENTS_DISABLE === \"1\" ||\n (process.env.VITEST === \"true\" &&\n process.env.AGENT_NATIVE_SYNC_EVENTS_ENABLE_IN_TESTS !== \"1\")\n );\n}\n\nasync function readMaxUpdatedAtRaw(\n db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n },\n table: \"application_state\" | \"settings\" | \"tools\",\n): Promise<unknown> {\n try {\n const result = await db.execute(\n `SELECT MAX(updated_at) as max_ts FROM ${table}`,\n );\n return result.rows[0]?.max_ts;\n } catch {\n // Optional framework tables may not exist in every app yet.\n return undefined;\n }\n}\n\nasync function readMaxUpdatedAt(\n db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n },\n table: \"application_state\" | \"settings\" | \"tools\",\n): Promise<number> {\n return timestampValue(await readMaxUpdatedAtRaw(db, table));\n}\n\nasync function readExtensionMarkerMaxUpdatedAt(db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n}): Promise<number> {\n try {\n const result = await db.execute({\n sql: \"SELECT MAX(updated_at) as max_ts FROM application_state WHERE key = ?\",\n args: [EXTENSION_CHANGE_MARKER_KEY],\n });\n return timestampValue(result.rows[0]?.max_ts);\n } catch {\n return 0;\n }\n}\n\nasync function readActionMarkerMaxUpdatedAt(db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n}): Promise<number> {\n try {\n const result = await db.execute({\n sql: \"SELECT MAX(updated_at) as max_ts FROM application_state WHERE key = ?\",\n args: [ACTION_CHANGE_MARKER_KEY],\n });\n return timestampValue(result.rows[0]?.max_ts);\n } catch {\n return 0;\n }\n}\n\nfunction accessCacheKey(\n userEmail: string,\n orgId: string | undefined,\n resourceType: string,\n resourceId: string,\n): string {\n // orgId is part of the key: org visibility and org shares are org-scoped, so a\n // user in multiple orgs must not reuse an org-A decision under an org-B\n // session. The trailing `|resourceType|resourceId` still lets\n // invalidateCollabAccessCache match by suffix.\n return `${userEmail}|${orgId ?? \"\"}|${resourceType}|${resourceId}`;\n}\n\nfunction accessResourceKey(resourceType: string, resourceId: string): string {\n return `${resourceType}|${resourceId}`;\n}\n\nfunction accessCacheTtl(allowed: boolean): number {\n return allowed ? ACCESS_CACHE_TTL_MS : ACCESS_CACHE_DENY_TTL_MS;\n}\n\nfunction extensionTargetKey(target: ExtensionChangeTarget): string | null {\n if (target.owner) return `owner:${target.owner}`;\n if (target.orgId) return `org:${target.orgId}`;\n return null;\n}\n\nfunction addExtensionTarget(\n targets: Map<string, ExtensionChangeTarget>,\n target: ExtensionChangeTarget,\n): void {\n const key = extensionTargetKey(target);\n if (key) targets.set(key, target);\n}\n\nfunction extensionTargetsForRow(\n row: Record<string, unknown>,\n shareRows: Array<Record<string, unknown>>,\n): ExtensionChangeTarget[] {\n const targets = new Map<string, ExtensionChangeTarget>();\n const owner = typeof row.owner_email === \"string\" ? row.owner_email : \"\";\n const orgId = typeof row.org_id === \"string\" ? row.org_id : \"\";\n const visibility =\n typeof row.visibility === \"string\" ? row.visibility : \"private\";\n\n if (owner) addExtensionTarget(targets, { owner });\n if (visibility === \"org\" && orgId) addExtensionTarget(targets, { orgId });\n\n for (const share of shareRows) {\n const principalType =\n typeof share.principal_type === \"string\" ? share.principal_type : \"\";\n const principalId =\n typeof share.principal_id === \"string\" ? share.principal_id : \"\";\n if (principalType === \"user\" && principalId) {\n addExtensionTarget(targets, { owner: principalId });\n } else if (principalType === \"org\" && principalId) {\n addExtensionTarget(targets, { orgId: principalId });\n }\n }\n\n return Array.from(targets.values());\n}\n\nasync function readExtensionTargetsForRows(\n db: {\n execute: (\n query: string | { sql: string; args?: unknown[] },\n ) => Promise<{ rows: Array<Record<string, unknown>> }>;\n },\n rows: Array<Record<string, unknown>>,\n): Promise<ExtensionChangeTarget[][]> {\n const ids = rows\n .map((row) => (typeof row.id === \"string\" ? row.id : \"\"))\n .filter(Boolean);\n const sharesByResourceId = new Map<string, Array<Record<string, unknown>>>();\n\n if (ids.length > 0) {\n try {\n const placeholders = ids.map(() => \"?\").join(\", \");\n const shareResult = await db.execute({\n sql: `SELECT resource_id, principal_type, principal_id FROM tool_shares WHERE resource_id IN (${placeholders})`,\n args: ids,\n });\n for (const share of shareResult.rows) {\n const resourceId =\n typeof share.resource_id === \"string\" ? share.resource_id : \"\";\n if (!resourceId) continue;\n const bucket = sharesByResourceId.get(resourceId) ?? [];\n bucket.push(share);\n sharesByResourceId.set(resourceId, bucket);\n }\n } catch {\n // Sharing tables are optional during early app initialization.\n }\n }\n\n return rows.map((row) =>\n extensionTargetsForRow(\n row,\n sharesByResourceId.get(typeof row.id === \"string\" ? row.id : \"\") ?? [],\n ),\n );\n}\n\ntype ChangeVisibility = \"visible\" | \"hidden\" | \"pending\";\n\nexport type ChangeReadResult = {\n version: number;\n events: ChangeEvent[];\n /**\n * True when the returned version is an intentional cursor stop, not the\n * source high-water mark. This happens when access is still pending or when a\n * durable page hit the read limit and more rows may remain unread.\n */\n cursorLimited?: boolean;\n};\n\n/**\n * Resolve whether `userEmail`/`orgId` may access a shareable resource. Injected\n * so the hosted gateway can bind the check to a specific app's resource\n * registry + DB; the default resolves the framework's process-global registry\n * lazily to avoid a load-order/circular-import hazard (poll.ts is imported very\n * widely and the sharing module pulls in the resource registry).\n */\nexport type AccessResolver = (\n resourceType: string,\n resourceId: string,\n ctx: { userEmail: string; orgId: string | undefined },\n) => Promise<unknown | null>;\n\nconst defaultResolveAccess: AccessResolver = async (\n resourceType,\n resourceId,\n ctx,\n) => {\n const { resolveAccess } = await import(\"../sharing/access.js\");\n return resolveAccess(resourceType, resourceId, ctx);\n};\n\nexport interface AppSyncStateOptions {\n /**\n * Per-app DB accessor. Called per query (not memoized here) so a mocked or\n * hot-swapped exec is always honored. Defaults to the process-global\n * `getDbExec`.\n */\n getDb?: () => DbExec;\n /** Whether this app's DB is Postgres. Defaults to the process-global check. */\n isPostgres?: () => boolean;\n /** Access-aware delivery resolver. Defaults to the framework registry. */\n resolveAccess?: AccessResolver;\n /**\n * Derive durable-event ids deterministically from the event's logical\n * identity plus a caller-supplied dedupe signal (the source row's\n * `updated_at`), instead of the default `version-<random>` id.\n *\n * Off by default: a single-process app has one writer, so random ids are\n * fine and `ON CONFLICT (id) DO NOTHING` never needs to fire. The hosted\n * gateway sets this so two instances that independently detect the same\n * out-of-band write persist the SAME id and dedupe to one row. The signal\n * intentionally excludes `version` (which is per-instance) so it collides\n * across instances.\n */\n deterministicEventIds?: boolean;\n}\n\n/**\n * Per-app change-tracking state and read path. One instance per deployed app.\n * The framework runs a single default instance ({@link getDefaultAppSyncState})\n * bound to the process DB; the hosted Realtime Gateway constructs one instance\n * per app with that app's pooled Neon connection injected.\n */\nexport class AppSyncState {\n private readonly getDb: () => DbExec;\n private readonly isPg: () => boolean;\n private readonly resolveAccessFn: AccessResolver;\n private readonly deterministicEventIds: boolean;\n\n // Timestamp-aligned versions so all serverless instances produce values in\n // the same range (seeded from DB, then incremented via Date.now). Plain\n // ++counter diverges across cold starts.\n private version = 0;\n private readonly buffer: ChangeEvent[] = [];\n private readonly pollEmitter = new EventEmitter();\n private syncEventsInitPromise: Promise<boolean> | undefined;\n private lastDurablePrune = 0;\n\n /**\n * Whether we've seeded `version` from the DB. In serverless (Netlify,\n * Vercel, etc.) each invocation starts fresh — without seeding, `version`\n * resets to 0 and polling clients see the version jump backwards, causing\n * duplicate events and stuck UI.\n */\n private versionSeeded = false;\n\n private lastDbCheck = 0;\n // Coalesces concurrent checkExternalDbChanges runs. The throttle alone does\n // not prevent overlap when a single check takes longer than the interval —\n // two overlapping runs would each read+advance the watermarks and double-emit.\n private checkPromise: Promise<void> | null = null;\n private lastAppStateTs = 0;\n private lastSettingsTs = 0;\n private lastExtensionsTs = 0;\n private lastExtensionsUpdatedAt: string | number | undefined;\n private lastExtensionMarkerTs = 0;\n private lastActionMarkerTs = 0;\n\n /**\n * Tracks the latest updated_at seen on the `__screen_refresh__` key.\n * `screenRefreshInitialized` guards against spurious emits on the first poll\n * after a restart (where an existing row would look like a fresh bump).\n */\n private lastScreenRefreshTs = 0;\n private screenRefreshInitialized = false;\n private readonly lastScreenRefreshTsBySession = new Map<string, number>();\n private localEmittersWired = false;\n\n /**\n * TTL'd access cache for the access-aware branch of `canSeeChangeForUser`,\n * keyed `${userEmail}|${resourceType}|${resourceId}`. Insertion order doubles\n * as FIFO for eviction (JS Maps preserve insertion order). Held per-instance\n * so one gateway process serving many apps never leaks one app's cached\n * access decision into another app's delivery filter.\n */\n private readonly accessCache = new Map<\n string,\n { allowed: boolean; checkedAt: number }\n >();\n /** In-flight background access checks, keyed identically, to dedupe bursts. */\n private readonly accessInFlight = new Set<string>();\n /** Per-resource generation bumped when shares/visibility change. */\n private readonly accessInvalidationEpoch = new Map<string, number>();\n\n constructor(options: AppSyncStateOptions = {}) {\n this.getDb = options.getDb ?? getDbExec;\n this.isPg = options.isPostgres ?? isPostgres;\n this.resolveAccessFn = options.resolveAccess ?? defaultResolveAccess;\n this.deterministicEventIds = options.deterministicEventIds ?? false;\n this.pollEmitter.setMaxListeners(0);\n }\n\n /**\n * Durable-event id. Deterministic (hash of logical identity + `dedupeKey`,\n * excluding the per-instance `version`) when the instance opts in AND a\n * dedupe signal is supplied — that combination lets `ON CONFLICT (id) DO\n * NOTHING` collapse the same out-of-band write detected by multiple gateway\n * instances into one row. Otherwise the historical `version-<random>` id,\n * which is unique-per-write for a single-writer app.\n */\n private durableEventId(event: ChangeEvent, dedupeKey?: string): string {\n if (this.deterministicEventIds && dedupeKey !== undefined) {\n const identity = [\n event.source,\n event.type,\n event.key ?? \"\",\n event.owner ?? \"\",\n event.orgId ?? \"\",\n event.resourceType ?? \"\",\n event.resourceId ?? \"\",\n dedupeKey,\n ].join(\"\u0000\");\n return createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 32);\n }\n return `${event.version}-${Math.random().toString(36).slice(2, 10)}`;\n }\n\n /** Get the current version counter. */\n getVersion(): number {\n return this.version;\n }\n\n getPollEmitter(): EventEmitter {\n return this.pollEmitter;\n }\n\n /**\n * Wire the in-process app-state/settings emitters into `recordChange` so\n * same-process writes surface on the poll/SSE fast path. Idempotent. Only the\n * default (in-process) instance calls this — the gateway learns of changes by\n * tailing the DB, not from these process-global emitters.\n */\n wireLocalEmitters(): void {\n if (this.localEmittersWired) return;\n this.localEmittersWired = true;\n getAppStateEmitter().on(\"app-state\", (event) => {\n if (\n event.key === EXTENSION_CHANGE_MARKER_KEY ||\n event.key === ACTION_CHANGE_MARKER_KEY\n ) {\n return;\n }\n this.recordChange(event);\n });\n getSettingsEmitter().on(\"settings\", (event) => {\n this.recordChange(event);\n });\n }\n\n async ensureSyncEventsTable(): Promise<boolean> {\n if (syncEventsDisabled()) return false;\n if (!this.syncEventsInitPromise) {\n this.syncEventsInitPromise = (async () => {\n const client = this.getDb();\n const createSql = `\n CREATE TABLE IF NOT EXISTS sync_events (\n id TEXT PRIMARY KEY,\n version BIGINT NOT NULL,\n event_json TEXT NOT NULL,\n source TEXT NOT NULL,\n type TEXT NOT NULL,\n event_key TEXT,\n owner TEXT,\n org_id TEXT,\n resource_type TEXT,\n resource_id TEXT,\n created_at BIGINT NOT NULL\n )\n `;\n\n if (this.isPg()) {\n // Run DDL against THIS app's DB, not the process-global one — the\n // gateway injects a per-app getDb, and ddl-guard otherwise probes/\n // creates via the global exec. The dialect override matters for the\n // same reason: ddl-guard's own isPostgres() reads the process-global\n // DB config, which in a gateway process is not this app's dialect.\n const guardOptions = {\n injectedClient: client,\n dialectIsPostgres: true,\n };\n await ensureTableExists(\"sync_events\", createSql, guardOptions);\n await ensureIndexExists(\n \"sync_events_version_idx\",\n \"CREATE INDEX IF NOT EXISTS sync_events_version_idx ON sync_events (version)\",\n guardOptions,\n );\n await ensureIndexExists(\n \"sync_events_owner_version_idx\",\n \"CREATE INDEX IF NOT EXISTS sync_events_owner_version_idx ON sync_events (owner, version)\",\n guardOptions,\n );\n await ensureIndexExists(\n \"sync_events_org_version_idx\",\n \"CREATE INDEX IF NOT EXISTS sync_events_org_version_idx ON sync_events (org_id, version)\",\n guardOptions,\n );\n return true;\n }\n\n await client.execute(createSql);\n for (const ddl of [\n \"CREATE INDEX IF NOT EXISTS sync_events_version_idx ON sync_events (version)\",\n \"CREATE INDEX IF NOT EXISTS sync_events_owner_version_idx ON sync_events (owner, version)\",\n \"CREATE INDEX IF NOT EXISTS sync_events_org_version_idx ON sync_events (org_id, version)\",\n ]) {\n try {\n await client.execute(ddl);\n } catch {\n // Index already exists or the dialect rejected a duplicate.\n }\n }\n return true;\n })().catch(() => {\n this.syncEventsInitPromise = undefined;\n return false;\n });\n }\n return this.syncEventsInitPromise;\n }\n\n private async pruneDurableEvents(client: DbExec): Promise<void> {\n const now = Date.now();\n if (now - this.lastDurablePrune < 5 * 60 * 1000) return;\n this.lastDurablePrune = now;\n await client\n .execute({\n sql: \"DELETE FROM sync_events WHERE created_at < ?\",\n args: [now - DURABLE_RETENTION_MS],\n })\n .catch(() => {});\n }\n\n async persistSyncEvent(\n event: ChangeEvent,\n dedupeKey?: string,\n ): Promise<void> {\n if (!(await this.ensureSyncEventsTable())) return;\n const client = this.getDb();\n await client\n .execute({\n sql: this.isPg()\n ? `INSERT INTO sync_events (id, version, event_json, source, type, event_key, owner, org_id, resource_type, resource_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO NOTHING`\n : `INSERT OR IGNORE INTO sync_events (id, version, event_json, source, type, event_key, owner, org_id, resource_type, resource_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n this.durableEventId(event, dedupeKey),\n event.version,\n JSON.stringify(event),\n event.source,\n event.type,\n event.key ?? null,\n event.owner ?? null,\n event.orgId ?? null,\n event.resourceType ?? null,\n event.resourceId ?? null,\n Date.now(),\n ],\n })\n .catch(() => {});\n await this.pruneDurableEvents(client);\n }\n\n async readMaxSyncEventVersion(): Promise<number> {\n if (!(await this.ensureSyncEventsTable())) return 0;\n try {\n const result = await this.getDb().execute(\n \"SELECT MAX(version) as max_version FROM sync_events\",\n );\n return timestampValue(result.rows[0]?.max_version);\n } catch {\n return 0;\n }\n }\n\n /**\n * Oldest retained durable version. Used to detect a reconnect cursor that\n * predates the 24h retention window so the gateway can signal a full\n * resync instead of silently dropping events. One indexed aggregate over\n * `sync_events_version_idx`; no schema change.\n */\n async readMinSyncEventVersion(): Promise<number> {\n if (!(await this.ensureSyncEventsTable())) return 0;\n try {\n const result = await this.getDb().execute(\n \"SELECT MIN(version) as min_version FROM sync_events\",\n );\n return timestampValue(result.rows[0]?.min_version);\n } catch {\n return 0;\n }\n }\n\n invalidateCollabAccessCache(resourceType: string, resourceId: string): void {\n const resourceKey = accessResourceKey(resourceType, resourceId);\n this.accessInvalidationEpoch.set(\n resourceKey,\n (this.accessInvalidationEpoch.get(resourceKey) ?? 0) + 1,\n );\n const suffix = `|${resourceKey}`;\n for (const key of Array.from(this.accessCache.keys())) {\n if (key.endsWith(suffix)) this.accessCache.delete(key);\n }\n for (const key of Array.from(this.accessInFlight)) {\n if (key.endsWith(suffix)) this.accessInFlight.delete(key);\n }\n }\n\n private setAccessCache(key: string, allowed: boolean, now: number): void {\n // Re-insert so the key moves to the end (most-recent) for FIFO ordering.\n this.accessCache.delete(key);\n this.accessCache.set(key, { allowed, checkedAt: now });\n if (this.accessCache.size > ACCESS_CACHE_MAX) {\n // Evict the oldest entries (front of insertion order) back under the cap.\n const overflow = this.accessCache.size - ACCESS_CACHE_MAX;\n let removed = 0;\n for (const oldestKey of this.accessCache.keys()) {\n this.accessCache.delete(oldestKey);\n if (++removed >= overflow) break;\n }\n }\n }\n\n /**\n * Fire a background access check for a cache-miss key. Never awaited by the\n * caller — the current event is NOT delivered (we returned false), but the\n * result is cached so the user's NEXT event within the TTL is pushed. Dedupes\n * concurrent checks for the same key via `accessInFlight`.\n */\n private scheduleAccessCheck(\n key: string,\n resourceType: string,\n resourceId: string,\n userEmail: string,\n orgId: string | undefined,\n ): void {\n if (this.accessInFlight.has(key)) return;\n this.accessInFlight.add(key);\n const resourceKey = accessResourceKey(resourceType, resourceId);\n const epoch = this.accessInvalidationEpoch.get(resourceKey) ?? 0;\n void (async () => {\n try {\n const access = await this.resolveAccessFn(resourceType, resourceId, {\n userEmail,\n orgId,\n });\n if ((this.accessInvalidationEpoch.get(resourceKey) ?? 0) !== epoch) {\n return;\n }\n this.setAccessCache(key, access != null, Date.now());\n } catch {\n // Fail closed on any error (DB not ready, missing registration, etc.),\n // but with the short deny TTL so a transient failure self-heals quickly.\n if ((this.accessInvalidationEpoch.get(resourceKey) ?? 0) !== epoch) {\n return;\n }\n this.setAccessCache(key, false, Date.now());\n } finally {\n this.accessInFlight.delete(key);\n }\n })();\n }\n\n /**\n * Test-only: clear the access cache and in-flight set so cases don't bleed\n * into each other. Intentionally NOT part of the public API.\n */\n __resetAccessCacheForTests(): void {\n this.accessCache.clear();\n this.accessInFlight.clear();\n this.accessInvalidationEpoch.clear();\n }\n\n /**\n * Decide whether a poll/SSE change event should be delivered to a user.\n *\n * SYNC-CACHE VARIANT — WHY THIS IS SYNCHRONOUS:\n * This function is called on hot, synchronous paths: the SSE emitter callback\n * `push(change)` in poll-events.ts (fires per event) and the\n * `getChangesSinceForUser` loop in this file. Making it async would be\n * invasive. Instead, for the access-aware branch we consult an in-memory\n * cache and, on a miss, fire a NON-BLOCKING background access check and\n * return `false` for the current event. Because the poll fallback re-evaluates\n * with the now-populated cache, delivery is eventually guaranteed — the only\n * cost is that the very first event for a fresh (user, resource) pair goes\n * over poll instead of push, and every subsequent event within the TTL is\n * pushed.\n *\n * Security: a cache MISS returns `false`, so we NEVER deliver to a user before\n * their access has been affirmatively confirmed by the resolver — the same\n * authority that gates the HTTP routes. Errors fail closed (cached deny). The\n * owner/org fast paths below are unchanged and evaluated first.\n */\n canSeeChangeForUser(\n event: Pick<ChangeEvent, \"owner\" | \"orgId\" | \"resourceType\" | \"resourceId\">,\n userEmail: string,\n orgId: string | undefined,\n ): boolean {\n return (\n this.getChangeVisibilityForUser(event, userEmail, orgId) === \"visible\"\n );\n }\n\n private getChangeVisibilityForUser(\n event: Pick<ChangeEvent, \"owner\" | \"orgId\" | \"resourceType\" | \"resourceId\">,\n userEmail: string,\n orgId: string | undefined,\n ): ChangeVisibility {\n // Global / unowned events: every authenticated user gets them. Events that\n // predate resource tagging (owner/org only, no resourceType) keep the exact\n // conservative contract they had before.\n if (!event.owner && !event.orgId && !event.resourceType) return \"visible\";\n if (event.owner && event.owner === userEmail) return \"visible\";\n if (event.orgId && orgId && event.orgId === orgId) return \"visible\";\n\n // Access-aware branch: only when the event carries BOTH resourceType and\n // resourceId and the owner/org fast paths above did not already grant.\n if (event.resourceType && event.resourceId) {\n const key = accessCacheKey(\n userEmail,\n orgId,\n event.resourceType,\n event.resourceId,\n );\n const cached = this.accessCache.get(key);\n const now = Date.now();\n if (cached && now - cached.checkedAt < accessCacheTtl(cached.allowed)) {\n // Fresh, non-expired cache hit → trust the cached decision.\n return cached.allowed ? \"visible\" : \"hidden\";\n }\n // Miss or expired: do NOT deliver this event, but schedule the async check\n // so the user's next event (or poll cycle) resolves correctly.\n this.scheduleAccessCheck(\n key,\n event.resourceType,\n event.resourceId,\n userEmail,\n orgId,\n );\n return \"pending\";\n }\n\n return \"hidden\";\n }\n\n /**\n * Record a change event. Called by emitter listeners and the tail detector.\n * `dedupeKey` is a stable cross-instance signal (a source row's `updated_at`)\n * used only when the instance derives deterministic ids; it is a persistence\n * concern and never stored on the event object.\n */\n recordChange(\n event: {\n source: string;\n type: string;\n key?: string;\n [k: string]: unknown;\n },\n opts?: { dedupeKey?: string },\n ): void {\n this.version = Math.max(this.version + 1, Date.now());\n const entry: ChangeEvent = { ...event, version: this.version };\n this.buffer.push(entry);\n if (this.buffer.length > MAX_BUFFER) {\n this.buffer.splice(0, this.buffer.length - MAX_BUFFER);\n }\n this.pollEmitter.emit(POLL_CHANGE_EVENT, entry);\n void this.persistSyncEvent(entry, opts?.dedupeKey);\n }\n\n private recordExtensionChanges(\n targets: ExtensionChangeTarget[],\n dedupeKey?: string,\n ): void {\n const uniqueTargets = new Map<string, ExtensionChangeTarget>();\n for (const target of targets) addExtensionTarget(uniqueTargets, target);\n for (const target of uniqueTargets.values()) {\n this.recordChange(\n {\n source: \"extensions\",\n type: \"change\",\n key: \"*\",\n ...(target.owner ? { owner: target.owner } : {}),\n ...(target.orgId ? { orgId: target.orgId } : {}),\n },\n dedupeKey !== undefined\n ? {\n dedupeKey: `${dedupeKey}|${target.owner ?? \"\"}|${target.orgId ?? \"\"}`,\n }\n : undefined,\n );\n }\n }\n\n private recordActionChanges(\n targets: ActionChangeTarget[],\n dedupeKey?: string,\n ): void {\n for (const target of targets) {\n this.recordChange(\n {\n source: \"action\",\n type: \"change\",\n key: target.actionName ?? \"*\",\n ...(target.owner ? { owner: target.owner } : {}),\n ...(target.orgId ? { orgId: target.orgId } : {}),\n ...(target.requestSource\n ? { requestSource: target.requestSource }\n : {}),\n },\n dedupeKey !== undefined\n ? {\n dedupeKey: `${dedupeKey}|${target.actionName ?? \"\"}|${target.owner ?? \"\"}|${target.orgId ?? \"\"}`,\n }\n : undefined,\n );\n }\n }\n\n /** Get all changes after a given version. */\n getChangesSince(since: number): { version: number; events: ChangeEvent[] } {\n if (since >= this.version) {\n return { version: this.version, events: [] };\n }\n const events = this.buffer.filter((e) => e.version > since);\n return { version: this.version, events };\n }\n\n /**\n * Get changes after a given version, filtered to events the caller is\n * allowed to see.\n */\n getChangesSinceForUser(\n since: number,\n userEmail: string,\n orgId: string | undefined,\n ): ChangeReadResult {\n if (since >= this.version) {\n return { version: this.version, events: [] };\n }\n const events: ChangeEvent[] = [];\n let version = this.version;\n for (const event of this.buffer) {\n if (event.version <= since) continue;\n const visibility = this.getChangeVisibilityForUser(\n event,\n userEmail,\n orgId,\n );\n if (visibility === \"visible\") {\n events.push(event);\n continue;\n }\n if (visibility === \"pending\") {\n version = Math.max(since, event.version - 1);\n return { version, events, cursorLimited: true };\n }\n }\n return { version, events };\n }\n\n async getDurableChangesSinceForUser(\n since: number,\n userEmail: string,\n orgId: string | undefined,\n ): Promise<ChangeReadResult> {\n if (since <= 0 || !(await this.ensureSyncEventsTable())) {\n return { version: this.version, events: [] };\n }\n\n try {\n // Scope the fetch to rows that could ever be visible to this caller\n // before paying to JSON.parse and visibility-check every deployment-wide\n // event: deployment-global rows (no owner, no org), the caller's own\n // rows, the caller's org's rows, and resource-scoped rows (access is\n // decided below by the access-aware branch, which can grant a non-owner\n // sharee, so resource-scoped rows must still flow through that check\n // regardless of who owns them). A caller with no org passes a null\n // `orgId` bind param, which makes `org_id = ?` match no row in both\n // dialects — mirroring the `event.orgId && orgId` truthy check.\n const result = await this.getDb().execute({\n sql: `SELECT version, event_json FROM sync_events WHERE version > ?\n AND (\n (owner IS NULL AND org_id IS NULL)\n OR owner = ?\n OR org_id = ?\n OR resource_type IS NOT NULL\n )\n ORDER BY version ASC LIMIT ?`,\n args: [since, userEmail, orgId ?? null, DURABLE_READ_LIMIT + 1],\n });\n const events: ChangeEvent[] = [];\n let version = Math.max(this.version, since);\n let lastDurableVersion = since;\n const rows = result.rows.slice(0, DURABLE_READ_LIMIT);\n const overflowVersion = timestampValue(\n result.rows[DURABLE_READ_LIMIT]?.version,\n );\n\n for (const row of rows) {\n const rawVersion = timestampValue(row.version);\n if (rawVersion > lastDurableVersion) lastDurableVersion = rawVersion;\n if (rawVersion > version) version = rawVersion;\n let event: ChangeEvent | null = null;\n try {\n const parsed = JSON.parse(String(row.event_json));\n if (\n parsed &&\n typeof parsed === \"object\" &&\n typeof parsed.source === \"string\" &&\n typeof parsed.type === \"string\"\n ) {\n event = {\n ...(parsed as ChangeEvent),\n version: rawVersion || (parsed as ChangeEvent).version,\n };\n }\n } catch {\n event = null;\n }\n if (!event) continue;\n\n const visibility = this.getChangeVisibilityForUser(\n event,\n userEmail,\n orgId,\n );\n if (visibility === \"visible\") {\n events.push(event);\n continue;\n }\n if (visibility === \"pending\") {\n return {\n version: Math.max(since, event.version - 1),\n events,\n cursorLimited: true,\n };\n }\n }\n\n if (rows.length >= DURABLE_READ_LIMIT) {\n if (overflowVersion === lastDurableVersion) {\n const boundaryVersion = lastDurableVersion;\n return {\n version: Math.max(since, boundaryVersion - 1),\n events: events.filter((event) => event.version < boundaryVersion),\n cursorLimited: true,\n };\n }\n return {\n version: Math.max(since, lastDurableVersion),\n events,\n cursorLimited: true,\n };\n }\n\n return { version, events };\n } catch {\n return { version: this.version, events: [] };\n }\n }\n\n async getCombinedChangesSinceForUser(\n since: number,\n userEmail: string,\n orgId: string | undefined,\n useDurableEvents: boolean,\n ): Promise<{ version: number; events: ChangeEvent[] }> {\n const memory = this.getChangesSinceForUser(since, userEmail, orgId);\n if (!useDurableEvents) return memory;\n\n const durable = await this.getDurableChangesSinceForUser(\n since,\n userEmail,\n orgId,\n );\n const byIdentity = new Map<string, ChangeEvent>();\n for (const event of [...durable.events, ...memory.events]) {\n byIdentity.set(\n JSON.stringify([\n event.version,\n event.source,\n event.type,\n event.key,\n event.owner,\n event.orgId,\n event.resourceType,\n event.resourceId,\n ]),\n event,\n );\n }\n const events = Array.from(byIdentity.values()).sort(\n (a, b) => a.version - b.version,\n );\n const limitedVersions = [memory, durable]\n .filter((result) => result.cursorLimited)\n .map((result) => result.version);\n return {\n version:\n limitedVersions.length > 0\n ? Math.min(...limitedVersions)\n : Math.max(memory.version, durable.version, since),\n events:\n limitedVersions.length > 0\n ? events.filter(\n (event) => event.version <= Math.min(...limitedVersions),\n )\n : events,\n };\n }\n\n /**\n * Seed `version` from DB timestamps on the first call so serverless cold\n * starts don't return version 0 and confuse polling clients.\n */\n async seedVersionFromDb(): Promise<void> {\n if (this.versionSeeded) return;\n this.versionSeeded = true;\n\n try {\n const db = this.getDb();\n\n const [\n syncEventsTs,\n appTs,\n settingsTs,\n extensionsMaxUpdatedAt,\n extensionMarkerTs,\n actionMarkerTs,\n refreshResult,\n ] = await Promise.all([\n this.readMaxSyncEventVersion(),\n readMaxUpdatedAt(db, \"application_state\"),\n readMaxUpdatedAt(db, \"settings\"),\n readMaxUpdatedAtRaw(db, \"tools\"),\n readExtensionMarkerMaxUpdatedAt(db),\n readActionMarkerMaxUpdatedAt(db),\n db\n .execute({\n sql: \"SELECT session_id, updated_at FROM application_state WHERE key = ?\",\n args: [SCREEN_REFRESH_KEY],\n })\n .catch(() => ({ rows: [] as Record<string, unknown>[] })),\n ]);\n\n const extensionsTs = timestampValue(extensionsMaxUpdatedAt);\n let refreshTs = 0;\n for (const row of refreshResult.rows) {\n refreshTs = Math.max(refreshTs, timestampValue(row.updated_at));\n }\n\n // Seed version — never decrease an already-set value\n this.version = Math.max(\n this.version,\n syncEventsTs,\n appTs,\n settingsTs,\n extensionsTs,\n extensionMarkerTs,\n actionMarkerTs,\n );\n\n // Set baselines so checkExternalDbChanges detects future writes\n this.lastAppStateTs = appTs;\n this.lastSettingsTs = settingsTs;\n this.lastExtensionsTs = extensionsTs;\n this.lastExtensionsUpdatedAt = sqlWatermarkValue(extensionsMaxUpdatedAt);\n this.lastExtensionMarkerTs = extensionMarkerTs;\n // Action markers are durable specifically so a web server can observe work\n // performed by a separate action process. Do not baseline past an existing\n // marker on cold start, or the first poll after the action will miss it.\n this.lastActionMarkerTs = 0;\n this.lastScreenRefreshTs = refreshTs;\n this.lastScreenRefreshTsBySession.clear();\n for (const row of refreshResult.rows) {\n if (typeof row.session_id === \"string\") {\n this.lastScreenRefreshTsBySession.set(\n row.session_id,\n timestampValue(row.updated_at),\n );\n }\n }\n this.screenRefreshInitialized = true;\n // Skip the redundant cold-start recheck unless there is an existing durable\n // action marker that the first poll still needs to emit.\n this.lastDbCheck = actionMarkerTs > 0 ? 0 : Date.now();\n } catch {\n // Tables may not exist yet — ignore\n }\n }\n\n /**\n * Check for cross-process DB writes by comparing updated_at timestamps.\n * Throttled per instance.\n */\n async checkExternalDbChanges(options: {\n durableEvents: boolean;\n }): Promise<void> {\n const now = Date.now();\n const interval = options.durableEvents\n ? DURABLE_LEGACY_DB_CHECK_INTERVAL_MS\n : LEGACY_DB_CHECK_INTERVAL_MS;\n if (now - this.lastDbCheck < interval) return;\n // Coalesce: if a check is already running, await it instead of starting a\n // second overlapping run that would double-advance the watermarks.\n if (this.checkPromise) return this.checkPromise;\n this.lastDbCheck = now;\n this.checkPromise = this.doCheckExternalDbChanges().finally(() => {\n this.checkPromise = null;\n });\n return this.checkPromise;\n }\n\n private async doCheckExternalDbChanges(): Promise<void> {\n try {\n const db = this.getDb();\n\n // These reads are independent — each compares the DB against instance\n // high-water marks rather than another query's result. Run them\n // concurrently to shave stacked latency; results are still processed in\n // the original sequential order, and conditional follow-up queries stay\n // sequential within their branch.\n const [\n appResult,\n actionMarkerTs,\n refreshResult,\n extensionMarkerTs,\n settingsTs,\n extensionsMaxUpdatedAt,\n ] = await Promise.all([\n db.execute({\n sql: \"SELECT session_id, key, updated_at FROM application_state WHERE updated_at > ? ORDER BY updated_at ASC\",\n args: [this.lastAppStateTs],\n }),\n readActionMarkerMaxUpdatedAt(db),\n db.execute({\n sql: \"SELECT session_id, updated_at, value FROM application_state WHERE key = ?\",\n args: [SCREEN_REFRESH_KEY],\n }),\n readExtensionMarkerMaxUpdatedAt(db),\n readMaxUpdatedAt(db, \"settings\"),\n readMaxUpdatedAtRaw(db, \"tools\"),\n ]);\n\n // Check application_state for external writes. Preserve the changed key so\n // clients can invalidate one-shot command queries (`navigate`, `__set_url__`)\n // only when those command rows actually change; noisy keys such as\n // `slide-fit-check` should not wake navigation readers.\n if (appResult.rows.length > 0) {\n const appTs = appResult.rows.reduce(\n (max, row) => Math.max(max, timestampValue(row.updated_at)),\n this.lastAppStateTs,\n );\n if (this.lastAppStateTs > 0) {\n for (const row of appResult.rows) {\n const key = typeof row.key === \"string\" ? row.key : \"*\";\n if (\n key === EXTENSION_CHANGE_MARKER_KEY ||\n key === ACTION_CHANGE_MARKER_KEY\n ) {\n continue;\n }\n const owner =\n typeof row.session_id === \"string\" ? row.session_id : undefined;\n this.recordChange(\n {\n source: \"app-state\",\n type: \"change\",\n key,\n ...(owner ? { owner } : {}),\n },\n { dedupeKey: `app-state|${timestampValue(row.updated_at)}` },\n );\n }\n }\n this.lastAppStateTs = appTs;\n }\n\n // Mutating actions write a durable marker in addition to the in-process\n // event. This lets dev-mode `pnpm action ...` child processes and\n // serverless action invocations wake the web server's SSE/poll loop as a\n // first-class source:\"action\" event rather than a generic app-state bump.\n if (actionMarkerTs > this.lastActionMarkerTs) {\n const actionMarkerResult = await db.execute({\n sql: \"SELECT session_id, value, updated_at FROM application_state WHERE key = ? ORDER BY updated_at ASC\",\n args: [ACTION_CHANGE_MARKER_KEY],\n });\n const changedActionMarkers = actionMarkerResult.rows.filter(\n (row) => timestampValue(row.updated_at) > this.lastActionMarkerTs,\n );\n this.recordActionChanges(\n changedActionMarkers\n .map((row) => parseActionChangeMarker(row.session_id, row.value))\n .filter((target): target is ActionChangeTarget => !!target),\n `action|${actionMarkerTs}`,\n );\n this.lastActionMarkerTs = actionMarkerTs;\n }\n\n // Check for screen-refresh requests from the agent. The `refresh-screen`\n // tool writes to application_state under a well-known key; when its\n // updated_at bumps, emit a distinct event so the client invalidates\n // all queries (not just the ones matching its default queryKey prefix).\n const refreshTs = refreshResult.rows.reduce(\n (max, row) => Math.max(max, timestampValue(row.updated_at)),\n 0,\n );\n if (!this.screenRefreshInitialized) {\n this.lastScreenRefreshTs = refreshTs;\n for (const row of refreshResult.rows) {\n if (typeof row.session_id === \"string\") {\n this.lastScreenRefreshTsBySession.set(\n row.session_id,\n timestampValue(row.updated_at),\n );\n }\n }\n this.screenRefreshInitialized = true;\n } else if (refreshTs > this.lastScreenRefreshTs) {\n // Emit a per-user event only for the session(s) whose row actually\n // advanced, scoped with `owner` so canSeeChangeForUser delivers it only\n // to that user — not every authenticated poller.\n for (const row of refreshResult.rows) {\n const owner =\n typeof row.session_id === \"string\" ? row.session_id : undefined;\n if (!owner) continue;\n const rowTs = timestampValue(row.updated_at);\n if (rowTs <= (this.lastScreenRefreshTsBySession.get(owner) ?? 0)) {\n continue;\n }\n let scope: string | undefined;\n try {\n const raw = row.value;\n if (typeof raw === \"string\") {\n const parsed = JSON.parse(raw);\n if (typeof parsed?.scope === \"string\") scope = parsed.scope;\n }\n } catch {}\n this.recordChange(\n {\n source: \"screen-refresh\",\n type: \"change\",\n key: SCREEN_REFRESH_KEY,\n owner,\n ...(scope ? { scope } : {}),\n },\n { dedupeKey: `screen-refresh|${rowTs}` },\n );\n this.lastScreenRefreshTsBySession.set(owner, rowTs);\n }\n this.lastScreenRefreshTs = refreshTs;\n }\n\n // Extension mutations write a durable marker row so delete and hide/unhide\n // operations are visible across serverless invocations. Translate those\n // marker rows back into extension-source events for targeted client\n // invalidation while preserving user/org scope.\n if (extensionMarkerTs > this.lastExtensionMarkerTs) {\n const extensionMarkerResult = await db.execute({\n sql: \"SELECT session_id, value, updated_at FROM application_state WHERE key = ? ORDER BY updated_at ASC\",\n args: [EXTENSION_CHANGE_MARKER_KEY],\n });\n const changedExtensionMarkers = extensionMarkerResult.rows.filter(\n (row) => timestampValue(row.updated_at) > this.lastExtensionMarkerTs,\n );\n if (this.lastExtensionMarkerTs > 0) {\n this.recordExtensionChanges(\n changedExtensionMarkers\n .map((row) =>\n parseExtensionChangeMarker(row.session_id, row.value),\n )\n .filter((target): target is ExtensionChangeTarget => !!target),\n `ext-marker|${extensionMarkerTs}`,\n );\n }\n this.lastExtensionMarkerTs = extensionMarkerTs;\n }\n\n // Check settings for external writes.\n if (settingsTs > this.lastSettingsTs) {\n if (this.lastSettingsTs > 0) {\n this.recordChange(\n { source: \"settings\", type: \"change\", key: \"*\" },\n { dedupeKey: `settings|${settingsTs}` },\n );\n }\n this.lastSettingsTs = settingsTs;\n }\n\n // Extension rows live in the legacy physical `tools` table. Keep this as a\n // compatibility fallback for direct table writes, but scope events to the\n // resource owner/share targets instead of broadcasting deployment-wide.\n const extensionsTs = timestampValue(extensionsMaxUpdatedAt);\n if (extensionsTs > this.lastExtensionsTs) {\n const since = this.lastExtensionsUpdatedAt;\n const extensionResult =\n since === undefined\n ? await db.execute({\n sql: \"SELECT id, owner_email, org_id, visibility, updated_at FROM tools ORDER BY updated_at ASC\",\n args: [],\n })\n : await db.execute({\n sql: \"SELECT id, owner_email, org_id, visibility, updated_at FROM tools WHERE updated_at > ? ORDER BY updated_at ASC\",\n args: [since],\n });\n const changedExtensionRows = extensionResult.rows.filter(\n (row) => timestampValue(row.updated_at) > this.lastExtensionsTs,\n );\n if (this.lastExtensionsTs > 0) {\n const targetsByRow = await readExtensionTargetsForRows(\n db,\n changedExtensionRows,\n );\n targetsByRow.forEach((targets, i) => {\n this.recordExtensionChanges(\n targets,\n `ext-tools|${timestampValue(changedExtensionRows[i]?.updated_at)}`,\n );\n });\n }\n this.lastExtensionsTs = extensionsTs;\n this.lastExtensionsUpdatedAt = sqlWatermarkValue(\n extensionsMaxUpdatedAt,\n );\n }\n } catch {\n // Tables may not exist yet — ignore\n }\n }\n}\n\nlet _defaultState: AppSyncState | undefined;\n\n/**\n * The process-wide default instance, bound to the global DB. All module-level\n * exports delegate here so self-hosted apps run exactly one code path.\n */\nexport function getDefaultAppSyncState(): AppSyncState {\n if (!_defaultState) _defaultState = new AppSyncState();\n return _defaultState;\n}\n\n/** Get the current global version counter. */\nexport function getVersion(): number {\n return getDefaultAppSyncState().getVersion();\n}\n\nexport function getPollEmitter(): EventEmitter {\n return getDefaultAppSyncState().getPollEmitter();\n}\n\nexport function invalidateCollabAccessCache(\n resourceType: string,\n resourceId: string,\n): void {\n getDefaultAppSyncState().invalidateCollabAccessCache(\n resourceType,\n resourceId,\n );\n}\n\n/**\n * Test-only: clear the default instance's access cache. Underscore-prefixed and\n * intentionally NOT part of the public API — do not rely on it outside tests.\n */\nexport function __resetCollabAccessCacheForTests(): void {\n getDefaultAppSyncState().__resetAccessCacheForTests();\n}\n\nexport function canSeeChangeForUser(\n event: Pick<ChangeEvent, \"owner\" | \"orgId\" | \"resourceType\" | \"resourceId\">,\n userEmail: string,\n orgId: string | undefined,\n): boolean {\n return getDefaultAppSyncState().canSeeChangeForUser(event, userEmail, orgId);\n}\n\n/** Record a change event. Called by emitter listeners. */\nexport function recordChange(event: {\n source: string;\n type: string;\n key?: string;\n [k: string]: unknown;\n}): void {\n getDefaultAppSyncState().recordChange(event);\n}\n\n/** Get all changes after a given version. */\nexport function getChangesSince(since: number): {\n version: number;\n events: ChangeEvent[];\n} {\n return getDefaultAppSyncState().getChangesSince(since);\n}\n\n/**\n * Get changes after a given version, filtered to events the caller is\n * allowed to see.\n */\nexport function getChangesSinceForUser(\n since: number,\n userEmail: string,\n orgId: string | undefined,\n): ChangeReadResult {\n return getDefaultAppSyncState().getChangesSinceForUser(\n since,\n userEmail,\n orgId,\n );\n}\n\n/**\n * Create an H3 handler for the poll endpoint.\n *\n * GET /_agent-native/poll?since=N → { version, events[] }\n *\n * Requires an authenticated session. Events are filtered to the caller's\n * tenant — global events (owner-less, table-level pings) reach every\n * authenticated caller; owned events reach only the matching user/org.\n * Without auth + filtering, an anonymous attacker could poll the deployment\n * and infer cross-tenant activity from the global event stream.\n */\nexport function createPollHandler(\n state: AppSyncState = getDefaultAppSyncState(),\n) {\n // Only the default (in-process) instance wires the local emitters; a gateway\n // per-app instance learns of changes by tailing its own DB.\n if (state === getDefaultAppSyncState()) state.wireLocalEmitters();\n return defineEventHandler(async (event) => {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { error: \"Unauthenticated\" };\n }\n // On cold start, seed version from DB so we don't return version: 0\n await state.seedVersionFromDb();\n const durableEvents = await state.ensureSyncEventsTable();\n // Durable sync_events rows are the cheap cross-process path. Keep the\n // legacy watermark scan as a slower safety net for direct SQL writes and\n // older processes that have not started writing durable events yet.\n await state.checkExternalDbChanges({ durableEvents });\n\n const query = getQuery(event);\n const since = parseInt(String(query.since ?? \"0\"), 10) || 0;\n return state.getCombinedChangesSinceForUser(\n since,\n session.email,\n session.orgId,\n durableEvents,\n );\n });\n}\n"]}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Realtime subscribe-token mint endpoint.
3
+ *
4
+ * `GET /_agent-native/realtime-token` — the one Netlify request per page load
5
+ * that the hosted Realtime Gateway path needs. The SSR HTML/`.data` shell is a
6
+ * single impersonal, CDN-cached document (`guard:ssr-cache-shell`), so a
7
+ * per-visitor token cannot be baked into the page; the client mints it here
8
+ * after load. Same-origin + session-gated; sessionless requests get 401.
9
+ *
10
+ * The signed token binds this app's Builder project id (the gateway channel)
11
+ * and carries the app's own end-user identity (`owner` = session email, `orgId`
12
+ * = framework org) — the exact tuple `recordChange` stamps onto `sync_events`
13
+ * and the gateway feeds to `canSeeChangeForUser`. It is signed with the app's
14
+ * per-project HMAC secret, injected as a reserved env var at provision time.
15
+ */
16
+ /**
17
+ * Reserved env var holding the app's per-project HMAC secret. Injected by the
18
+ * Builder provisioning path (`SYSTEM_RESERVED_KEYS` + prod allowlist); see the
19
+ * Agent-Native Realtime Sync tech spec.
20
+ */
21
+ export declare const REALTIME_HMAC_SECRET_ENV = "AGENT_NATIVE_REALTIME_HMAC_SECRET";
22
+ export declare function getRealtimeSigningSecret(): string | undefined;
23
+ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
24
+ error: string;
25
+ token?: undefined;
26
+ expiresAt?: undefined;
27
+ ttlSeconds?: undefined;
28
+ } | {
29
+ error?: undefined;
30
+ token: string;
31
+ expiresAt: string;
32
+ ttlSeconds: number;
33
+ }>>;
34
+ //# sourceMappingURL=realtime-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-token.d.ts","sourceRoot":"","sources":["../../src/server/realtime-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAiBH;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,sCAAsC,CAAC;AAK5E,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,SAAS,CAE7D;AAED,wBAAgB,0BAA0B;;;;;;;;;;IA4DzC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Realtime subscribe-token mint endpoint.
3
+ *
4
+ * `GET /_agent-native/realtime-token` — the one Netlify request per page load
5
+ * that the hosted Realtime Gateway path needs. The SSR HTML/`.data` shell is a
6
+ * single impersonal, CDN-cached document (`guard:ssr-cache-shell`), so a
7
+ * per-visitor token cannot be baked into the page; the client mints it here
8
+ * after load. Same-origin + session-gated; sessionless requests get 401.
9
+ *
10
+ * The signed token binds this app's Builder project id (the gateway channel)
11
+ * and carries the app's own end-user identity (`owner` = session email, `orgId`
12
+ * = framework org) — the exact tuple `recordChange` stamps onto `sync_events`
13
+ * and the gateway feeds to `canSeeChangeForUser`. It is signed with the app's
14
+ * per-project HMAC secret, injected as a reserved env var at provision time.
15
+ */
16
+ import { defineEventHandler, getMethod, setResponseHeader, setResponseStatus, } from "h3";
17
+ import { getOrgContext } from "../org/context.js";
18
+ import { getSession } from "./auth.js";
19
+ import { resolveBuilderBranchProjectId } from "./builder-browser.js";
20
+ import { runWithRequestContext } from "./request-context.js";
21
+ import { isSameOriginRequest } from "./request-origin.js";
22
+ import { signRealtimeSubscribeToken } from "./short-lived-token.js";
23
+ /**
24
+ * Reserved env var holding the app's per-project HMAC secret. Injected by the
25
+ * Builder provisioning path (`SYSTEM_RESERVED_KEYS` + prod allowlist); see the
26
+ * Agent-Native Realtime Sync tech spec.
27
+ */
28
+ export const REALTIME_HMAC_SECRET_ENV = "AGENT_NATIVE_REALTIME_HMAC_SECRET";
29
+ /** Short TTL — validated at connect; the gateway rotates over the stream. */
30
+ const REALTIME_TOKEN_TTL_SECONDS = 600;
31
+ export function getRealtimeSigningSecret() {
32
+ return process.env[REALTIME_HMAC_SECRET_ENV]?.trim() || undefined;
33
+ }
34
+ export function createRealtimeTokenHandler() {
35
+ return defineEventHandler(async (event) => {
36
+ // Identity-bearing token, valid ~10 min — never cacheable by the browser or
37
+ // any intermediary. Set once up front so every return path carries it.
38
+ setResponseHeader(event, "Cache-Control", "private, no-store");
39
+ if (getMethod(event) !== "GET") {
40
+ setResponseStatus(event, 405);
41
+ return { error: "Method not allowed" };
42
+ }
43
+ if (!isSameOriginRequest(event)) {
44
+ setResponseStatus(event, 403);
45
+ return { error: "Cross-origin request rejected" };
46
+ }
47
+ const session = await getSession(event).catch(() => null);
48
+ if (!session?.email) {
49
+ setResponseStatus(event, 401);
50
+ return { error: "Authentication required" };
51
+ }
52
+ const orgCtx = await getOrgContext(event).catch(() => null);
53
+ const requestContext = {
54
+ userEmail: session.email,
55
+ orgId: orgCtx?.orgId ?? session.orgId,
56
+ };
57
+ // The scoped-secret fallback inside resolveBuilderBranchProjectId reads the
58
+ // request-context ALS (resolveSecret -> getRequestUserEmail); without it the
59
+ // user/org/workspace scopes silently no-op and only env vars resolve. Wrap
60
+ // the resolution like google-realtime-session.ts does.
61
+ return runWithRequestContext(requestContext, async () => {
62
+ // Async resolver so hosted apps whose project id lives in a
63
+ // request-scoped app/org/workspace secret (not an env var) also work —
64
+ // the sync env-only lookup would 404 them and silently drop the gateway.
65
+ const projectId = await resolveBuilderBranchProjectId();
66
+ const secret = getRealtimeSigningSecret();
67
+ if (!projectId || !secret) {
68
+ // Hosted realtime isn't provisioned for this app. 404 lets the client
69
+ // fall back to the app's own /_agent-native/poll without treating it
70
+ // as an auth failure.
71
+ setResponseStatus(event, 404);
72
+ return { error: "Realtime gateway not configured" };
73
+ }
74
+ const token = signRealtimeSubscribeToken({
75
+ projectId,
76
+ owner: session.email,
77
+ orgId: requestContext.orgId,
78
+ ttlSeconds: REALTIME_TOKEN_TTL_SECONDS,
79
+ }, secret);
80
+ const expiresAt = new Date(Date.now() + REALTIME_TOKEN_TTL_SECONDS * 1000).toISOString();
81
+ return { token, expiresAt, ttlSeconds: REALTIME_TOKEN_TTL_SECONDS };
82
+ });
83
+ });
84
+ }
85
+ //# sourceMappingURL=realtime-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-token.js","sourceRoot":"","sources":["../../src/server/realtime-token.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Realtime subscribe-token mint endpoint.\n *\n * `GET /_agent-native/realtime-token` — the one Netlify request per page load\n * that the hosted Realtime Gateway path needs. The SSR HTML/`.data` shell is a\n * single impersonal, CDN-cached document (`guard:ssr-cache-shell`), so a\n * per-visitor token cannot be baked into the page; the client mints it here\n * after load. Same-origin + session-gated; sessionless requests get 401.\n *\n * The signed token binds this app's Builder project id (the gateway channel)\n * and carries the app's own end-user identity (`owner` = session email, `orgId`\n * = framework org) — the exact tuple `recordChange` stamps onto `sync_events`\n * and the gateway feeds to `canSeeChangeForUser`. It is signed with the app's\n * per-project HMAC secret, injected as a reserved env var at provision time.\n */\n\nimport {\n defineEventHandler,\n getMethod,\n type H3Event,\n setResponseHeader,\n setResponseStatus,\n} from \"h3\";\n\nimport { getOrgContext } from \"../org/context.js\";\nimport { getSession } from \"./auth.js\";\nimport { resolveBuilderBranchProjectId } from \"./builder-browser.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { isSameOriginRequest } from \"./request-origin.js\";\nimport { signRealtimeSubscribeToken } from \"./short-lived-token.js\";\n\n/**\n * Reserved env var holding the app's per-project HMAC secret. Injected by the\n * Builder provisioning path (`SYSTEM_RESERVED_KEYS` + prod allowlist); see the\n * Agent-Native Realtime Sync tech spec.\n */\nexport const REALTIME_HMAC_SECRET_ENV = \"AGENT_NATIVE_REALTIME_HMAC_SECRET\";\n\n/** Short TTL — validated at connect; the gateway rotates over the stream. */\nconst REALTIME_TOKEN_TTL_SECONDS = 600;\n\nexport function getRealtimeSigningSecret(): string | undefined {\n return process.env[REALTIME_HMAC_SECRET_ENV]?.trim() || undefined;\n}\n\nexport function createRealtimeTokenHandler() {\n return defineEventHandler(async (event: H3Event) => {\n // Identity-bearing token, valid ~10 min — never cacheable by the browser or\n // any intermediary. Set once up front so every return path carries it.\n setResponseHeader(event, \"Cache-Control\", \"private, no-store\");\n\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!isSameOriginRequest(event)) {\n setResponseStatus(event, 403);\n return { error: \"Cross-origin request rejected\" };\n }\n\n const session = await getSession(event).catch(() => null);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { error: \"Authentication required\" };\n }\n\n const orgCtx = await getOrgContext(event).catch(() => null);\n const requestContext = {\n userEmail: session.email,\n orgId: orgCtx?.orgId ?? session.orgId,\n };\n\n // The scoped-secret fallback inside resolveBuilderBranchProjectId reads the\n // request-context ALS (resolveSecret -> getRequestUserEmail); without it the\n // user/org/workspace scopes silently no-op and only env vars resolve. Wrap\n // the resolution like google-realtime-session.ts does.\n return runWithRequestContext(requestContext, async () => {\n // Async resolver so hosted apps whose project id lives in a\n // request-scoped app/org/workspace secret (not an env var) also work —\n // the sync env-only lookup would 404 them and silently drop the gateway.\n const projectId = await resolveBuilderBranchProjectId();\n const secret = getRealtimeSigningSecret();\n if (!projectId || !secret) {\n // Hosted realtime isn't provisioned for this app. 404 lets the client\n // fall back to the app's own /_agent-native/poll without treating it\n // as an auth failure.\n setResponseStatus(event, 404);\n return { error: \"Realtime gateway not configured\" };\n }\n\n const token = signRealtimeSubscribeToken(\n {\n projectId,\n owner: session.email,\n orgId: requestContext.orgId,\n ttlSeconds: REALTIME_TOKEN_TTL_SECONDS,\n },\n secret,\n );\n const expiresAt = new Date(\n Date.now() + REALTIME_TOKEN_TTL_SECONDS * 1000,\n ).toISOString();\n return { token, expiresAt, ttlSeconds: REALTIME_TOKEN_TTL_SECONDS };\n });\n });\n}\n"]}
@@ -2,4 +2,16 @@ export declare function resolveSentryEnvironment(): string;
2
2
  export declare function resolveServerSentryDsn(): string | undefined;
3
3
  export declare function resolvePublicSentryDsn(): string | undefined;
4
4
  export declare function getSentryClientConfigScript(): string | null;
5
+ /**
6
+ * Hosted Realtime Gateway config for the client, or null for the in-process
7
+ * (local) transport. Values are env-derived and identical for every visitor,
8
+ * so this is safe inside the CDN-cached SSR shell (see `guard:ssr-cache-shell`).
9
+ * The per-user subscribe token is NOT here — it is minted client-side after
10
+ * load from `/_agent-native/realtime-token`.
11
+ */
12
+ export declare function resolveRealtimeClientConfig(): {
13
+ transport: "hosted";
14
+ gatewayBaseUrl: string;
15
+ } | null;
16
+ export declare function getRealtimeClientConfigScript(): string | null;
5
17
  //# sourceMappingURL=sentry-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sentry-config.d.ts","sourceRoot":"","sources":["../../src/server/sentry-config.ts"],"names":[],"mappings":"AA2BA,wBAAgB,wBAAwB,IAAI,MAAM,CASjD;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAK3D;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAS3D;AAED,wBAAgB,2BAA2B,IAAI,MAAM,GAAG,IAAI,CAgB3D"}
1
+ {"version":3,"file":"sentry-config.d.ts","sourceRoot":"","sources":["../../src/server/sentry-config.ts"],"names":[],"mappings":"AA2BA,wBAAgB,wBAAwB,IAAI,MAAM,CASjD;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAK3D;AAED,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,SAAS,CAS3D;AAED,wBAAgB,2BAA2B,IAAI,MAAM,GAAG,IAAI,CAgB3D;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,IAAI;IAC7C,SAAS,EAAE,QAAQ,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,IAAI,CAeP;AAED,wBAAgB,6BAA6B,IAAI,MAAM,GAAG,IAAI,CAW7D"}
@@ -40,4 +40,38 @@ export function getSentryClientConfigScript() {
40
40
  "</script>",
41
41
  ].join("");
42
42
  }
43
+ /**
44
+ * Hosted Realtime Gateway config for the client, or null for the in-process
45
+ * (local) transport. Values are env-derived and identical for every visitor,
46
+ * so this is safe inside the CDN-cached SSR shell (see `guard:ssr-cache-shell`).
47
+ * The per-user subscribe token is NOT here — it is minted client-side after
48
+ * load from `/_agent-native/realtime-token`.
49
+ */
50
+ export function resolveRealtimeClientConfig() {
51
+ // Fail closed: emit hosted config only when BOTH the transport is hosted AND
52
+ // an explicit gateway URL is set. No production default — this ships into the
53
+ // CDN-cached shell served to every visitor, so a mis-set staging/preview/
54
+ // self-hosted env must stay on the local transport rather than silently
55
+ // point every browser at api.builder.io. This gating is mirrored byte-for-
56
+ // byte in the worker emitter in `deploy/build.ts` (kept in sync deliberately).
57
+ if (firstNonEmpty(process.env.AGENT_NATIVE_REALTIME_TRANSPORT) !== "hosted") {
58
+ return null;
59
+ }
60
+ const gatewayBaseUrl = firstNonEmpty(process.env.AGENT_NATIVE_REALTIME_GATEWAY_URL);
61
+ if (!gatewayBaseUrl)
62
+ return null;
63
+ return { transport: "hosted", gatewayBaseUrl };
64
+ }
65
+ export function getRealtimeClientConfigScript() {
66
+ const realtime = resolveRealtimeClientConfig();
67
+ if (!realtime)
68
+ return null;
69
+ return [
70
+ "<script data-agent-native-realtime-config>",
71
+ "window.__AGENT_NATIVE_CONFIG__=Object.assign({},window.__AGENT_NATIVE_CONFIG__,",
72
+ JSON.stringify({ realtime }),
73
+ ");",
74
+ "</script>",
75
+ ].join("");
76
+ }
43
77
  //# sourceMappingURL=sentry-config.js.map