@agent-native/core 0.7.21 → 0.7.23

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 (163) hide show
  1. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  2. package/dist/agent/engine/ai-sdk-engine.js +43 -1
  3. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  4. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  5. package/dist/agent/engine/anthropic-engine.js +8 -0
  6. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  7. package/dist/agent/engine/builder-engine.d.ts +1 -1
  8. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  9. package/dist/agent/engine/builder-engine.js +9 -4
  10. package/dist/agent/engine/builder-engine.js.map +1 -1
  11. package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
  12. package/dist/agent/engine/translate-ai-sdk.js +31 -1
  13. package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
  14. package/dist/agent/engine/translate-anthropic.d.ts.map +1 -1
  15. package/dist/agent/engine/translate-anthropic.js +16 -0
  16. package/dist/agent/engine/translate-anthropic.js.map +1 -1
  17. package/dist/agent/engine/types.d.ts +16 -1
  18. package/dist/agent/engine/types.d.ts.map +1 -1
  19. package/dist/agent/engine/types.js.map +1 -1
  20. package/dist/agent/production-agent.d.ts +4 -0
  21. package/dist/agent/production-agent.d.ts.map +1 -1
  22. package/dist/agent/production-agent.js +96 -4
  23. package/dist/agent/production-agent.js.map +1 -1
  24. package/dist/agent/types.d.ts +3 -0
  25. package/dist/agent/types.d.ts.map +1 -1
  26. package/dist/agent/types.js.map +1 -1
  27. package/dist/cli/create.d.ts +2 -1
  28. package/dist/cli/create.d.ts.map +1 -1
  29. package/dist/cli/create.js +21 -14
  30. package/dist/cli/create.js.map +1 -1
  31. package/dist/client/AgentPanel.d.ts.map +1 -1
  32. package/dist/client/AgentPanel.js +5 -5
  33. package/dist/client/AgentPanel.js.map +1 -1
  34. package/dist/client/AssistantChat.d.ts +5 -0
  35. package/dist/client/AssistantChat.d.ts.map +1 -1
  36. package/dist/client/AssistantChat.js +54 -2
  37. package/dist/client/AssistantChat.js.map +1 -1
  38. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  39. package/dist/client/MultiTabAssistantChat.js +33 -2
  40. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  41. package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -1
  42. package/dist/client/NewWorkspaceAppFlow.js +10 -1
  43. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  44. package/dist/client/agent-chat-adapter.d.ts +4 -0
  45. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  46. package/dist/client/agent-chat-adapter.js +5 -1
  47. package/dist/client/agent-chat-adapter.js.map +1 -1
  48. package/dist/client/composer/TiptapComposer.d.ts +6 -1
  49. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  50. package/dist/client/composer/TiptapComposer.js +25 -17
  51. package/dist/client/composer/TiptapComposer.js.map +1 -1
  52. package/dist/client/composer/useVoiceDictation.d.ts +6 -5
  53. package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
  54. package/dist/client/composer/useVoiceDictation.js +54 -21
  55. package/dist/client/composer/useVoiceDictation.js.map +1 -1
  56. package/dist/client/org/OrgSwitcher.d.ts +3 -1
  57. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  58. package/dist/client/org/OrgSwitcher.js +12 -7
  59. package/dist/client/org/OrgSwitcher.js.map +1 -1
  60. package/dist/client/settings/AutomationsSection.d.ts.map +1 -1
  61. package/dist/client/settings/AutomationsSection.js +2 -2
  62. package/dist/client/settings/AutomationsSection.js.map +1 -1
  63. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  64. package/dist/client/settings/VoiceTranscriptionSection.js +46 -15
  65. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  66. package/dist/client/tools/ToolViewer.d.ts.map +1 -1
  67. package/dist/client/tools/ToolViewer.js +2 -2
  68. package/dist/client/tools/ToolViewer.js.map +1 -1
  69. package/dist/client/tools/ToolsListPage.d.ts.map +1 -1
  70. package/dist/client/tools/ToolsListPage.js +4 -4
  71. package/dist/client/tools/ToolsListPage.js.map +1 -1
  72. package/dist/client/tools/ToolsSidebarSection.d.ts.map +1 -1
  73. package/dist/client/tools/ToolsSidebarSection.js +2 -2
  74. package/dist/client/tools/ToolsSidebarSection.js.map +1 -1
  75. package/dist/client/transcription/use-live-transcription.d.ts +1 -0
  76. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
  77. package/dist/client/transcription/use-live-transcription.js +41 -0
  78. package/dist/client/transcription/use-live-transcription.js.map +1 -1
  79. package/dist/integrations/adapters/email.js +81 -5
  80. package/dist/integrations/adapters/email.js.map +1 -1
  81. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  82. package/dist/integrations/adapters/slack.js +4 -1
  83. package/dist/integrations/adapters/slack.js.map +1 -1
  84. package/dist/integrations/plugin.d.ts.map +1 -1
  85. package/dist/integrations/plugin.js +2 -1
  86. package/dist/integrations/plugin.js.map +1 -1
  87. package/dist/integrations/types.d.ts +2 -0
  88. package/dist/integrations/types.d.ts.map +1 -1
  89. package/dist/integrations/types.js.map +1 -1
  90. package/dist/integrations/webhook-handler.js +12 -2
  91. package/dist/integrations/webhook-handler.js.map +1 -1
  92. package/dist/oauth-tokens/store.d.ts.map +1 -1
  93. package/dist/oauth-tokens/store.js +34 -16
  94. package/dist/oauth-tokens/store.js.map +1 -1
  95. package/dist/scripts/db/exec.d.ts.map +1 -1
  96. package/dist/scripts/db/exec.js +32 -23
  97. package/dist/scripts/db/exec.js.map +1 -1
  98. package/dist/scripts/db/patch.d.ts.map +1 -1
  99. package/dist/scripts/db/patch.js +48 -35
  100. package/dist/scripts/db/patch.js.map +1 -1
  101. package/dist/scripts/db/query.d.ts.map +1 -1
  102. package/dist/scripts/db/query.js +22 -13
  103. package/dist/scripts/db/query.js.map +1 -1
  104. package/dist/scripts/db/safety.d.ts +2 -0
  105. package/dist/scripts/db/safety.d.ts.map +1 -0
  106. package/dist/scripts/db/safety.js +67 -0
  107. package/dist/scripts/db/safety.js.map +1 -0
  108. package/dist/scripts/db/scoping.js +4 -4
  109. package/dist/scripts/db/scoping.js.map +1 -1
  110. package/dist/server/email-template.d.ts +5 -0
  111. package/dist/server/email-template.d.ts.map +1 -1
  112. package/dist/server/email-template.js +7 -4
  113. package/dist/server/email-template.js.map +1 -1
  114. package/dist/server/google-auth-plugin.d.ts.map +1 -1
  115. package/dist/server/google-auth-plugin.js +1 -8
  116. package/dist/server/google-auth-plugin.js.map +1 -1
  117. package/dist/server/index.d.ts +3 -2
  118. package/dist/server/index.d.ts.map +1 -1
  119. package/dist/server/index.js +3 -2
  120. package/dist/server/index.js.map +1 -1
  121. package/dist/server/onboarding-html.d.ts.map +1 -1
  122. package/dist/server/onboarding-html.js +3 -10
  123. package/dist/server/onboarding-html.js.map +1 -1
  124. package/dist/server/transcribe-voice.d.ts +9 -9
  125. package/dist/server/transcribe-voice.d.ts.map +1 -1
  126. package/dist/server/transcribe-voice.js +405 -51
  127. package/dist/server/transcribe-voice.js.map +1 -1
  128. package/dist/server/voice-providers-status.d.ts.map +1 -1
  129. package/dist/server/voice-providers-status.js +13 -1
  130. package/dist/server/voice-providers-status.js.map +1 -1
  131. package/dist/settings/store.d.ts.map +1 -1
  132. package/dist/settings/store.js +14 -6
  133. package/dist/settings/store.js.map +1 -1
  134. package/dist/shared/reasoning-effort.d.ts +8 -0
  135. package/dist/shared/reasoning-effort.d.ts.map +1 -0
  136. package/dist/shared/reasoning-effort.js +94 -0
  137. package/dist/shared/reasoning-effort.js.map +1 -0
  138. package/dist/templates/default/public/favicon.svg +1 -13
  139. package/dist/templates/default/public/icon-180.svg +1 -13
  140. package/dist/templates/default/public/icon-192.svg +1 -13
  141. package/dist/templates/default/public/icon-512.svg +1 -13
  142. package/dist/templates/workspace-root/.github/workflows/ci.yml +32 -0
  143. package/dist/templates/workspace-root/.prettierignore +19 -0
  144. package/dist/templates/workspace-root/_gitignore +5 -0
  145. package/dist/templates/workspace-root/package.json +13 -2
  146. package/dist/templates/workspace-root/pnpm-workspace.yaml +1 -0
  147. package/dist/templates/workspace-root/scripts/workspace-dev.ts +2 -0
  148. package/dist/transcription/builder-transcription.d.ts +2 -0
  149. package/dist/transcription/builder-transcription.d.ts.map +1 -1
  150. package/dist/transcription/builder-transcription.js +4 -0
  151. package/dist/transcription/builder-transcription.js.map +1 -1
  152. package/docs/content/voice-input.md +14 -13
  153. package/package.json +1 -1
  154. package/src/templates/default/public/favicon.svg +1 -13
  155. package/src/templates/default/public/icon-180.svg +1 -13
  156. package/src/templates/default/public/icon-192.svg +1 -13
  157. package/src/templates/default/public/icon-512.svg +1 -13
  158. package/src/templates/workspace-root/.github/workflows/ci.yml +32 -0
  159. package/src/templates/workspace-root/.prettierignore +19 -0
  160. package/src/templates/workspace-root/_gitignore +5 -0
  161. package/src/templates/workspace-root/package.json +13 -2
  162. package/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
  163. package/src/templates/workspace-root/scripts/workspace-dev.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"scoping.js","sourceRoot":"","sources":["../../../src/scripts/db/scoping.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Per-user and per-org data scoping for db-query / db-exec.\n *\n * In production mode, creates temporary views that shadow real tables so\n * that raw SQL only sees the current user's (and org's) data.\n *\n * Convention:\n * - Template tables use an `owner_email` column for user scoping.\n * - Template tables use an `org_id` column for org scoping.\n * - Core tables have their own scoping patterns (key prefix, session_id, etc.).\n * - When both columns are present, both WHERE clauses are applied (AND).\n *\n * Temp views take precedence over real tables in both SQLite and Postgres,\n * so the user's SQL runs unmodified against the filtered views.\n */\n\n// Core tables with non-standard scoping (not owner_email).\n// Map of table name → { column, mode }.\nconst CORE_TABLE_SCOPING: Record<\n string,\n { column: string; mode: \"prefix\" | \"exact\" }\n> = {\n settings: { column: \"key\", mode: \"prefix\" }, // keys like u:<email>:<key>\n application_state: { column: \"session_id\", mode: \"exact\" },\n oauth_tokens: { column: \"owner\", mode: \"exact\" },\n sessions: { column: \"email\", mode: \"exact\" },\n};\n\n// The conventional column names for user/org ownership in template tables.\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n} from \"../../server/request-context.js\";\n\nconst OWNER_COLUMN = \"owner_email\";\nconst ORG_COLUMN = \"org_id\";\nconst DEV_FALLBACK_EMAIL = \"local@localhost\"; // guard:allow-localhost-fallback — sentinel is rejected below so DB scripts cannot silently scope to the dev fallback tenant\n\ninterface ScopedTable {\n name: string;\n viewSql: string;\n}\n\nfunction getUserEmail(): string | null {\n const userEmail = getRequestUserEmail() || null;\n if (userEmail === DEV_FALLBACK_EMAIL) {\n throw new Error(\n \"DB script scoping requires a real user identity; refusing to run with local@localhost.\",\n );\n }\n return userEmail;\n}\n\nfunction getOrgId(): string | null {\n return getRequestOrgId() || null;\n}\n\n// ─── Schema introspection ───────────────────────────────────────────────────\n\ninterface TableColumn {\n table: string;\n column: string;\n}\n\nasync function discoverColumnsPostgres(pgSql: any): Promise<TableColumn[]> {\n const rows: any[] = await pgSql`\n SELECT table_name, column_name\n FROM information_schema.columns\n WHERE table_schema = 'public'\n ORDER BY table_name, ordinal_position\n `;\n return rows.map((r) => ({ table: r.table_name, column: r.column_name }));\n}\n\nasync function discoverColumnsSqlite(client: any): Promise<TableColumn[]> {\n const tablesResult = await client.execute(\n `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`,\n );\n const tables = tablesResult.rows.map((r: any) => (r.name ?? r[0]) as string);\n\n const result: TableColumn[] = [];\n for (const table of tables) {\n const escaped = table.replace(/\"/g, '\"\"');\n const colsResult = await client.execute(`PRAGMA table_info(\"${escaped}\")`);\n for (const row of colsResult.rows) {\n result.push({\n table,\n column: (row.name ?? row[1]) as string,\n });\n }\n }\n return result;\n}\n\n// ─── View generation ────────────────────────────────────────────────────────\n\n/** Escape a string for safe inclusion in a SQL single-quoted literal. */\nfunction escapeSqlString(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\nfunction buildScopedTables(\n allColumns: TableColumn[],\n userEmail: string,\n orgId: string | null,\n isPostgres: boolean,\n): ScopedTable[] {\n // Group columns by table\n const columnsByTable = new Map<string, string[]>();\n for (const { table, column } of allColumns) {\n const cols = columnsByTable.get(table) || [];\n cols.push(column);\n columnsByTable.set(table, cols);\n }\n\n const scoped: ScopedTable[] = [];\n const qualifiedPrefix = isPostgres ? \"public.\" : \"main.\";\n const safeEmail = escapeSqlString(userEmail);\n const safeOrgId = orgId ? escapeSqlString(orgId) : null;\n\n // WITH CHECK OPTION ensures INSERTs/UPDATEs through the auto-updatable view\n // can't write rows that violate the WHERE filter. Without it, an attacker\n // could `INSERT INTO recordings (..., owner_email) VALUES (..., 'victim@x')`\n // through the view and the row would land in the base table under the\n // victim's identity. SQLite views are not auto-updatable in the same way\n // (they require triggers), so this clause is a no-op there but harmless.\n const checkOption = isPostgres ? \" WITH LOCAL CHECK OPTION\" : \"\";\n\n for (const [table, columns] of columnsByTable) {\n // Check core table scoping\n const coreScoping = CORE_TABLE_SCOPING[table];\n if (coreScoping) {\n const realTable = `${qualifiedPrefix}\"${table}\"`;\n let whereSql: string;\n if (coreScoping.mode === \"prefix\") {\n // settings: key starts with u:<email>:\n // Escape \\, % and _ in the email so LIKE treats them literally.\n const likeEmail = safeEmail\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/%/g, \"\\\\%\")\n .replace(/_/g, \"\\\\_\");\n const prefix = `u:${likeEmail}:`;\n whereSql = `\"${coreScoping.column}\" LIKE '${prefix}%' ESCAPE '\\\\'`;\n } else {\n whereSql = `\"${coreScoping.column}\" = '${safeEmail}'`;\n }\n scoped.push({\n name: table,\n viewSql: `CREATE TEMPORARY VIEW \"${table}\" AS SELECT * FROM ${realTable} WHERE ${whereSql}${checkOption}`,\n });\n continue;\n }\n\n if (\n table === \"tool_data\" &&\n columns.includes(\"scope\") &&\n columns.includes(OWNER_COLUMN) &&\n columns.includes(ORG_COLUMN)\n ) {\n const realTable = `${qualifiedPrefix}\"${table}\"`;\n const orgClause = safeOrgId\n ? ` OR (\"scope\" = 'org' AND \"${ORG_COLUMN}\" = '${safeOrgId}')`\n : \"\";\n scoped.push({\n name: table,\n viewSql: `CREATE TEMPORARY VIEW \"${table}\" AS SELECT * FROM ${realTable} WHERE ((\"scope\" = 'user' AND \"${OWNER_COLUMN}\" = '${safeEmail}')${orgClause})${checkOption}`,\n });\n continue;\n }\n\n // Build WHERE clauses for owner_email and org_id\n const clauses: string[] = [];\n const hasOwner = columns.includes(OWNER_COLUMN);\n const hasOrg = columns.includes(ORG_COLUMN);\n\n if (hasOwner) {\n clauses.push(`\"${OWNER_COLUMN}\" = '${safeEmail}'`);\n }\n if (hasOrg && safeOrgId) {\n clauses.push(`\"${ORG_COLUMN}\" = '${safeOrgId}'`);\n }\n\n if (clauses.length > 0) {\n const realTable = `${qualifiedPrefix}\"${table}\"`;\n scoped.push({\n name: table,\n viewSql: `CREATE TEMPORARY VIEW \"${table}\" AS SELECT * FROM ${realTable} WHERE ${clauses.join(\" AND \")}${checkOption}`,\n });\n }\n }\n\n return scoped;\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────────\n\nexport interface ScopingContext {\n /** SQL statements to run before the user's query (create temp views). */\n setup: string[];\n /** SQL statements to run after the user's query (drop temp views). */\n teardown: string[];\n /** Whether scoping is active. */\n active: boolean;\n /** The current user email (for INSERT injection in db-exec). */\n userEmail: string | null;\n /** The current org ID (for INSERT injection in db-exec). */\n orgId: string | null;\n /** Tables that have owner_email columns (for INSERT injection). */\n ownerEmailTables: Set<string>;\n /** Tables that have org_id columns (for INSERT injection). */\n orgIdTables: Set<string>;\n}\n\n/**\n * Build scoping context for a Postgres connection.\n * Returns setup/teardown SQL to run before/after the user's query.\n */\nexport async function buildScopingPostgres(\n pgSql: any,\n): Promise<ScopingContext> {\n const inactive: ScopingContext = {\n setup: [],\n teardown: [],\n active: false,\n userEmail: null,\n orgId: null,\n ownerEmailTables: new Set(),\n orgIdTables: new Set(),\n };\n\n // Scoping is always active when there is a request user (dev, preview, and\n // prod). Previously this short-circuited outside production, which created\n // a cross-user read in dev mode. See audit 05-tools-sandbox.md (C3.d).\n const userEmail = getUserEmail();\n if (!userEmail) return inactive;\n\n const orgId = getOrgId();\n const allColumns = await discoverColumnsPostgres(pgSql);\n const scoped = buildScopedTables(allColumns, userEmail, orgId, true);\n\n // Track which tables have owner_email / org_id for INSERT injection\n const columnsByTable = new Map<string, string[]>();\n for (const { table, column } of allColumns) {\n const cols = columnsByTable.get(table) || [];\n cols.push(column);\n columnsByTable.set(table, cols);\n }\n const ownerEmailTables = new Set<string>();\n const orgIdTables = new Set<string>();\n for (const [table, columns] of columnsByTable) {\n if (columns.includes(OWNER_COLUMN)) ownerEmailTables.add(table);\n if (columns.includes(ORG_COLUMN)) orgIdTables.add(table);\n }\n\n return {\n setup: scoped.map((s) => s.viewSql),\n teardown: scoped.map((s) => `DROP VIEW IF EXISTS \"${s.name}\"`),\n active: scoped.length > 0,\n userEmail,\n orgId,\n ownerEmailTables,\n orgIdTables,\n };\n}\n\n/**\n * Build scoping context for a SQLite/libsql connection.\n * Returns setup/teardown SQL to run before/after the user's query.\n */\nexport async function buildScopingSqlite(client: any): Promise<ScopingContext> {\n const inactive: ScopingContext = {\n setup: [],\n teardown: [],\n active: false,\n userEmail: null,\n orgId: null,\n ownerEmailTables: new Set(),\n orgIdTables: new Set(),\n };\n\n // Scoping is always active when there is a request user (dev, preview, and\n // prod). Previously this short-circuited outside production, which created\n // a cross-user read in dev mode. See audit 05-tools-sandbox.md (C3.d).\n const userEmail = getUserEmail();\n if (!userEmail) return inactive;\n\n const orgId = getOrgId();\n const allColumns = await discoverColumnsSqlite(client);\n const scoped = buildScopedTables(allColumns, userEmail, orgId, false);\n\n const columnsByTable = new Map<string, string[]>();\n for (const { table, column } of allColumns) {\n const cols = columnsByTable.get(table) || [];\n cols.push(column);\n columnsByTable.set(table, cols);\n }\n const ownerEmailTables = new Set<string>();\n const orgIdTables = new Set<string>();\n for (const [table, columns] of columnsByTable) {\n if (columns.includes(OWNER_COLUMN)) ownerEmailTables.add(table);\n if (columns.includes(ORG_COLUMN)) orgIdTables.add(table);\n }\n\n return {\n setup: scoped.map((s) => s.viewSql),\n teardown: scoped.map((s) => `DROP VIEW IF EXISTS \"${s.name}\"`),\n active: scoped.length > 0,\n userEmail,\n orgId,\n ownerEmailTables,\n orgIdTables,\n };\n}\n"]}
