@agent-native/core 0.141.7 → 0.144.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 (328) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
  4. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
  5. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  6. package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
  7. package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  8. package/corpus/templates/analytics/AGENTS.md +35 -38
  9. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
  10. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
  11. package/corpus/templates/analytics/actions/navigate.ts +4 -5
  12. package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
  13. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +44 -11
  14. package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
  15. package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
  16. package/corpus/templates/analytics/app/i18n-data.ts +680 -0
  17. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
  18. package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
  19. package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
  20. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
  21. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
  22. package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
  23. package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
  24. package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
  25. package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
  26. package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
  27. package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
  28. package/corpus/templates/analytics/netlify.toml +7 -0
  29. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
  30. package/corpus/templates/analytics/server/db/index.ts +27 -0
  31. package/corpus/templates/analytics/server/db/schema.ts +10 -0
  32. package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
  33. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +133 -44
  34. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
  35. package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
  36. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
  37. package/corpus/templates/analytics/server/plugins/db.ts +52 -18
  38. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +28 -2
  39. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
  40. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
  41. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  42. package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
  43. package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  44. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
  45. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  46. package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
  47. package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  48. package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
  49. package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
  50. package/corpus/templates/brain/app/routes/sources.tsx +15 -7
  51. package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
  52. package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
  53. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
  54. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
  55. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  56. package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
  57. package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  58. package/corpus/templates/calendar/AGENTS.md +11 -32
  59. package/corpus/templates/calendar/actions/update-event.ts +107 -1
  60. package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
  61. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
  62. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
  63. package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
  64. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  65. package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  66. package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
  67. package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
  68. package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
  69. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  70. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  71. package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  72. package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  73. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
  74. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  75. package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
  76. package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  77. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
  78. package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
  79. package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
  80. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
  81. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
  82. package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
  83. package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
  84. package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
  86. package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
  87. package/corpus/templates/clips/desktop/src/app.tsx +48 -20
  88. package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
  89. package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
  90. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
  91. package/corpus/templates/clips/server/plugins/db.ts +214 -26
  92. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
  93. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  94. package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
  95. package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  96. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
  97. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  98. package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
  99. package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  100. package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
  101. package/corpus/templates/crm/server/plugins/db.ts +11 -8
  102. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
  103. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
  104. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  105. package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
  106. package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  107. package/corpus/templates/design/actions/import-from-url.ts +1 -1
  108. package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
  109. package/corpus/templates/design/app/pages/Index.tsx +6 -2
  110. package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
  111. package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
  112. package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
  113. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
  114. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  115. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
  116. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  117. package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
  118. package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
  119. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
  120. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  121. package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
  122. package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  123. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
  124. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  125. package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
  126. package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  127. package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  128. package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
  129. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
  130. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  131. package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
  132. package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  133. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
  134. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  135. package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
  136. package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  137. package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  138. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  139. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
  140. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  141. package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
  142. package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  143. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
  144. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +37 -1
  145. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
  146. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
  147. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
  148. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
  149. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  150. package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
  151. package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  152. package/corpus/templates/slides/AGENTS.md +7 -9
  153. package/corpus/templates/slides/_gitignore +1 -0
  154. package/corpus/templates/slides/actions/export-pptx.ts +402 -36
  155. package/corpus/templates/slides/actions/import-file.ts +46 -85
  156. package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
  157. package/corpus/templates/slides/actions/import-pptx.ts +85 -60
  158. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
  159. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
  160. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
  161. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
  162. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
  163. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
  164. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +173 -0
  165. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
  166. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  167. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
  168. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
  169. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
  170. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +4 -0
  171. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
  172. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  173. package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
  174. package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
  175. package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
  176. package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
  177. package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
  178. package/corpus/templates/slides/app/pages/Index.tsx +91 -1
  179. package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
  180. package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
  181. package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
  182. package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
  183. package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
  184. package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
  185. package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
  186. package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
  187. package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
  188. package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
  189. package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
  190. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
  191. package/corpus/templates/slides/server/handlers/import/html-converter.ts +236 -13
  192. package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
  193. package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
  194. package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
  195. package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -3
  196. package/corpus/templates/slides/server/lib/emails.ts +7 -2
  197. package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
  198. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
  199. package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
  200. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
  201. package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
  202. package/corpus/templates/slides/shared/upload-types.ts +3 -0
  203. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
  204. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  205. package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
  206. package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  207. package/dist/agent/production-agent.d.ts +17 -0
  208. package/dist/agent/production-agent.js +72 -1
  209. package/dist/cli/agent-plugin.d.ts +112 -0
  210. package/dist/cli/agent-plugin.js +1081 -0
  211. package/dist/cli/app-skill.js +39 -1
  212. package/dist/cli/code-agent-executor.d.ts +3 -0
  213. package/dist/cli/code-agent-executor.js +51 -13
  214. package/dist/cli/index.js +13 -0
  215. package/dist/cli/templates-meta.js +1 -1
  216. package/dist/client/AgentPanel.d.ts +3 -1
  217. package/dist/client/AgentPanel.js +9 -2
  218. package/dist/client/AssistantChat.d.ts +8 -0
  219. package/dist/client/AssistantChat.js +23 -8
  220. package/dist/client/NewWorkspaceAppFlow.js +1 -0
  221. package/dist/client/agent-chat-adapter.js +123 -4
  222. package/dist/client/assistant-ui-recovery.d.ts +2 -1
  223. package/dist/client/assistant-ui-recovery.js +7 -3
  224. package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
  225. package/dist/client/org/TeamPage.js +1 -1
  226. package/dist/client/require-session.js +1 -1
  227. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  228. package/dist/client/resources/McpConnectionSuggestion.js +27 -10
  229. package/dist/client/resources/McpIntegrationDialog.js +77 -45
  230. package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
  231. package/dist/client/resources/mcp-integration-catalog.js +255 -2
  232. package/dist/client/resources/mcp-integration-logos.js +18 -2
  233. package/dist/client/settings/AccountSettingsCard.js +2 -1
  234. package/dist/collab/routes.d.ts +1 -1
  235. package/dist/collab/struct-routes.d.ts +1 -1
  236. package/dist/db/client.d.ts +9 -0
  237. package/dist/db/client.js +51 -16
  238. package/dist/db/create-get-db.js +2 -2
  239. package/dist/db/ddl-guard.d.ts +11 -10
  240. package/dist/db/ddl-guard.js +40 -12
  241. package/dist/deploy/build.d.ts +2 -0
  242. package/dist/deploy/build.js +97 -4
  243. package/dist/deploy/workspace-deploy.js +0 -2
  244. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  245. package/dist/guards/no-env-credentials.js +9 -0
  246. package/dist/ingestion/index.d.ts +1 -1
  247. package/dist/ingestion/pptx.d.ts +68 -0
  248. package/dist/ingestion/pptx.js +660 -213
  249. package/dist/integrations/plugin.js +9 -6
  250. package/dist/localization/default-messages.d.ts +54 -0
  251. package/dist/localization/default-messages.js +57 -2
  252. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  253. package/dist/mcp-client/oauth-routes.d.ts +2 -0
  254. package/dist/mcp-client/oauth-routes.js +73 -6
  255. package/dist/notifications/routes.d.ts +1 -1
  256. package/dist/observability/routes.d.ts +3 -3
  257. package/dist/onboarding/app-profile.js +11 -0
  258. package/dist/resources/handlers.d.ts +1 -1
  259. package/dist/resources/store.js +15 -1
  260. package/dist/scripts/call-agent.js +34 -4
  261. package/dist/secrets/routes.d.ts +9 -9
  262. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  263. package/dist/server/agent-chat/action-filters-a2a.js +36 -1
  264. package/dist/server/agent-chat-plugin.js +29 -8
  265. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  266. package/dist/server/auth.js +47 -11
  267. package/dist/server/better-auth-instance.js +5 -3
  268. package/dist/server/core-routes-plugin.d.ts +8 -1
  269. package/dist/server/core-routes-plugin.js +28 -3
  270. package/dist/server/credential-provider.d.ts +3 -3
  271. package/dist/server/credential-provider.js +90 -4
  272. package/dist/server/onboarding-html.d.ts +2 -0
  273. package/dist/server/onboarding-html.js +115 -29
  274. package/dist/server/self-dispatch.d.ts +5 -4
  275. package/dist/server/self-dispatch.js +25 -14
  276. package/dist/server/ssr-handler.d.ts +1 -1
  277. package/dist/server/ssr-handler.js +1 -1
  278. package/dist/server/transcribe-voice.d.ts +1 -1
  279. package/dist/shared/cache-control.d.ts +26 -2
  280. package/dist/shared/cache-control.js +43 -2
  281. package/dist/shared/password-policy.d.ts +3 -0
  282. package/dist/shared/password-policy.js +3 -0
  283. package/dist/sharing/actions/set-resource-visibility.js +16 -4
  284. package/dist/sharing/registry.d.ts +14 -0
  285. package/dist/styles/agent-native.css +6 -0
  286. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  287. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  288. package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  289. package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  290. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  291. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  292. package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  293. package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  294. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  295. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  296. package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  297. package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  298. package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  299. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  300. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  301. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  302. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  303. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  304. package/dist/templates/workspace-root/AGENTS.md +7 -0
  305. package/dist/user-profile/actions/change-password.js +8 -3
  306. package/dist/user-profile/actions/set-password.js +5 -1
  307. package/dist/vite/action-types-plugin.js +59 -0
  308. package/docs/content/skills-guide.mdx +13 -0
  309. package/package.json +6 -2
  310. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  311. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  312. package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  313. package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  314. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  315. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  316. package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  317. package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  318. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  319. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  320. package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  321. package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  322. package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  323. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  324. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  325. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  326. package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  327. package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  328. package/src/templates/workspace-root/AGENTS.md +7 -0