1
+ {"version":3,"file":"scoping.js","sourceRoot":"","sources":["../../../src/scripts/db/scoping.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Per-user and per-org data scoping for db-query / db-exec.\n *\n * In production mode, creates temporary views that shadow real tables so\n * that raw SQL only sees the current user's (and org's) data.\n *\n * Convention:\n * - Template tables use an `owner_email` column for user scoping.\n * - Template tables use an `org_id` column for org scoping.\n * - Core tables have their own scoping patterns (key prefix, session_id, etc.).\n * - When both columns are present, both WHERE clauses are applied (AND).\n *\n * Temp views take precedence over real tables in both SQLite and Postgres,\n * so the user's SQL runs unmodified against the filtered views.\n */\n\n// Core tables with non-standard scoping (not owner_email).\n// Map of table name → { column, mode }.\nconst CORE_TABLE_SCOPING: Record<\n string,\n { column: string; mode: \"prefix\" | \"exact\" }\n> = {\n settings: { column: \"key\", mode: \"prefix\" }, // keys like u:<email>:<key>\n application_state: { column: \"session_id\", mode: \"exact\" },\n oauth_tokens: { column: \"owner\", mode: \"exact\" },\n sessions: { column: \"email\", mode: \"exact\" },\n};\n\n// The conventional column names for user/org ownership in template tables.\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n} from \"../../server/request-context.js\";\n\nconst OWNER_COLUMN = \"owner_email\";\nconst ORG_COLUMN = \"org_id\";\nconst DEV_FALLBACK_EMAIL = \"local@localhost\"; // guard:allow-localhost-fallback — sentinel is rejected below so DB scripts cannot silently scope to the dev fallback tenant\n\ninterface ScopedTable {\n name: string;\n viewSql: string;\n}\n\nfunction getUserEmail(): string | null {\n const userEmail = getRequestUserEmail() || null;\n if (userEmail === DEV_FALLBACK_EMAIL) {\n throw new Error(\n \"DB script scoping requires a real user identity; refusing to run with local@localhost.\",\n );\n }\n return userEmail;\n}\n\nfunction getOrgId(): string | null {\n return getRequestOrgId() || null;\n}\n\n// ─── Schema introspection ───────────────────────────────────────────────────\n\ninterface TableColumn {\n table: string;\n column: string;\n}\n\nasync function discoverColumnsPostgres(pgSql: any): Promise<TableColumn[]> {\n const rows: any[] = await pgSql`\n SELECT table_name, column_name\n FROM information_schema.columns\n WHERE table_schema = 'public'\n ORDER BY table_name, ordinal_position\n `;\n return rows.map((r) => ({ table: r.table_name, column: r.column_name }));\n}\n\nasync function discoverColumnsSqlite(client: any): Promise<TableColumn[]> {\n const tablesResult = await client.execute(\n `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`,\n );\n const tables = tablesResult.rows.map((r: any) => (r.name ?? r[0]) as string);\n\n const result: TableColumn[] = [];\n for (const table of tables) {\n const escaped = table.replace(/\"/g, '\"\"');\n const colsResult = await client.execute(`PRAGMA table_info(\"${escaped}\")`);\n for (const row of colsResult.rows) {\n result.push({\n table,\n column: (row.name ?? row[1]) as string,\n });\n }\n }\n return result;\n}\n\n// ─── View generation ────────────────────────────────────────────────────────\n\n/** Escape a string for safe inclusion in a SQL single-quoted literal. */\nfunction escapeSqlString(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\nfunction buildScopedTables(\n allColumns: TableColumn[],\n userEmail: string,\n orgId: string | null,\n isPostgres: boolean,\n): ScopedTable[] {\n // Group columns by table\n const columnsByTable = new Map<string, string[]>();\n for (const { table, column } of allColumns) {\n const cols = columnsByTable.get(table) || [];\n cols.push(column);\n columnsByTable.set(table, cols);\n }\n\n const scoped: ScopedTable[] = [];\n const qualifiedPrefix = isPostgres ? \"public.\" : \"main.\";\n const safeEmail = escapeSqlString(userEmail);\n const safeOrgId = orgId ? escapeSqlString(orgId) : null;\n\n // WITH CHECK OPTION ensures INSERTs/UPDATEs through the auto-updatable view\n // can't write rows that violate the WHERE filter. Without it, an attacker\n // could `INSERT INTO recordings (..., owner_email) VALUES (..., 'victim@x')`\n // through the view and the row would land in the base table under the\n // victim's identity. SQLite views are not auto-updatable in the same way\n // (they require triggers), so this clause is a no-op there but harmless.\n const checkOption = isPostgres ? \" WITH LOCAL CHECK OPTION\" : \"\";\n\n for (const [table, columns] of columnsByTable) {\n // Check core table scoping\n const coreScoping = CORE_TABLE_SCOPING[table];\n if (coreScoping) {\n const realTable = `${qualifiedPrefix}\"${table}\"`;\n let whereSql: string;\n if (coreScoping.mode === \"prefix\") {\n // settings: key starts with u:<email>:\n // Escape \\, % and _ in the email so LIKE treats them literally.\n const likeEmail = safeEmail\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/%/g, \"\\\\%\")\n .replace(/_/g, \"\\\\_\");\n const prefix = `u:${likeEmail}:`;\n whereSql = `\"${coreScoping.column}\" LIKE '${prefix}%' ESCAPE '\\\\'`;\n } else {\n whereSql = `\"${coreScoping.column}\" = '${safeEmail}'`;\n }\n scoped.push({\n name: table,\n viewSql: `${isPostgres ? \"CREATE OR REPLACE TEMPORARY\" : \"CREATE TEMPORARY\"} VIEW \"${table}\" AS SELECT * FROM ${realTable} WHERE ${whereSql}${checkOption}`,\n });\n continue;\n }\n\n if (\n table === \"tool_data\" &&\n columns.includes(\"scope\") &&\n columns.includes(OWNER_COLUMN) &&\n columns.includes(ORG_COLUMN)\n ) {\n const realTable = `${qualifiedPrefix}\"${table}\"`;\n const orgClause = safeOrgId\n ? ` OR (\"scope\" = 'org' AND \"${ORG_COLUMN}\" = '${safeOrgId}')`\n : \"\";\n scoped.push({\n name: table,\n viewSql: `${isPostgres ? \"CREATE OR REPLACE TEMPORARY\" : \"CREATE TEMPORARY\"} VIEW \"${table}\" AS SELECT * FROM ${realTable} WHERE ((\"scope\" = 'user' AND \"${OWNER_COLUMN}\" = '${safeEmail}')${orgClause})${checkOption}`,\n });\n continue;\n }\n\n // Build WHERE clauses for owner_email and org_id\n const clauses: string[] = [];\n const hasOwner = columns.includes(OWNER_COLUMN);\n const hasOrg = columns.includes(ORG_COLUMN);\n\n if (hasOwner) {\n clauses.push(`\"${OWNER_COLUMN}\" = '${safeEmail}'`);\n }\n if (hasOrg && safeOrgId) {\n clauses.push(`\"${ORG_COLUMN}\" = '${safeOrgId}'`);\n }\n\n if (clauses.length > 0) {\n const realTable = `${qualifiedPrefix}\"${table}\"`;\n scoped.push({\n name: table,\n viewSql: `${isPostgres ? \"CREATE OR REPLACE TEMPORARY\" : \"CREATE TEMPORARY\"} VIEW \"${table}\" AS SELECT * FROM ${realTable} WHERE ${clauses.join(\" AND \")}${checkOption}`,\n });\n }\n }\n\n return scoped;\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────────\n\nexport interface ScopingContext {\n /** SQL statements to run before the user's query (create temp views). */\n setup: string[];\n /** SQL statements to run after the user's query (drop temp views). */\n teardown: string[];\n /** Whether scoping is active. */\n active: boolean;\n /** The current user email (for INSERT injection in db-exec). */\n userEmail: string | null;\n /** The current org ID (for INSERT injection in db-exec). */\n orgId: string | null;\n /** Tables that have owner_email columns (for INSERT injection). */\n ownerEmailTables: Set<string>;\n /** Tables that have org_id columns (for INSERT injection). */\n orgIdTables: Set<string>;\n}\n\n/**\n * Build scoping context for a Postgres connection.\n * Returns setup/teardown SQL to run before/after the user's query.\n */\nexport async function buildScopingPostgres(\n pgSql: any,\n): Promise<ScopingContext> {\n const inactive: ScopingContext = {\n setup: [],\n teardown: [],\n active: false,\n userEmail: null,\n orgId: null,\n ownerEmailTables: new Set(),\n orgIdTables: new Set(),\n };\n\n // Scoping is always active when there is a request user (dev, preview, and\n // prod). Previously this short-circuited outside production, which created\n // a cross-user read in dev mode. See audit 05-tools-sandbox.md (C3.d).\n const userEmail = getUserEmail();\n if (!userEmail) return inactive;\n\n const orgId = getOrgId();\n const allColumns = await discoverColumnsPostgres(pgSql);\n const scoped = buildScopedTables(allColumns, userEmail, orgId, true);\n\n // Track which tables have owner_email / org_id for INSERT injection\n const columnsByTable = new Map<string, string[]>();\n for (const { table, column } of allColumns) {\n const cols = columnsByTable.get(table) || [];\n cols.push(column);\n columnsByTable.set(table, cols);\n }\n const ownerEmailTables = new Set<string>();\n const orgIdTables = new Set<string>();\n for (const [table, columns] of columnsByTable) {\n if (columns.includes(OWNER_COLUMN)) ownerEmailTables.add(table);\n if (columns.includes(ORG_COLUMN)) orgIdTables.add(table);\n }\n\n return {\n setup: scoped.map((s) => s.viewSql),\n teardown: scoped.map((s) => `DROP VIEW IF EXISTS pg_temp.\"${s.name}\"`),\n active: scoped.length > 0,\n userEmail,\n orgId,\n ownerEmailTables,\n orgIdTables,\n };\n}\n\n/**\n * Build scoping context for a SQLite/libsql connection.\n * Returns setup/teardown SQL to run before/after the user's query.\n */\nexport async function buildScopingSqlite(client: any): Promise<ScopingContext> {\n const inactive: ScopingContext = {\n setup: [],\n teardown: [],\n active: false,\n userEmail: null,\n orgId: null,\n ownerEmailTables: new Set(),\n orgIdTables: new Set(),\n };\n\n // Scoping is always active when there is a request user (dev, preview, and\n // prod). Previously this short-circuited outside production, which created\n // a cross-user read in dev mode. See audit 05-tools-sandbox.md (C3.d).\n const userEmail = getUserEmail();\n if (!userEmail) return inactive;\n\n const orgId = getOrgId();\n const allColumns = await discoverColumnsSqlite(client);\n const scoped = buildScopedTables(allColumns, userEmail, orgId, false);\n\n const columnsByTable = new Map<string, string[]>();\n for (const { table, column } of allColumns) {\n const cols = columnsByTable.get(table) || [];\n cols.push(column);\n columnsByTable.set(table, cols);\n }\n const ownerEmailTables = new Set<string>();\n const orgIdTables = new Set<string>();\n for (const [table, columns] of columnsByTable) {\n if (columns.includes(OWNER_COLUMN)) ownerEmailTables.add(table);\n if (columns.includes(ORG_COLUMN)) orgIdTables.add(table);\n }\n\n return {\n setup: scoped.map((s) => s.viewSql),\n teardown: scoped.map((s) => `DROP VIEW IF EXISTS \"${s.name}\"`),\n active: scoped.length > 0,\n userEmail,\n orgId,\n ownerEmailTables,\n orgIdTables,\n };\n}\n"]}
@@ -48,4 +48,9 @@ export declare function renderEmail(args: RenderEmailArgs): RenderedEmail;
48
48
  * paragraph strings passed to `renderEmail`. Escapes the content.