@@ -8,6 +8,7 @@ import { resolveAccess } from "@agent-native/core/sharing";
8
8
  import { z } from "zod";
9
9
 
10
10
  import "../server/db/index.js"; // ensure registerShareableResource runs
11
+ import { readLocalImportedAsset } from "../server/lib/import-asset-storage.js";
11
12
  import {
12
13
  safeGeneratedFilename,
13
14
  tenantExportDir,
@@ -98,6 +99,20 @@ interface TextElement {
98
99
  align?: "left" | "center" | "right";
99
100
  letterSpacing?: number;
100
101
  lineSpacing?: number;
102
+ runs?: TextRunElement[];
103
+ order?: number;
104
+ }
105
+
106
+ interface TextRunElement {
107
+ text: string;
108
+ options: {
109
+ fontSize?: number;
110
+ fontFace?: string;
111
+ color?: string;
112
+ bold?: boolean;
113
+ italic?: boolean;
114
+ underline?: { style: "sng" };
115
+ };
101
116
  }
102
117
 
103
118
  interface ImageElement {
@@ -106,6 +121,28 @@ interface ImageElement {
106
121
  y: number;
107
122
  w: number;
108
123
  h: number;
124
+ order?: number;
125
+ }
126
+
127
+ interface ShapeElement {
128
+ x: number;
129
+ y: number;
130
+ w: number;
131
+ h: number;
132
+ fill?: string;
133
+ lineColor?: string;
134
+ lineWidth?: number;
135
+ rounded?: boolean;
136
+ order?: number;
137
+ }
138
+
139
+ interface GridElement {
140
+ color: string;
141
+ stepX: number;
142
+ stepY: number;
143
+ offsetX: number;
144
+ offsetY: number;
145
+ lineWidth: number;
109
146
  }
110
147
 
111
148
  export function assertServerPptxExportable(
@@ -118,6 +155,7 @@ export function assertServerPptxExportable(
118
155
  const hasPersistedFreeformObject =
119
156
  /\bdata-slide-object-id\s*=/i.test(html) ||
120
157
  /\bclass\s*=\s*["'][^"']*\bfmd-freeform-object\b/i.test(html);
158
+ if (html.includes('data-imported-pptx="true"')) return;
121
159
  if (!hasPersistedFreeformObject) return;
122
160
 
123
161
  const error = new Error(
@@ -138,14 +176,21 @@ export function parseSlideHtml(
138
176
  ): {
139
177
  texts: TextElement[];
140
178
  images: ImageElement[];
179
+ shapes: ShapeElement[];
180
+ grid?: GridElement;
141
181
  bgColor: string;
142
182
  } {
143
183
  assertServerPptxExportable(html, slideNumber);
184
+ const dims = getAspectRatioDims(aspectRatio);
185
+ if (html.includes('data-imported-pptx="true"')) {
186
+ return parseImportedSlideHtml(html, dims);
187
+ }
188
+
144
189
  const texts: TextElement[] = [];
145
190
  const images: ImageElement[] = [];
191
+ const shapes: ShapeElement[] = [];
146
192
  let bgColor = "000000";
147
193
 
148
- const dims = getAspectRatioDims(aspectRatio);
149
194
  const slideW = dims.pptxInches.w;
150
195
  const slideH = dims.pptxInches.h;
151
196
 
@@ -321,7 +366,241 @@ export function parseSlideHtml(
321
366
  }
322
367
  }
323
368
 
324
- return { texts, images, bgColor };
369
+ return { texts, images, shapes, bgColor };
370
+ }
371
+
372
+ type SlideDims = ReturnType<typeof getAspectRatioDims>;
373
+
374
+ function parseImportedSlideHtml(
375
+ html: string,
376
+ dims: SlideDims,
377
+ ): {
378
+ texts: TextElement[];
379
+ images: ImageElement[];
380
+ shapes: ShapeElement[];
381
+ grid?: GridElement;
382
+ bgColor: string;
383
+ } {
384
+ const texts: TextElement[] = [];
385
+ const images: ImageElement[] = [];
386
+ const shapes: ShapeElement[] = [];
387
+ const outerStyle = html.match(
388
+ /class=["'][^"']*\bfmd-slide\b[^"']*["'][^>]*style=["']([^"']*)["']/i,
389
+ )?.[1];
390
+ const bgColor = colorToHex(
391
+ outerStyle
392
+ ? (getStyle(outerStyle, "background(?:-color)?") ?? "#000000") // guard:allow-raw-color - PPTX background fallback
393
+ : "#000000", // guard:allow-raw-color - PPTX background fallback
394
+ );
395
+ const grid = outerStyle ? parseImportedGrid(outerStyle) : undefined;
396
+ const elementRegex =
397
+ /<div\b([^>]*\bdata-pptx-element-kind=["'](text|image|shape)["'][^>]*)>([\s\S]*?)<\/div>/gi;
398
+ let match: RegExpExecArray | null;
399
+ while ((match = elementRegex.exec(html)) !== null) {
400
+ const attrs = match[1];
401
+ const kind = match[2].toLowerCase();
402
+ const innerHtml = match[3];
403
+ const style = getAttribute(attrs, "style") ?? "";
404
+ const geometry = importedGeometry(style, dims);
405
+ if (!geometry) continue;
406
+
407
+ if (kind === "image") {
408
+ const imageAttrs = innerHtml.match(/<img\b([^>]*)>/i)?.[1] ?? "";
409
+ const src = getAttribute(imageAttrs, "src");
410
+ if (src) {
411
+ images.push({ src, ...geometry, order: match.index });
412
+ }
413
+ continue;
414
+ }
415
+
416
+ if (kind === "shape") {
417
+ const fill = getStyle(style, "background(?:-color)?");
418
+ const border = getStyle(style, "border");
419
+ const borderMatch = border?.match(/([\d.]+)px\s+solid\s+(.+)/i);
420
+ shapes.push({
421
+ ...geometry,
422
+ ...(fill && !fill.includes("gradient")
423
+ ? { fill: colorToHex(fill) }
424
+ : {}),
425
+ ...(borderMatch
426
+ ? {
427
+ lineColor: colorToHex(borderMatch[2]),
428
+ lineWidth: Number(borderMatch[1]),
429
+ }
430
+ : {}),
431
+ rounded: style.includes("border-radius"),
432
+ order: match.index,
433
+ });
434
+ continue;
435
+ }
436
+
437
+ const runs = importedTextRuns(innerHtml);
438
+ const firstRun = runs.find((run) => run.text.trim()) ?? runs[0];
439
+ const firstParagraph = innerHtml.match(
440
+ /<p\b[^>]*style=["']([^"']*)["']/i,
441
+ )?.[1];
442
+ const lineHeight = firstParagraph
443
+ ? getStyle(firstParagraph, "line-height")
444
+ : null;
445
+ const fontSize = firstRun?.options.fontSize ?? 18;
446
+ const alignValue = getStyle(style, "text-align");
447
+ texts.push({
448
+ text: runs.map((run) => run.text).join(""),
449
+ fontSize,
450
+ fontFace: firstRun?.options.fontFace ?? "Poppins",
451
+ color: firstRun?.options.color ?? "FFFFFF",
452
+ bold: firstRun?.options.bold ?? false,
453
+ align:
454
+ alignValue === "center" || alignValue === "right" ? alignValue : "left",
455
+ lineSpacing: lineHeight ? Number(lineHeight) * fontSize : undefined,
456
+ x: geometry.x,
457
+ y: geometry.y,
458
+ w: geometry.w,
459
+ h: geometry.h,
460
+ runs,
461
+ order: match.index,
462
+ });
463
+ }
464
+
465
+ return { texts, images, shapes, grid, bgColor };
466
+ }
467
+
468
+ function parseImportedGrid(style: string): GridElement | undefined {
469
+ const backgroundImage = getStyle(style, "background-image");
470
+ const size = getStyle(style, "background-size")
471
+ ?.split(/\s+/)
472
+ .map((value) => Number.parseFloat(value));
473
+ const position = getStyle(style, "background-position")
474
+ ?.split(/\s+/)
475
+ .map((value) => Number.parseFloat(value));
476
+ const color = backgroundImage?.match(/#[0-9a-f]{6}|rgb\([^)]*\)/i)?.[0];
477
+ const lineWidth = backgroundImage?.match(/\s0\s+([\d.]+)px/i)?.[1];
478
+ if (
479
+ !color ||
480
+ !size ||
481
+ size.length < 2 ||
482
+ !Number.isFinite(size[0]) ||
483
+ !Number.isFinite(size[1]) ||
484
+ size[0] <= 0 ||
485
+ size[1] <= 0 ||
486
+ !position ||
487
+ position.length < 2 ||
488
+ !Number.isFinite(position[0]) ||
489
+ !Number.isFinite(position[1]) ||
490
+ !lineWidth
491
+ ) {
492
+ return undefined;
493
+ }
494
+ return {
495
+ color: colorToHex(color),
496
+ stepX: size[0],
497
+ stepY: size[1],
498
+ offsetX: position[0],
499
+ offsetY: position[1],
500
+ lineWidth: Number.parseFloat(lineWidth),
501
+ };
502
+ }
503
+
504
+ function importedGeometry(
505
+ style: string,
506
+ dims: SlideDims,
507
+ ): { x: number; y: number; w: number; h: number } | null {
508
+ const left = cssPx(style, "left");
509
+ const top = cssPx(style, "top");
510
+ const width = cssPx(style, "width");
511
+ const height = cssPx(style, "height");
512
+ if (left == null || top == null || width == null || height == null)
513
+ return null;
514
+ return {
515
+ x: pxToIn(left, dims),
516
+ y: pxToInY(top, dims),
517
+ w: pxToIn(width, dims),
518
+ h: pxToInY(height, dims),
519
+ };
520
+ }
521
+
522
+ function pxToInY(px: number, dims: SlideDims): number {
523
+ return (px / dims.height) * dims.pptxInches.h;
524
+ }
525
+
526
+ function importedTextRuns(html: string): TextRunElement[] {
527
+ const paragraphs = [...html.matchAll(/<p\b[^>]*>([\s\S]*?)<\/p>/gi)].map(
528
+ (match) => match[1],
529
+ );
530
+ const blocks = paragraphs.length > 0 ? paragraphs : [html];
531
+ const runs: TextRunElement[] = [];
532
+ blocks.forEach((block, paragraphIndex) => {
533
+ if (paragraphIndex > 0) runs.push({ text: "\n", options: {} });
534
+ const spans = [...block.matchAll(/<span\b([^>]*)>([\s\S]*?)<\/span>/gi)];
535
+ if (spans.length === 0) {
536
+ const text = decodeHtmlText(stripTags(block));
537
+ if (text) runs.push({ text, options: {} });
538
+ return;
539
+ }
540
+ for (const span of spans) {
541
+ const attrs = span[1];
542
+ const style = getAttribute(attrs, "style") ?? "";
543
+ const text = decodeHtmlText(stripTags(span[2]));
544
+ if (!text) continue;
545
+ runs.push({ text, options: importedRunOptions(style) });
546
+ }
547
+ });
548
+ return runs;
549
+ }
550
+
551
+ function importedRunOptions(style: string): TextRunElement["options"] {
552
+ const fontSizePx = cssPx(style, "font-size");
553
+ const fontFamily = getStyle(style, "font-family")
554
+ ?.replace(/["']/g, "")
555
+ .split(",")[0]
556
+ ?.trim();
557
+ const fontWeight = getStyle(style, "font-weight");
558
+ return {
559
+ ...(fontSizePx != null ? { fontSize: pxToPt(fontSizePx) } : {}),
560
+ ...(fontFamily ? { fontFace: fontFamily } : {}),
561
+ ...(getStyle(style, "color")
562
+ ? { color: colorToHex(getStyle(style, "color") ?? "#FFFFFF") } // guard:allow-raw-color - PPTX text fallback
563
+ : {}),
564
+ ...(fontWeight
565
+ ? {
566
+ bold: Number.parseInt(fontWeight, 10) >= 700 || fontWeight === "bold",
567
+ }
568
+ : {}),
569
+ ...(getStyle(style, "font-style") === "italic" ? { italic: true } : {}),
570
+ ...(getStyle(style, "text-decoration")?.includes("underline")
571
+ ? { underline: { style: "sng" as const } }
572
+ : {}),
573
+ };
574
+ }
575
+
576
+ function cssPx(style: string, property: string): number | null {
577
+ const value = getStyle(style, property);
578
+ if (!value) return null;
579
+ const parsed = Number.parseFloat(value);
580
+ return Number.isFinite(parsed) ? parsed : null;
581
+ }
582
+
583
+ function getAttribute(attrs: string, name: string): string | null {
584
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
585
+ const match = attrs.match(
586
+ new RegExp(`\\b${escapedName}\\s*=\\s*(["'])(.*?)\\1`, "i"),
587
+ );
588
+ return match?.[2] ?? null;
589
+ }
590
+
591
+ function stripTags(value: string): string {
592
+ return value.replace(/<br\s*\/?\s*>/gi, "\n").replace(/<[^>]+>/g, "");
593
+ }
594
+
595
+ function decodeHtmlText(value: string): string {
596
+ return value
597
+ .replace(/&nbsp;/gi, " ")
598
+ .replace(/&amp;/gi, "&")
599
+ .replace(/&lt;/gi, "<")
600
+ .replace(/&gt;/gi, ">")
601
+ .replace(/&quot;/gi, '"')
602
+ .replace(/&#x27;|&#39;/gi, "'")
603
+ .replace(/&#x25cf;/gi, "●");
325
604
  }
326
605
 
327
606
  /**
@@ -334,8 +613,23 @@ export function parseSlideHtml(
334
613
  * image so a 200 OK from an internal HTML / JSON endpoint can't smuggle bytes
335
614
  * into the .pptx.
336
615
  */
337
- export async function fetchImageAsBase64(url: string): Promise<string | null> {
616
+ export async function fetchImageAsBase64(
617
+ url: string,
618
+ ownerEmail?: string,
619
+ ): Promise<string | null> {
338
620
  try {
621
+ const parsedUrl = new URL(url, "http://slides.local");
622
+ if (parsedUrl.pathname.startsWith("/api/import-assets/") && ownerEmail) {
623
+ const token = parsedUrl.pathname.slice("/api/import-assets/".length);
624
+ const localAsset = await readLocalImportedAsset({
625
+ token,
626
+ email: ownerEmail,
627
+ });
628
+ if (localAsset) {
629
+ return `data:${localAsset.mimeType};base64,${Buffer.from(localAsset.data).toString("base64")}`;
630
+ }
631
+ return null;
632
+ }
339
633
  const response = await ssrfSafeFetch(
340
634
  url,
341
635
  { signal: AbortSignal.timeout(10_000) },
@@ -356,7 +650,7 @@ export async function fetchImageAsBase64(url: string): Promise<string | null> {
356
650
 
357
651
  export default defineAction({
358
652
  description:
359
- "Export a normal-flow deck as a PowerPoint (.pptx) file. Decks with freeform positioned objects must use the Slides editor's Export > PowerPoint flow so browser-rendered geometry is preserved. Returns a download URL for the generated file.",
653
+ "Export a deck as a PowerPoint (.pptx) file, preserving imported PPTX geometry, text styles, shapes, and images. Freeform editor objects must use the Slides editor's Export > PowerPoint flow so browser-rendered geometry is preserved. Returns a download URL for the generated file.",
360
654
  schema: z.object({
361
655
  deckId: z.string().describe("Deck ID to export"),
362
656
  includeNotes: z
@@ -409,7 +703,7 @@ export default defineAction({
409
703
  slide && typeof slide === "object" && typeof slide.content === "string"
410
704
  ? slide.content
411
705
  : "";
412
- const { texts, images, bgColor } = parseSlideHtml(
706
+ const { texts, images, shapes, grid, bgColor } = parseSlideHtml(
413
707
  slideContent,
414
708
  aspectRatio,
415
709
  slideIndex + 1,
@@ -417,39 +711,111 @@ export default defineAction({
417
711
 
418
712
  pptxSlide.background = { color: bgColor };
419
713
 
420
- // Add text elements
421
- for (const t of texts) {
422
- pptxSlide.addText(t.text, {
423
- x: t.x,
424
- y: t.y,
425
- w: t.w,
426
- h: t.h,
427
- fontSize: t.fontSize,
428
- fontFace: t.fontFace,
429
- color: t.color,
430
- bold: t.bold,
431
- align: t.align || "left",
432
- valign: "top",
433
- wrap: true,
434
- ...(t.letterSpacing != null ? { charSpacing: t.letterSpacing } : {}),
435
- ...(t.lineSpacing != null
436
- ? { lineSpacingMultiple: t.lineSpacing / t.fontSize }
437
- : {}),
438
- });
714
+ if (grid) {
715
+ const gridWidth = pxToIn(grid.stepX, dims);
716
+ const gridHeight = pxToInY(grid.stepY, dims);
717
+ const gridX = pxToIn(grid.offsetX, dims);
718
+ const gridY = pxToInY(grid.offsetY, dims);
719
+ const lineWidth = Math.max(0.5, grid.lineWidth * 0.75);
720
+
721
+ for (let x = gridX; x < dims.pptxInches.w; x += gridWidth) {
722
+ pptxSlide.addShape(pptx.ShapeType.line, {
723
+ x,
724
+ y: 0,
725
+ w: 0,
726
+ h: dims.pptxInches.h,
727
+ line: { color: grid.color, width: lineWidth },
728
+ });
729
+ }
730
+ for (let y = gridY; y < dims.pptxInches.h; y += gridHeight) {
731
+ pptxSlide.addShape(pptx.ShapeType.line, {
732
+ x: 0,
733
+ y,
734
+ w: dims.pptxInches.w,
735
+ h: 0,
736
+ line: { color: grid.color, width: lineWidth },
737
+ });
738
+ }
439
739
  }
440
740
 
441
- // Add images
442
- for (const img of images) {
443
- // Try to fetch and embed as base64
444
- const dataUri = await fetchImageAsBase64(img.src);
445
- if (dataUri) {
446
- pptxSlide.addImage({
447
- data: dataUri,
448
- x: img.x,
449
- y: img.y,
450
- w: img.w,
451
- h: img.h,
452
- });
741
+ const orderedTexts = [...texts].sort(
742
+ (a, b) => (a.order ?? 0) - (b.order ?? 0),
743
+ );
744
+ const orderedImages = [...images].sort(
745
+ (a, b) => (a.order ?? 0) - (b.order ?? 0),
746
+ );
747
+ const orderedShapes = [...shapes].sort(
748
+ (a, b) => (a.order ?? 0) - (b.order ?? 0),
749
+ );
750
+
751
+ // Imported elements are parsed separately because PptxGenJS needs real
752
+ // slide objects. Keep their source order so overlapping objects retain
753
+ // the same paint order as the editor preview.
754
+ const orderedObjects = [
755
+ ...orderedTexts.map((value) => ({ kind: "text" as const, value })),
756
+ ...orderedImages.map((value) => ({ kind: "image" as const, value })),
757
+ ...orderedShapes.map((value) => ({ kind: "shape" as const, value })),
758
+ ].sort((a, b) => (a.value.order ?? 0) - (b.value.order ?? 0));
759
+
760
+ for (const object of orderedObjects) {
761
+ if (object.kind === "text") {
762
+ const t = object.value;
763
+ const options = {
764
+ x: t.x,
765
+ y: t.y,
766
+ w: t.w,
767
+ h: t.h,
768
+ fontSize: t.fontSize,
769
+ fontFace: t.fontFace,
770
+ color: t.color,
771
+ bold: t.bold,
772
+ align: t.align || "left",
773
+ valign: "top" as const,
774
+ wrap: true,
775
+ ...(t.letterSpacing != null
776
+ ? { charSpacing: t.letterSpacing }
777
+ : {}),
778
+ ...(t.lineSpacing != null
779
+ ? { lineSpacingMultiple: t.lineSpacing / t.fontSize }
780
+ : {}),
781
+ };
782
+ if (t.runs?.length) {
783
+ pptxSlide.addText(t.runs, options);
784
+ } else {
785
+ pptxSlide.addText(t.text, options);
786
+ }
787
+ } else if (object.kind === "image") {
788
+ const img = object.value;
789
+ const dataUri = await fetchImageAsBase64(img.src, userEmail);
790
+ if (dataUri) {
791
+ pptxSlide.addImage({
792
+ data: dataUri,
793
+ x: img.x,
794
+ y: img.y,
795
+ w: img.w,
796
+ h: img.h,
797
+ });
798
+ }
799
+ } else {
800
+ const shape = object.value;
801
+ pptxSlide.addShape(
802
+ shape.rounded ? pptx.ShapeType.roundRect : pptx.ShapeType.rect,
803
+ {
804
+ x: shape.x,
805
+ y: shape.y,
806
+ w: shape.w,
807
+ h: shape.h,
808
+ ...(shape.fill ? { fill: { color: shape.fill } } : {}),
809
+ ...(shape.lineColor
810
+ ? {
811
+ line: {
812
+ color: shape.lineColor,
813
+ width: shape.lineWidth ?? 1,
814
+ },
815
+ }
816
+ : {}),
817
+ },
818
+ );
453
819
  }
454
820
  }
455
821