49
49
  */
50
50
  export declare function emailStrong(text: string): string;
51
+ /**
52
+ * Build a labelled inline link for paragraph strings passed to `renderEmail`.
53
+ * Use this instead of rendering raw URLs in the visible email body.
54
+ */
55
+ export declare function emailLink(label: string, url: string): string;
51
56
  //# sourceMappingURL=email-template.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"email-template.d.ts","sourceRoot":"","sources":["../../src/server/email-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,wDAAwD;IACxD,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAwBD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,CAgGhE;AAeD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD"}
1
+ {"version":3,"file":"email-template.d.ts","sourceRoot":"","sources":["../../src/server/email-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,wDAAwD;IACxD,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAwBD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,CA4FhE;AAeD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5D"}
@@ -60,10 +60,6 @@ export function renderEmail(args) {
60
60
  </td>
61
61
  </tr>
62
62
  </table>
63
- <p style="margin:20px 0 0 0; font-size:13px; line-height:1.5; color:#71717a; word-break:break-all;">
64
- Or paste this link into your browser:<br/>
65
- <a href="${escapeAttr(args.cta.url)}" style="color:${linkColor}; text-decoration:none;">${escapeHtml(args.cta.url)}</a>
66
- </p>
67
63
  `
68
64
  : "";
69
65
  const footerHtml = args.footer
@@ -143,4 +139,11 @@ function stripTags(s) {
143
139
  export function emailStrong(text) {
144
140
  return `<strong style="color:#fafafa; font-weight:600;">${escapeHtml(text)}</strong>`;
145
141
  }
142
+ /**
143
+ * Build a labelled inline link for paragraph strings passed to `renderEmail`.
144
+ * Use this instead of rendering raw URLs in the visible email body.
145
+ */
146
+ export function emailLink(label, url) {
147
+ return `<a href="${escapeAttr(url)}" style="color:#a1a1aa; text-decoration:underline;">${escapeHtml(label)}</a>`;
148
+ }
146
149
  //# sourceMappingURL=email-template.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"email-template.js","sourceRoot":"","sources":["../../src/server/email-template.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reusable dark-themed HTML email template.\n *\n * Email clients have limited CSS support, so everything is inlined and layout\n * uses tables for Outlook compatibility. The design mirrors the app's dark UI:\n * near-black card on neutral background, Inter typography with safe fallbacks.\n *\n * Default is monochrome (white CTA on dark). Pass `brandColor` to tint the\n * CTA button and inline links — Clips, for example, passes its purple.\n *\n * Usage:\n * const { html, text } = renderEmail({\n * preheader: \"…\",\n * heading: \"You're invited to join Acme\",\n * paragraphs: [\"Alice invited you to join…\"],\n * cta: { label: \"Accept invite\", url: \"https://…\" },\n * footer: \"If you weren't expecting this, ignore this email.\",\n * });\n */\n\nexport interface EmailCta {\n label: string;\n url: string;\n}\n\nexport interface RenderEmailArgs {\n /** Short preview text shown by email clients next to the subject. */\n preheader?: string;\n /** Large headline at the top of the card. */\n heading: string;\n /** Body paragraphs rendered after the heading. Plain strings — escaped. */\n paragraphs: string[];\n /** Primary call-to-action rendered as a real button. */\n cta?: EmailCta;\n /** Small muted text under the CTA (e.g. expiry note). */\n footer?: string;\n /**\n * Optional brand hex color for the CTA button and inline links. Defaults to\n * a monochrome near-white button with dark text.\n */\n brandColor?: string;\n}\n\nexport interface RenderedEmail {\n html: string;\n text: string;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(s: string): string {\n return escapeHtml(s);\n}\n\n/**\n * Only accept a strict `#rrggbb` hex color for `brandColor`. Anything else\n * could inject CSS into the inline `style` attribute (`red; background:url(…)`).\n */\nfunction sanitizeHexColor(input: string | undefined): string | undefined {\n if (!input) return undefined;\n return /^#[0-9a-fA-F]{6}$/.test(input) ? input : undefined;\n}\n\nexport function renderEmail(args: RenderEmailArgs): RenderedEmail {\n const preheader = args.preheader || \"\";\n const brand = sanitizeHexColor(args.brandColor);\n\n // Monochrome default: near-white button with dark text. Brand override:\n // colored button with white text.\n const ctaBg = brand ?? \"#fafafa\";\n const ctaFg = brand ? \"#ffffff\" : \"#0a0a0c\";\n const linkColor = brand ?? \"#a1a1aa\";\n\n const paragraphsHtml = args.paragraphs\n .map(\n (p) =>\n `<p style=\"margin:0 0 16px 0; font-size:16px; line-height:1.6; color:#d4d4d8;\">${p}</p>`,\n )\n .join(\"\");\n\n const ctaHtml = args.cta\n ? `\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"margin:24px 0 0 0;\">\n <tr>\n <td style=\"border-radius:10px; background:${ctaBg};\">\n <a href=\"${escapeAttr(args.cta.url)}\"\n style=\"display:inline-block; padding:14px 26px; font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size:15px; font-weight:600; color:${ctaFg}; text-decoration:none; border-radius:10px;\">\n ${escapeHtml(args.cta.label)}\n </a>\n </td>\n </tr>\n </table>\n <p style=\"margin:20px 0 0 0; font-size:13px; line-height:1.5; color:#71717a; word-break:break-all;\">\n Or paste this link into your browser:<br/>\n <a href=\"${escapeAttr(args.cta.url)}\" style=\"color:${linkColor}; text-decoration:none;\">${escapeHtml(args.cta.url)}</a>\n </p>\n `\n : \"\";\n\n const footerHtml = args.footer\n ? `<p style=\"margin:28px 0 0 0; font-size:13px; line-height:1.5; color:#71717a;\">${escapeHtml(args.footer)}</p>`\n : \"\";\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"color-scheme\" content=\"dark light\" />\n <meta name=\"supported-color-schemes\" content=\"dark light\" />\n <title>${escapeHtml(args.heading)}</title>\n <style>\n @media (prefers-color-scheme: light) {\n .bg-outer { background-color: #0a0a0c !important; }\n }\n a { color: ${linkColor}; }\n </style>\n </head>\n <body style=\"margin:0; padding:0; background-color:#0a0a0c; font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; -webkit-font-smoothing:antialiased;\">\n <div style=\"display:none; max-height:0; overflow:hidden; opacity:0; color:transparent;\">\n ${escapeHtml(preheader)}\n </div>\n <table role=\"presentation\" class=\"bg-outer\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"background-color:#0a0a0c; padding:40px 16px;\">\n <tr>\n <td align=\"center\">\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"max-width:560px;\">\n <tr>\n <td style=\"background-color:#141417; border:1px solid #27272a; border-radius:16px; padding:36px 36px 32px 36px;\">\n <h1 style=\"margin:0 0 20px 0; font-size:24px; line-height:1.3; font-weight:600; color:#fafafa; letter-spacing:-0.02em;\">\n ${escapeHtml(args.heading)}\n </h1>\n ${paragraphsHtml}\n ${ctaHtml}\n ${footerHtml}\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n</html>`;\n\n const textLines: string[] = [];\n textLines.push(args.heading);\n textLines.push(\"\");\n for (const p of args.paragraphs) {\n textLines.push(stripTags(p));\n textLines.push(\"\");\n }\n if (args.cta) {\n textLines.push(`${args.cta.label}: ${args.cta.url}`);\n textLines.push(\"\");\n }\n if (args.footer) {\n textLines.push(args.footer);\n }\n\n return { html, text: textLines.join(\"\\n\").trim() };\n}\n\nfunction stripTags(s: string): string {\n return s\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&nbsp;/g, \" \")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .trim();\n}\n\n/**\n * Build an inline `<strong>` tag with consistent styling for use inside\n * paragraph strings passed to `renderEmail`. Escapes the content.\n */\nexport function emailStrong(text: string): string {\n return `<strong style=\"color:#fafafa; font-weight:600;\">${escapeHtml(text)}</strong>`;\n}\n"]}
1
+ {"version":3,"file":"email-template.js","sourceRoot":"","sources":["../../src/server/email-template.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reusable dark-themed HTML email template.\n *\n * Email clients have limited CSS support, so everything is inlined and layout\n * uses tables for Outlook compatibility. The design mirrors the app's dark UI:\n * near-black card on neutral background, Inter typography with safe fallbacks.\n *\n * Default is monochrome (white CTA on dark). Pass `brandColor` to tint the\n * CTA button and inline links — Clips, for example, passes its purple.\n *\n * Usage:\n * const { html, text } = renderEmail({\n * preheader: \"…\",\n * heading: \"You're invited to join Acme\",\n * paragraphs: [\"Alice invited you to join…\"],\n * cta: { label: \"Accept invite\", url: \"https://…\" },\n * footer: \"If you weren't expecting this, ignore this email.\",\n * });\n */\n\nexport interface EmailCta {\n label: string;\n url: string;\n}\n\nexport interface RenderEmailArgs {\n /** Short preview text shown by email clients next to the subject. */\n preheader?: string;\n /** Large headline at the top of the card. */\n heading: string;\n /** Body paragraphs rendered after the heading. Plain strings — escaped. */\n paragraphs: string[];\n /** Primary call-to-action rendered as a real button. */\n cta?: EmailCta;\n /** Small muted text under the CTA (e.g. expiry note). */\n footer?: string;\n /**\n * Optional brand hex color for the CTA button and inline links. Defaults to\n * a monochrome near-white button with dark text.\n */\n brandColor?: string;\n}\n\nexport interface RenderedEmail {\n html: string;\n text: string;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(s: string): string {\n return escapeHtml(s);\n}\n\n/**\n * Only accept a strict `#rrggbb` hex color for `brandColor`. Anything else\n * could inject CSS into the inline `style` attribute (`red; background:url(…)`).\n */\nfunction sanitizeHexColor(input: string | undefined): string | undefined {\n if (!input) return undefined;\n return /^#[0-9a-fA-F]{6}$/.test(input) ? input : undefined;\n}\n\nexport function renderEmail(args: RenderEmailArgs): RenderedEmail {\n const preheader = args.preheader || \"\";\n const brand = sanitizeHexColor(args.brandColor);\n\n // Monochrome default: near-white button with dark text. Brand override:\n // colored button with white text.\n const ctaBg = brand ?? \"#fafafa\";\n const ctaFg = brand ? \"#ffffff\" : \"#0a0a0c\";\n const linkColor = brand ?? \"#a1a1aa\";\n\n const paragraphsHtml = args.paragraphs\n .map(\n (p) =>\n `<p style=\"margin:0 0 16px 0; font-size:16px; line-height:1.6; color:#d4d4d8;\">${p}</p>`,\n )\n .join(\"\");\n\n const ctaHtml = args.cta\n ? `\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"margin:24px 0 0 0;\">\n <tr>\n <td style=\"border-radius:10px; background:${ctaBg};\">\n <a href=\"${escapeAttr(args.cta.url)}\"\n style=\"display:inline-block; padding:14px 26px; font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size:15px; font-weight:600; color:${ctaFg}; text-decoration:none; border-radius:10px;\">\n ${escapeHtml(args.cta.label)}\n </a>\n </td>\n </tr>\n </table>\n `\n : \"\";\n\n const footerHtml = args.footer\n ? `<p style=\"margin:28px 0 0 0; font-size:13px; line-height:1.5; color:#71717a;\">${escapeHtml(args.footer)}</p>`\n : \"\";\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"color-scheme\" content=\"dark light\" />\n <meta name=\"supported-color-schemes\" content=\"dark light\" />\n <title>${escapeHtml(args.heading)}</title>\n <style>\n @media (prefers-color-scheme: light) {\n .bg-outer { background-color: #0a0a0c !important; }\n }\n a { color: ${linkColor}; }\n </style>\n </head>\n <body style=\"margin:0; padding:0; background-color:#0a0a0c; font-family:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; -webkit-font-smoothing:antialiased;\">\n <div style=\"display:none; max-height:0; overflow:hidden; opacity:0; color:transparent;\">\n ${escapeHtml(preheader)}\n </div>\n <table role=\"presentation\" class=\"bg-outer\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"background-color:#0a0a0c; padding:40px 16px;\">\n <tr>\n <td align=\"center\">\n <table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"max-width:560px;\">\n <tr>\n <td style=\"background-color:#141417; border:1px solid #27272a; border-radius:16px; padding:36px 36px 32px 36px;\">\n <h1 style=\"margin:0 0 20px 0; font-size:24px; line-height:1.3; font-weight:600; color:#fafafa; letter-spacing:-0.02em;\">\n ${escapeHtml(args.heading)}\n </h1>\n ${paragraphsHtml}\n ${ctaHtml}\n ${footerHtml}\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n</html>`;\n\n const textLines: string[] = [];\n textLines.push(args.heading);\n textLines.push(\"\");\n for (const p of args.paragraphs) {\n textLines.push(stripTags(p));\n textLines.push(\"\");\n }\n if (args.cta) {\n textLines.push(`${args.cta.label}: ${args.cta.url}`);\n textLines.push(\"\");\n }\n if (args.footer) {\n textLines.push(args.footer);\n }\n\n return { html, text: textLines.join(\"\\n\").trim() };\n}\n\nfunction stripTags(s: string): string {\n return s\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&nbsp;/g, \" \")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .trim();\n}\n\n/**\n * Build an inline `<strong>` tag with consistent styling for use inside\n * paragraph strings passed to `renderEmail`. Escapes the content.\n */\nexport function emailStrong(text: string): string {\n return `<strong style=\"color:#fafafa; font-weight:600;\">${escapeHtml(text)}</strong>`;\n}\n\n/**\n * Build a labelled inline link for paragraph strings passed to `renderEmail`.\n * Use this instead of rendering raw URLs in the visible email body.\n */\nexport function emailLink(label: string, url: string): string {\n return `<a href=\"${escapeAttr(url)}\" style=\"color:#a1a1aa; text-decoration:underline;\">${escapeHtml(label)}</a>`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"google-auth-plugin.d.ts","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAwGD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,CAAC,EAAE,uBAAuB,GAChC,cAAc,CAUhB"}
1
+ {"version":3,"file":"google-auth-plugin.d.ts","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAiGD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,CAAC,EAAE,uBAAuB,GAChC,cAAc,CAUhB"}
@@ -78,14 +78,7 @@ const GOOGLE_LOGIN_HTML = `<!DOCTYPE html>
78
78
  var data = await res.json();
79
79
  if (data.url) {
80
80
  try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}
81
- window.open(data.url, '_blank');
82
- btn.disabled = false;
83
- btn.textContent = 'Waiting for sign-in…';
84
- var poll = setInterval(function() {
85
- fetch(__anPath('/_agent-native/auth/session')).then(function(r) { return r.json(); }).then(function(s) {
86
- if (s && s.email) { clearInterval(poll); window.location.reload(); }
87
- }).catch(function() {});
88
- }, 1500);
81
+ window.location.href = data.url;
89
82
  } else {
90
83
  err.textContent = data.message || 'Google OAuth is not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.';
91
84
  err.classList.add('show');
@@ -1 +1 @@
1
- {"version":3,"file":"google-auth-plugin.js","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AASpD,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAoGlB,CAAC;AAET;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAiC;IAEjC,OAAO,gBAAgB,CAAC;QACtB,WAAW,EAAE;YACX,gCAAgC;YAChC,gCAAgC;YAChC,wBAAwB;YACxB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,CAAC;SAChC;QACD,SAAS,EAAE,iBAAiB;KAC7B,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createAuthPlugin } from \"./auth-plugin.js\";\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\nexport interface GoogleAuthPluginOptions {\n /** Additional paths accessible without authentication */\n publicPaths?: string[];\n}\n\nconst GOOGLE_LOGIN_HTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>Sign in</title>\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n width: 100%;\n max-width: 360px;\n padding: 2rem;\n background: #141414;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 12px;\n text-align: center;\n }\n h1 { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n padding: 0.625rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 8px;\n font-size: 0.9375rem;\n font-weight: 500;\n cursor: pointer;\n }\n button:hover { opacity: 0.85; }\n button:disabled { opacity: 0.5; cursor: wait; }\n .error { margin-top: 0.75rem; font-size: 0.8125rem; color: #f87171; display: none; }\n .error.show { display: block; }\n svg { width: 18px; height: 18px; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Sign in</h1>\n <p class=\"subtitle\">Continue with your Google account</p>\n <button id=\"btn\" onclick=\"signIn()\">\n <svg viewBox=\"0 0 24 24\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n Sign in with Google\n </button>\n <p class=\"error\" id=\"err\"></p>\n</div>\n<script>\n function __anBasePath() {\n var marker = '/_agent-native';\n var idx = window.location.pathname.indexOf(marker);\n return idx > 0 ? window.location.pathname.slice(0, idx) : '';\n }\n function __anPath(path) {\n return __anBasePath() + path;\n }\n async function signIn() {\n var btn = document.getElementById('btn');\n var err = document.getElementById('err');\n btn.disabled = true;\n err.classList.remove('show');\n try {\n var res = await fetch(__anPath('/_agent-native/google/auth-url'));\n var data = await res.json();\n if (data.url) {\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n window.open(data.url, '_blank');\n btn.disabled = false;\n btn.textContent = 'Waiting for sign-in…';\n var poll = setInterval(function() {\n fetch(__anPath('/_agent-native/auth/session')).then(function(r) { return r.json(); }).then(function(s) {\n if (s && s.email) { clearInterval(poll); window.location.reload(); }\n }).catch(function() {});\n }, 1500);\n } else {\n err.textContent = data.message || 'Google OAuth is not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.';\n err.classList.add('show');\n btn.disabled = false;\n }\n } catch (e) {\n err.textContent = 'Failed to connect. Please try again.';\n err.classList.add('show');\n btn.disabled = false;\n }\n }\n</script>\n</body>\n</html>`;\n\n/**\n * Create an auth plugin that uses Google OAuth for authentication.\n *\n * When a user visits the app unauthenticated, they see a \"Sign in with Google\"\n * page. The Google OAuth callback (handled by the template) creates a session\n * tied to the user's Google email. `getSession()` then returns `{ email }` for\n * all subsequent requests.\n *\n * Better Auth handles Google OAuth internally when GOOGLE_CLIENT_ID and\n * GOOGLE_CLIENT_SECRET are set. The template's callback route at\n * /_agent-native/google/callback handles mobile deep linking.\n *\n * Usage in a template's `server/plugins/auth.ts`:\n * ```ts\n * import { createGoogleAuthPlugin } from \"@agent-native/core/server\";\n * export default createGoogleAuthPlugin();\n * ```\n */\nexport function createGoogleAuthPlugin(\n options?: GoogleAuthPluginOptions,\n): NitroPluginDef {\n return createAuthPlugin({\n publicPaths: [\n \"/_agent-native/google/callback\",\n \"/_agent-native/google/auth-url\",\n \"/_agent-native/auth/ba\",\n ...(options?.publicPaths ?? []),\n ],\n loginHtml: GOOGLE_LOGIN_HTML,\n });\n}\n"]}
1
+ {"version":3,"file":"google-auth-plugin.js","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AASpD,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA6FlB,CAAC;AAET;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAiC;IAEjC,OAAO,gBAAgB,CAAC;QACtB,WAAW,EAAE;YACX,gCAAgC;YAChC,gCAAgC;YAChC,wBAAwB;YACxB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,CAAC;SAChC;QACD,SAAS,EAAE,iBAAiB;KAC7B,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createAuthPlugin } from \"./auth-plugin.js\";\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\nexport interface GoogleAuthPluginOptions {\n /** Additional paths accessible without authentication */\n publicPaths?: string[];\n}\n\nconst GOOGLE_LOGIN_HTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>Sign in</title>\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n width: 100%;\n max-width: 360px;\n padding: 2rem;\n background: #141414;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 12px;\n text-align: center;\n }\n h1 { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n padding: 0.625rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 8px;\n font-size: 0.9375rem;\n font-weight: 500;\n cursor: pointer;\n }\n button:hover { opacity: 0.85; }\n button:disabled { opacity: 0.5; cursor: wait; }\n .error { margin-top: 0.75rem; font-size: 0.8125rem; color: #f87171; display: none; }\n .error.show { display: block; }\n svg { width: 18px; height: 18px; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Sign in</h1>\n <p class=\"subtitle\">Continue with your Google account</p>\n <button id=\"btn\" onclick=\"signIn()\">\n <svg viewBox=\"0 0 24 24\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n Sign in with Google\n </button>\n <p class=\"error\" id=\"err\"></p>\n</div>\n<script>\n function __anBasePath() {\n var marker = '/_agent-native';\n var idx = window.location.pathname.indexOf(marker);\n return idx > 0 ? window.location.pathname.slice(0, idx) : '';\n }\n function __anPath(path) {\n return __anBasePath() + path;\n }\n async function signIn() {\n var btn = document.getElementById('btn');\n var err = document.getElementById('err');\n btn.disabled = true;\n err.classList.remove('show');\n try {\n var res = await fetch(__anPath('/_agent-native/google/auth-url'));\n var data = await res.json();\n if (data.url) {\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n window.location.href = data.url;\n } else {\n err.textContent = data.message || 'Google OAuth is not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.';\n err.classList.add('show');\n btn.disabled = false;\n }\n } catch (e) {\n err.textContent = 'Failed to connect. Please try again.';\n err.classList.add('show');\n btn.disabled = false;\n }\n }\n</script>\n</body>\n</html>`;\n\n/**\n * Create an auth plugin that uses Google OAuth for authentication.\n *\n * When a user visits the app unauthenticated, they see a \"Sign in with Google\"\n * page. The Google OAuth callback (handled by the template) creates a session\n * tied to the user's Google email. `getSession()` then returns `{ email }` for\n * all subsequent requests.\n *\n * Better Auth handles Google OAuth internally when GOOGLE_CLIENT_ID and\n * GOOGLE_CLIENT_SECRET are set. The template's callback route at\n * /_agent-native/google/callback handles mobile deep linking.\n *\n * Usage in a template's `server/plugins/auth.ts`:\n * ```ts\n * import { createGoogleAuthPlugin } from \"@agent-native/core/server\";\n * export default createGoogleAuthPlugin();\n * ```\n */\nexport function createGoogleAuthPlugin(\n options?: GoogleAuthPluginOptions,\n): NitroPluginDef {\n return createAuthPlugin({\n publicPaths: [\n \"/_agent-native/google/callback\",\n \"/_agent-native/google/auth-url\",\n \"/_agent-native/auth/ba\",\n ...(options?.publicPaths ?? []),\n ],\n loginHtml: GOOGLE_LOGIN_HTML,\n });\n}\n"]}
@@ -27,12 +27,13 @@ export { formatDateInTimezone, todayInTimezone } from "./date-utils.js";
27
27
  export { createOnboardingPlugin, defaultOnboardingPlugin, } from "../onboarding/plugin.js";
28
28
  export { registerFileUploadProvider, unregisterFileUploadProvider, listFileUploadProviders, getActiveFileUploadProvider, uploadFile, builderFileUploadProvider, type FileUploadInput, type FileUploadProvider, type FileUploadResult, } from "../file-upload/index.js";
29
29
  export { createIntegrationsPlugin, defaultIntegrationsPlugin, slackAdapter, telegramAdapter, whatsappAdapter, emailAdapter, type PlatformAdapter, type IncomingMessage, type OutgoingMessage, type IntegrationStatus, type IntegrationsPluginOptions, } from "../integrations/index.js";
30
- export { isElectron, isMobile, getOrigin, getAppBasePath, getAppUrl, encodeOAuthState, decodeOAuthState, resolveOAuthOwner, createOAuthSession, oauthCallbackResponse, oauthErrorPage, oauthDesktopExchangePage, type OAuthStatePayload, type OAuthOwnerResult, type OAuthSessionResult, } from "./google-oauth.js";
30
+ export { isElectron, isMobile, getOrigin, getAppBasePath, getAppUrl, resolveOAuthRedirectUri, isAllowedOAuthRedirectUri, encodeOAuthState, decodeOAuthState, resolveOAuthOwner, createOAuthSession, oauthCallbackResponse, oauthErrorPage, oauthDesktopExchangePage, type OAuthStatePayload, type OAuthOwnerResult, type OAuthSessionResult, } from "./google-oauth.js";
31
31
  export { FeatureNotConfiguredError, hasBuilderPrivateKey, isBuilderEnvManaged, getBuilderProxyOrigin, getBuilderAuthHeader, resolveBuilderPrivateKey, resolveBuilderAuthHeader, resolveHasBuilderPrivateKey, resolveBuilderCredentials, resolveBuilderCredential, writeBuilderCredentials, deleteBuilderCredentials, resolveSecret, } from "./credential-provider.js";
32
32
  export { getBuilderBranchProjectId, isBuilderBranchingEnabled, runBuilderAgent, type RunBuilderAgentResult, } from "./builder-browser.js";
33
33
  export { sendEmail, isEmailConfigured, getEmailProvider, type EmailProvider, type SendEmailArgs, } from "./email.js";
34
- export { renderEmail, emailStrong, type RenderEmailArgs, type RenderedEmail, type EmailCta, } from "./email-template.js";
34
+ export { renderEmail, emailStrong, emailLink, type RenderEmailArgs, type RenderedEmail, type EmailCta, } from "./email-template.js";
35
35
  export { getAppProductionUrl, getFirstPartyProdUrl } from "./app-url.js";
36
+ export { getConfiguredAppBasePath, normalizeAppBasePath, withConfiguredAppBasePath, } from "./app-base-path.js";
36
37
  export { signShortLivedToken, verifyShortLivedToken, type ShortLivedTokenClaims, type VerifyResult as ShortLivedTokenVerifyResult, } from "./short-lived-token.js";
37
38
  type NitroPluginDef = (nitroApp: any) => void | Promise<void>;
38
39
  export declare function defineNitroPlugin(def: NitroPluginDef): NitroPluginDef;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -30,12 +30,13 @@ export { formatDateInTimezone, todayInTimezone } from "./date-utils.js";
30
30
  export { createOnboardingPlugin, defaultOnboardingPlugin, } from "../onboarding/plugin.js";
31
31
  export { registerFileUploadProvider, unregisterFileUploadProvider, listFileUploadProviders, getActiveFileUploadProvider, uploadFile, builderFileUploadProvider, } from "../file-upload/index.js";
32
32
  export { createIntegrationsPlugin, defaultIntegrationsPlugin, slackAdapter, telegramAdapter, whatsappAdapter, emailAdapter, } from "../integrations/index.js";
33
- export { isElectron, isMobile, getOrigin, getAppBasePath, getAppUrl, encodeOAuthState, decodeOAuthState, resolveOAuthOwner, createOAuthSession, oauthCallbackResponse, oauthErrorPage, oauthDesktopExchangePage, } from "./google-oauth.js";
33
+ export { isElectron, isMobile, getOrigin, getAppBasePath, getAppUrl, resolveOAuthRedirectUri, isAllowedOAuthRedirectUri, encodeOAuthState, decodeOAuthState, resolveOAuthOwner, createOAuthSession, oauthCallbackResponse, oauthErrorPage, oauthDesktopExchangePage, } from "./google-oauth.js";
34
34
  export { FeatureNotConfiguredError, hasBuilderPrivateKey, isBuilderEnvManaged, getBuilderProxyOrigin, getBuilderAuthHeader, resolveBuilderPrivateKey, resolveBuilderAuthHeader, resolveHasBuilderPrivateKey, resolveBuilderCredentials, resolveBuilderCredential, writeBuilderCredentials, deleteBuilderCredentials, resolveSecret, } from "./credential-provider.js";
35
35
  export { getBuilderBranchProjectId, isBuilderBranchingEnabled, runBuilderAgent, } from "./builder-browser.js";
36
36
  export { sendEmail, isEmailConfigured, getEmailProvider, } from "./email.js";
37
- export { renderEmail, emailStrong, } from "./email-template.js";
37
+ export { renderEmail, emailStrong, emailLink, } from "./email-template.js";
38
38
  export { getAppProductionUrl, getFirstPartyProdUrl } from "./app-url.js";
39
+ export { getConfiguredAppBasePath, normalizeAppBasePath, withConfiguredAppBasePath, } from "./app-base-path.js";
39
40
  export { signShortLivedToken, verifyShortLivedToken, } from "./short-lived-token.js";
40
41
  export function defineNitroPlugin(def) {
41
42
  return def;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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","sourcesContent":["export {\n createServer,\n upsertEnvFile,\n type CreateServerOptions,\n type EnvKeyConfig,\n} from \"./create-server.js\";\n\nexport { readBody, streamFile } from \"./h3-helpers.js\";\nexport { createSSEHandler, type SSEHandlerOptions } from \"./sse.js\";\nexport {\n mountAuthMiddleware,\n autoMountAuth,\n getSession,\n addSession,\n removeSession,\n getSessionEmail,\n runAuthGuard,\n setDesktopExchange,\n setDesktopExchangeError,\n DEV_MODE_USER_EMAIL,\n safeReturnPath,\n type DesktopExchangeErrorPayload,\n type AuthSession,\n type AuthOptions,\n} from \"./auth.js\";\nexport { requireEnvKey, type MissingKeyResponse } from \"./missing-key.js\";\nexport { verifyCaptcha, type CaptchaVerifyResult } from \"./captcha.js\";\nexport {\n createProductionAgentHandler,\n type ActionEntry,\n type ScriptEntry,\n type ProductionAgentOptions,\n type ActionTool,\n type ScriptTool,\n type AgentMessage,\n type AgentChatRequest,\n type AgentChatEvent,\n type AgentChatReference,\n type MentionProvider,\n type MentionProviderItem,\n} from \"../agent/index.js\";\nexport { createDevScriptRegistry } from \"../scripts/dev/index.js\";\n\nexport {\n createPollHandler,\n recordChange,\n getVersion,\n getChangesSince,\n} from \"./poll.js\";\nexport { createAuthPlugin, defaultAuthPlugin } from \"./auth-plugin.js\";\n// Re-export the org plugin so the auto-discovery's DEFAULT_PLUGIN_REGISTRY\n// (which references \"defaultOrgPlugin\" from @agent-native/core/server) can\n// resolve it during the deploy build worker-entry generation.\nexport { createOrgPlugin, defaultOrgPlugin } from \"../org/plugin.js\";\nexport {\n createGoogleAuthPlugin,\n type GoogleAuthPluginOptions,\n} from \"./google-auth-plugin.js\";\nexport {\n createAgentChatPlugin,\n defaultAgentChatPlugin,\n type AgentChatPluginOptions,\n} from \"./agent-chat-plugin.js\";\nexport {\n createThread,\n getThread,\n listThreads,\n updateThreadData,\n deleteThread,\n type ChatThread,\n type ChatThreadSummary,\n} from \"../chat-threads/store.js\";\nexport {\n createResourcesPlugin,\n defaultResourcesPlugin,\n} from \"./resources-plugin.js\";\nexport {\n createCoreRoutesPlugin,\n defaultCoreRoutesPlugin,\n FRAMEWORK_ROUTE_PREFIX,\n type CoreRoutesPluginOptions,\n} from \"./core-routes-plugin.js\";\nexport {\n createTerminalPlugin,\n defaultTerminalPlugin,\n type TerminalPluginOptions,\n} from \"../terminal/terminal-plugin.js\";\nexport {\n createCollabPlugin,\n type CollabPluginOptions,\n} from \"./collab-plugin.js\";\n\nexport {\n spawnTask,\n getTask,\n getTaskByThread,\n listTasks,\n sendToTask,\n markTaskErrored,\n type AgentTask,\n type SpawnTaskOptions,\n} from \"./agent-teams.js\";\nexport { isOAuthConnected, getOAuthAccounts } from \"./oauth-helpers.js\";\nexport { wrapWithAnalytics } from \"./analytics.js\";\nexport {\n getH3App,\n awaitBootstrap,\n type H3AppShim,\n} from \"./framework-request-handler.js\";\nexport {\n autoDiscoverActions,\n autoDiscoverScripts,\n loadActionsFromStaticRegistry,\n mergeCoreSharingActions,\n} from \"./action-discovery.js\";\nexport {\n mountActionRoutes,\n type MountActionRoutesOptions,\n} from \"./action-routes.js\";\nexport {\n runWithRequestContext,\n hasRequestContext,\n getRequestContext,\n getRequestUserEmail,\n getRequestOrgId,\n getRequestTimezone,\n getCredentialContext,\n isIntegrationCallerRequest,\n type RequestContext,\n} from \"./request-context.js\";\nexport { formatDateInTimezone, todayInTimezone } from \"./date-utils.js\";\n\nexport {\n createOnboardingPlugin,\n defaultOnboardingPlugin,\n} from \"../onboarding/plugin.js\";\n\nexport {\n registerFileUploadProvider,\n unregisterFileUploadProvider,\n listFileUploadProviders,\n getActiveFileUploadProvider,\n uploadFile,\n builderFileUploadProvider,\n type FileUploadInput,\n type FileUploadProvider,\n type FileUploadResult,\n} from \"../file-upload/index.js\";\n\nexport {\n createIntegrationsPlugin,\n defaultIntegrationsPlugin,\n slackAdapter,\n telegramAdapter,\n whatsappAdapter,\n emailAdapter,\n type PlatformAdapter,\n type IncomingMessage,\n type OutgoingMessage,\n type IntegrationStatus,\n type IntegrationsPluginOptions,\n} from \"../integrations/index.js\";\n\nexport {\n isElectron,\n isMobile,\n getOrigin,\n getAppBasePath,\n getAppUrl,\n encodeOAuthState,\n decodeOAuthState,\n resolveOAuthOwner,\n createOAuthSession,\n oauthCallbackResponse,\n oauthErrorPage,\n oauthDesktopExchangePage,\n type OAuthStatePayload,\n type OAuthOwnerResult,\n type OAuthSessionResult,\n} from \"./google-oauth.js\";\n\nexport {\n FeatureNotConfiguredError,\n hasBuilderPrivateKey,\n isBuilderEnvManaged,\n getBuilderProxyOrigin,\n getBuilderAuthHeader,\n resolveBuilderPrivateKey,\n resolveBuilderAuthHeader,\n resolveHasBuilderPrivateKey,\n resolveBuilderCredentials,\n resolveBuilderCredential,\n writeBuilderCredentials,\n deleteBuilderCredentials,\n resolveSecret,\n} from \"./credential-provider.js\";\nexport {\n getBuilderBranchProjectId,\n isBuilderBranchingEnabled,\n runBuilderAgent,\n type RunBuilderAgentResult,\n} from \"./builder-browser.js\";\n\nexport {\n sendEmail,\n isEmailConfigured,\n getEmailProvider,\n type EmailProvider,\n type SendEmailArgs,\n} from \"./email.js\";\nexport {\n renderEmail,\n emailStrong,\n type RenderEmailArgs,\n type RenderedEmail,\n type EmailCta,\n} from \"./email-template.js\";\nexport { getAppProductionUrl, getFirstPartyProdUrl } from \"./app-url.js\";\nexport {\n signShortLivedToken,\n verifyShortLivedToken,\n type ShortLivedTokenClaims,\n type VerifyResult as ShortLivedTokenVerifyResult,\n} from \"./short-lived-token.js\";\n\n// SSR handler is NOT re-exported here — it uses a virtual module\n// (virtual:react-router/server-build) that only exists at Vite dev/build time.\n// Including it in this barrel would break the esbuild CF Pages bundler.\n// Templates import directly: import { ssrHandler } from \"@agent-native/core/server/ssr-handler\"\n\n// Nitro plugin helper — re-exported so templates don't need nitro as a direct dependency.\n// defineNitroPlugin is an identity function; this typed wrapper lets templates use it\n// without resolving `nitro/runtime` (which requires Nitro's virtual modules at runtime).\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\nexport function defineNitroPlugin(def: NitroPluginDef): NitroPluginDef {\n return def;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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","sourcesContent":["export {\n createServer,\n upsertEnvFile,\n type CreateServerOptions,\n type EnvKeyConfig,\n} from \"./create-server.js\";\n\nexport { readBody, streamFile } from \"./h3-helpers.js\";\nexport { createSSEHandler, type SSEHandlerOptions } from \"./sse.js\";\nexport {\n mountAuthMiddleware,\n autoMountAuth,\n getSession,\n addSession,\n removeSession,\n getSessionEmail,\n runAuthGuard,\n setDesktopExchange,\n setDesktopExchangeError,\n DEV_MODE_USER_EMAIL,\n safeReturnPath,\n type DesktopExchangeErrorPayload,\n type AuthSession,\n type AuthOptions,\n} from \"./auth.js\";\nexport { requireEnvKey, type MissingKeyResponse } from \"./missing-key.js\";\nexport { verifyCaptcha, type CaptchaVerifyResult } from \"./captcha.js\";\nexport {\n createProductionAgentHandler,\n type ActionEntry,\n type ScriptEntry,\n type ProductionAgentOptions,\n type ActionTool,\n type ScriptTool,\n type AgentMessage,\n type AgentChatRequest,\n type AgentChatEvent,\n type AgentChatReference,\n type MentionProvider,\n type MentionProviderItem,\n} from \"../agent/index.js\";\nexport { createDevScriptRegistry } from \"../scripts/dev/index.js\";\n\nexport {\n createPollHandler,\n recordChange,\n getVersion,\n getChangesSince,\n} from \"./poll.js\";\nexport { createAuthPlugin, defaultAuthPlugin } from \"./auth-plugin.js\";\n// Re-export the org plugin so the auto-discovery's DEFAULT_PLUGIN_REGISTRY\n// (which references \"defaultOrgPlugin\" from @agent-native/core/server) can\n// resolve it during the deploy build worker-entry generation.\nexport { createOrgPlugin, defaultOrgPlugin } from \"../org/plugin.js\";\nexport {\n createGoogleAuthPlugin,\n type GoogleAuthPluginOptions,\n} from \"./google-auth-plugin.js\";\nexport {\n createAgentChatPlugin,\n defaultAgentChatPlugin,\n type AgentChatPluginOptions,\n} from \"./agent-chat-plugin.js\";\nexport {\n createThread,\n getThread,\n listThreads,\n updateThreadData,\n deleteThread,\n type ChatThread,\n type ChatThreadSummary,\n} from \"../chat-threads/store.js\";\nexport {\n createResourcesPlugin,\n defaultResourcesPlugin,\n} from \"./resources-plugin.js\";\nexport {\n createCoreRoutesPlugin,\n defaultCoreRoutesPlugin,\n FRAMEWORK_ROUTE_PREFIX,\n type CoreRoutesPluginOptions,\n} from \"./core-routes-plugin.js\";\nexport {\n createTerminalPlugin,\n defaultTerminalPlugin,\n type TerminalPluginOptions,\n} from \"../terminal/terminal-plugin.js\";\nexport {\n createCollabPlugin,\n type CollabPluginOptions,\n} from \"./collab-plugin.js\";\n\nexport {\n spawnTask,\n getTask,\n getTaskByThread,\n listTasks,\n sendToTask,\n markTaskErrored,\n type AgentTask,\n type SpawnTaskOptions,\n} from \"./agent-teams.js\";\nexport { isOAuthConnected, getOAuthAccounts } from \"./oauth-helpers.js\";\nexport { wrapWithAnalytics } from \"./analytics.js\";\nexport {\n getH3App,\n awaitBootstrap,\n type H3AppShim,\n} from \"./framework-request-handler.js\";\nexport {\n autoDiscoverActions,\n autoDiscoverScripts,\n loadActionsFromStaticRegistry,\n mergeCoreSharingActions,\n} from \"./action-discovery.js\";\nexport {\n mountActionRoutes,\n type MountActionRoutesOptions,\n} from \"./action-routes.js\";\nexport {\n runWithRequestContext,\n hasRequestContext,\n getRequestContext,\n getRequestUserEmail,\n getRequestOrgId,\n getRequestTimezone,\n getCredentialContext,\n isIntegrationCallerRequest,\n type RequestContext,\n} from \"./request-context.js\";\nexport { formatDateInTimezone, todayInTimezone } from \"./date-utils.js\";\n\nexport {\n createOnboardingPlugin,\n defaultOnboardingPlugin,\n} from \"../onboarding/plugin.js\";\n\nexport {\n registerFileUploadProvider,\n unregisterFileUploadProvider,\n listFileUploadProviders,\n getActiveFileUploadProvider,\n uploadFile,\n builderFileUploadProvider,\n type FileUploadInput,\n type FileUploadProvider,\n type FileUploadResult,\n} from \"../file-upload/index.js\";\n\nexport {\n createIntegrationsPlugin,\n defaultIntegrationsPlugin,\n slackAdapter,\n telegramAdapter,\n whatsappAdapter,\n emailAdapter,\n type PlatformAdapter,\n type IncomingMessage,\n type OutgoingMessage,\n type IntegrationStatus,\n type IntegrationsPluginOptions,\n} from \"../integrations/index.js\";\n\nexport {\n isElectron,\n isMobile,\n getOrigin,\n getAppBasePath,\n getAppUrl,\n resolveOAuthRedirectUri,\n isAllowedOAuthRedirectUri,\n encodeOAuthState,\n decodeOAuthState,\n resolveOAuthOwner,\n createOAuthSession,\n oauthCallbackResponse,\n oauthErrorPage,\n oauthDesktopExchangePage,\n type OAuthStatePayload,\n type OAuthOwnerResult,\n type OAuthSessionResult,\n} from \"./google-oauth.js\";\n\nexport {\n FeatureNotConfiguredError,\n hasBuilderPrivateKey,\n isBuilderEnvManaged,\n getBuilderProxyOrigin,\n getBuilderAuthHeader,\n resolveBuilderPrivateKey,\n resolveBuilderAuthHeader,\n resolveHasBuilderPrivateKey,\n resolveBuilderCredentials,\n resolveBuilderCredential,\n writeBuilderCredentials,\n deleteBuilderCredentials,\n resolveSecret,\n} from \"./credential-provider.js\";\nexport {\n getBuilderBranchProjectId,\n isBuilderBranchingEnabled,\n runBuilderAgent,\n type RunBuilderAgentResult,\n} from \"./builder-browser.js\";\n\nexport {\n sendEmail,\n isEmailConfigured,\n getEmailProvider,\n type EmailProvider,\n type SendEmailArgs,\n} from \"./email.js\";\nexport {\n renderEmail,\n emailStrong,\n emailLink,\n type RenderEmailArgs,\n type RenderedEmail,\n type EmailCta,\n} from \"./email-template.js\";\nexport { getAppProductionUrl, getFirstPartyProdUrl } from \"./app-url.js\";\nexport {\n getConfiguredAppBasePath,\n normalizeAppBasePath,\n withConfiguredAppBasePath,\n} from \"./app-base-path.js\";\nexport {\n signShortLivedToken,\n verifyShortLivedToken,\n type ShortLivedTokenClaims,\n type VerifyResult as ShortLivedTokenVerifyResult,\n} from \"./short-lived-token.js\";\n\n// SSR handler is NOT re-exported here — it uses a virtual module\n// (virtual:react-router/server-build) that only exists at Vite dev/build time.\n// Including it in this barrel would break the esbuild CF Pages bundler.\n// Templates import directly: import { ssrHandler } from \"@agent-native/core/server/ssr-handler\"\n\n// Nitro plugin helper — re-exported so templates don't need nitro as a direct dependency.\n// defineNitroPlugin is an identity function; this typed wrapper lets templates use it\n// without resolving `nitro/runtime` (which requires Nitro's virtual modules at runtime).\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\nexport function defineNitroPlugin(def: NitroPluginDef): NitroPluginDef {\n return def;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding-html.d.ts","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA0BH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAID,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,qBAA0B,GAAG,MAAM,CA60B1E;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAwG7C"}
1
+ {"version":3,"file":"onboarding-html.d.ts","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA0BH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAID,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,qBAA0B,GAAG,MAAM,CAs0B1E;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAwG7C"}
@@ -128,7 +128,7 @@ export function getOnboardingHtml(opts = {}) {
128
128
  letter-spacing: -0.02em;
129
129
  }
130
130
  .app-name img.brand-mark {
131
- height: 2.0125rem;
131
+ height: 2.21375rem;
132
132
  width: auto;
133
133
  display: block;
134
134
  flex-shrink: 0;
@@ -194,7 +194,7 @@ export function getOnboardingHtml(opts = {}) {
194
194
  .split { flex-direction: column; min-height: auto; }
195
195
  .marketing-panel { padding: 2rem 1.5rem 1.5rem; }
196
196
  .app-name { font-size: 1.375rem; }
197
- .app-name img.brand-mark { height: 1.4375rem; }
197
+ .app-name img.brand-mark { height: 1.58125rem; }
198
198
  .app-tagline { font-size: 1rem; margin-bottom: 1rem; }
199
199
  .app-desc { margin-bottom: 1rem; }
200
200
  .feature-list { gap: 0.5rem; }
@@ -837,14 +837,7 @@ ${showGoogle
837
837
  var data = await res.json();
838
838
  if (data.url) {
839
839
  try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}
840
- window.open(data.url, '_blank');
841
- btn.disabled = false;
842
- btn.textContent = 'Waiting for sign-in…';
843
- var poll = setInterval(function() {
844
- fetch(__anPath('/_agent-native/auth/session')).then(function(r) { return r.json(); }).then(function(s) {
845
- if (s && s.email) { clearInterval(poll); window.location.reload(); }
846
- }).catch(function() {});
847
- }, 1500);
840
+ window.location.href = data.url;
848
841
  } else {
849
842
  err.textContent = data.message || 'Google OAuth is not configured.';
850
843
  err.classList.add('show');