@agent-native/core 0.141.7 → 0.144.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +9 -0
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/analytics/AGENTS.md +35 -38
- package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
- package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
- package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +1 -1
- package/corpus/templates/analytics/actions/navigate.ts +4 -5
- package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +44 -11
- package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
- package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
- package/corpus/templates/analytics/app/i18n-data.ts +680 -0
- package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
- package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
- package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
- package/corpus/templates/analytics/netlify.toml +7 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
- package/corpus/templates/analytics/server/db/index.ts +27 -0
- package/corpus/templates/analytics/server/db/schema.ts +10 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +156 -45
- package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
- package/corpus/templates/analytics/server/plugins/db.ts +52 -18
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +28 -2
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
- package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
- package/corpus/templates/brain/app/routes/sources.tsx +15 -7
- package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
- package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/calendar/AGENTS.md +11 -32
- package/corpus/templates/calendar/actions/update-event.ts +107 -1
- package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
- package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
- package/corpus/templates/calendar/app/i18n-data.ts +20 -0
- package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
- package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
- package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
- package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
- package/corpus/templates/clips/app/components/player/player-controls.tsx +0 -3
- package/corpus/templates/clips/app/components/player/scrubber.tsx +2 -33
- package/corpus/templates/clips/app/components/player/video-player.tsx +58 -11
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
- package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-trimmed-clips-play-on-a-clean-timeline-without-cut-markers.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +48 -20
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
- package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
- package/corpus/templates/clips/server/plugins/db.ts +214 -26
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
- package/corpus/templates/crm/server/plugins/db.ts +11 -8
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/design/actions/import-from-url.ts +1 -1
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
- package/corpus/templates/design/app/pages/Index.tsx +6 -2
- package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
- package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/dispatch/AGENTS.md +8 -1
- package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -0
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +30 -15
- package/corpus/templates/dispatch/app/i18n-data.ts +131 -0
- package/corpus/templates/dispatch/app/routes/admin._index.tsx +4 -0
- package/corpus/templates/dispatch/app/routes/admin.agents.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.approvals.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.apps.$appId.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.apps.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.audit.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.automations.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.destinations.tsx +4 -0
- package/corpus/templates/dispatch/app/routes/admin.dreams.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.identities.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.integrations.tsx +4 -0
- package/corpus/templates/dispatch/app/routes/admin.messaging.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.metrics.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.new-app.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.operations.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.thread-debug.tsx +4 -0
- package/corpus/templates/dispatch/app/routes/admin.transactional-email.$appId.$id.tsx +4 -0
- package/corpus/templates/dispatch/app/routes/admin.transactional-email.tsx +4 -0
- package/corpus/templates/dispatch/app/routes/admin.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.vault.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/admin.workspace.tsx +1 -0
- package/corpus/templates/dispatch/changelog/2026-08-06-dispatch-keeps-everyday-navigation-focused-while-management-.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +37 -1
- package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/slides/AGENTS.md +17 -21
- package/corpus/templates/slides/_gitignore +1 -0
- package/corpus/templates/slides/actions/export-pptx.ts +470 -36
- package/corpus/templates/slides/actions/get-deck.ts +12 -0
- package/corpus/templates/slides/actions/import-file.ts +175 -139
- package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
- package/corpus/templates/slides/actions/import-pptx.ts +193 -68
- package/corpus/templates/slides/actions/patch-deck.ts +51 -0
- package/corpus/templates/slides/actions/update-slide.ts +29 -3
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +173 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
- package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
- package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +15 -0
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +72 -11
- package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
- package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
- package/corpus/templates/slides/app/lib/import-uploaded-deck.ts +89 -0
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
- package/corpus/templates/slides/app/pages/Index.tsx +172 -15
- package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-uploaded-decks-keep-their-slides-and-visuals-when-you-improv.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +247 -13
- package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
- package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
- package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
- package/corpus/templates/slides/server/lib/chat-attachments.ts +7 -4
- package/corpus/templates/slides/server/lib/emails.ts +7 -2
- package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
- package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
- package/corpus/templates/slides/server/lib/source-import.ts +167 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +12 -3
- package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
- package/corpus/templates/slides/shared/upload-types.ts +3 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/agent/production-agent.d.ts +17 -0
- package/dist/agent/production-agent.js +72 -1
- package/dist/cli/agent-plugin.d.ts +112 -0
- package/dist/cli/agent-plugin.js +1081 -0
- package/dist/cli/app-skill.js +39 -1
- package/dist/cli/code-agent-executor.d.ts +3 -0
- package/dist/cli/code-agent-executor.js +51 -13
- package/dist/cli/index.js +13 -0
- package/dist/cli/templates-meta.js +1 -1
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.js +9 -2
- package/dist/client/AssistantChat.d.ts +8 -0
- package/dist/client/AssistantChat.js +23 -8
- package/dist/client/NewWorkspaceAppFlow.js +1 -0
- package/dist/client/agent-chat-adapter.js +123 -4
- package/dist/client/assistant-ui-recovery.d.ts +2 -1
- package/dist/client/assistant-ui-recovery.js +7 -3
- package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
- package/dist/client/org/TeamPage.js +1 -1
- package/dist/client/require-session.js +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
- package/dist/client/resources/McpConnectionSuggestion.js +27 -10
- package/dist/client/resources/McpIntegrationDialog.js +77 -45
- package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
- package/dist/client/resources/mcp-integration-catalog.js +255 -2
- package/dist/client/resources/mcp-integration-logos.js +18 -2
- package/dist/client/settings/AccountSettingsCard.js +2 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +9 -0
- package/dist/db/client.js +51 -16
- package/dist/db/create-get-db.js +2 -2
- package/dist/db/ddl-guard.d.ts +11 -10
- package/dist/db/ddl-guard.js +40 -12
- package/dist/deploy/build.d.ts +2 -0
- package/dist/deploy/build.js +97 -4
- package/dist/deploy/workspace-deploy.js +0 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/guards/no-env-credentials.js +9 -0
- package/dist/ingestion/index.d.ts +1 -1
- package/dist/ingestion/pptx.d.ts +68 -0
- package/dist/ingestion/pptx.js +660 -213
- package/dist/integrations/plugin.js +9 -6
- package/dist/jobs/scheduler.js +79 -23
- package/dist/localization/default-messages.d.ts +54 -0
- package/dist/localization/default-messages.js +57 -2
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp-client/oauth-routes.d.ts +2 -0
- package/dist/mcp-client/oauth-routes.js +73 -6
- package/dist/observability/routes.d.ts +5 -5
- package/dist/onboarding/app-profile.js +11 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/store.js +15 -1
- package/dist/scripts/call-agent.js +34 -4
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +36 -1
- package/dist/server/agent-chat-plugin.js +29 -8
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +47 -11
- package/dist/server/better-auth-instance.js +5 -3
- package/dist/server/core-routes-plugin.d.ts +8 -1
- package/dist/server/core-routes-plugin.js +28 -3
- package/dist/server/credential-provider.d.ts +3 -3
- package/dist/server/credential-provider.js +90 -4
- package/dist/server/onboarding-html.d.ts +2 -0
- package/dist/server/onboarding-html.js +115 -29
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/self-dispatch.d.ts +5 -4
- package/dist/server/self-dispatch.js +25 -14
- package/dist/server/ssr-handler.d.ts +1 -1
- package/dist/server/ssr-handler.js +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/cache-control.d.ts +26 -2
- package/dist/shared/cache-control.js +43 -2
- package/dist/shared/password-policy.d.ts +3 -0
- package/dist/shared/password-policy.js +3 -0
- package/dist/sharing/actions/set-resource-visibility.js +16 -4
- package/dist/sharing/registry.d.ts +14 -0
- package/dist/styles/agent-native.css +6 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/workspace-root/AGENTS.md +7 -0
- package/dist/user-profile/actions/change-password.js +8 -3
- package/dist/user-profile/actions/set-password.js +5 -1
- package/dist/vite/action-types-plugin.js +59 -0
- package/docs/content/creating-templates.mdx +1 -1
- package/docs/content/getting-started-actions.mdx +38 -189
- package/docs/content/getting-started-database.mdx +80 -164
- package/docs/content/getting-started-pages.mdx +44 -155
- package/docs/content/getting-started.mdx +26 -106
- package/docs/content/skills-guide.mdx +13 -0
- package/package.json +6 -2
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/workspace-root/AGENTS.md +7 -0
|
@@ -15,8 +15,15 @@ import { z } from "zod";
|
|
|
15
15
|
|
|
16
16
|
import { getDb, schema } from "../server/db/index.js";
|
|
17
17
|
import { notifyClients } from "../server/handlers/decks.js";
|
|
18
|
+
import { uploadPptxSlideImages } from "../server/handlers/import/pptx-assets.js";
|
|
18
19
|
import { upsertBuilderProxyDesignSystem } from "../server/lib/builder-design-system-proxy.js";
|
|
19
20
|
import { setupPdfParse } from "../server/lib/pdf-parse-setup.js";
|
|
21
|
+
import {
|
|
22
|
+
buildSourceImportMetadata,
|
|
23
|
+
mergeSourceImportMetadata,
|
|
24
|
+
sourceImportForDeck,
|
|
25
|
+
type SourceImportSlideSnapshot,
|
|
26
|
+
} from "../server/lib/source-import.js";
|
|
20
27
|
import {
|
|
21
28
|
ASPECT_RATIOS,
|
|
22
29
|
DEFAULT_ASPECT_RATIO,
|
|
@@ -30,9 +37,9 @@ const DEFAULT_MAX_SOURCE_CHARS = 60_000;
|
|
|
30
37
|
export default defineAction({
|
|
31
38
|
description:
|
|
32
39
|
"Import a file (PPTX, DOCX, PDF, FIG) and extract content for creating slides or slide design systems. " +
|
|
33
|
-
"For PPTX files, returns parsed slides with text and layout info ready for conversion. " +
|
|
40
|
+
"For PPTX files, returns parsed slides with text and layout info ready for conversion, or writes positioned source-preserving slides when importIntoDeck is true. " +
|
|
34
41
|
"For DOCX files, returns structured sections extracted from the document. " +
|
|
35
|
-
"For PDF files, returns extracted text organized by page. " +
|
|
42
|
+
"For PDF files, returns extracted text organized by page, or source-faithful page-image slides when importIntoDeck is true. " +
|
|
36
43
|
"For Figma .fig files, requires Builder.io (free tier available) and starts Builder design-system indexing; the returned Builder job/design-system ids are the source of truth. " +
|
|
37
44
|
"The agent can then use the extracted content to create a deck via create-deck or add-slide, or tell the user where Builder is indexing the design system.",
|
|
38
45
|
schema: z.object({
|
|
@@ -53,7 +60,7 @@ export default defineAction({
|
|
|
53
60
|
.optional()
|
|
54
61
|
.default(false)
|
|
55
62
|
.describe(
|
|
56
|
-
"If true, append slides
|
|
63
|
+
"If true, append slides to deckId. PDF pages are imported as source-faithful images that preserve their original layout and aspect ratio; use the default false when editable extracted source text is needed.",
|
|
57
64
|
),
|
|
58
65
|
maxChars: z.coerce
|
|
59
66
|
.number()
|
|
@@ -152,7 +159,37 @@ export default defineAction({
|
|
|
152
159
|
(total, r) => total + r.imageSkippedCount,
|
|
153
160
|
0,
|
|
154
161
|
);
|
|
155
|
-
|
|
162
|
+
const sourceImport = buildSourceImportMetadata({
|
|
163
|
+
format: "pptx",
|
|
164
|
+
slides: pptxResults.map((result) => ({
|
|
165
|
+
id: result.slide.id,
|
|
166
|
+
text: result.sourceText,
|
|
167
|
+
notes: result.slide.notes ?? "",
|
|
168
|
+
imageUrls: result.imageUrls,
|
|
169
|
+
editableText: true,
|
|
170
|
+
})),
|
|
171
|
+
imagesSkipped,
|
|
172
|
+
});
|
|
173
|
+
if (imagesSkipped > 0) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`Source-faithful PPTX import could not preserve ${imagesSkipped} image(s). No slides were written. Retry with browser-renderable images or use a PDF export for page-faithful preservation.`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const aspectRatio =
|
|
179
|
+
presentation.slides[0]?.widthEmu && presentation.slides[0]?.heightEmu
|
|
180
|
+
? nearestAspectRatio(
|
|
181
|
+
presentation.slides[0].widthEmu,
|
|
182
|
+
presentation.slides[0].heightEmu,
|
|
183
|
+
)
|
|
184
|
+
: undefined;
|
|
185
|
+
await appendDeckSlides(
|
|
186
|
+
deckId,
|
|
187
|
+
title,
|
|
188
|
+
slides,
|
|
189
|
+
"import-file:pptx",
|
|
190
|
+
aspectRatio,
|
|
191
|
+
sourceImport,
|
|
192
|
+
);
|
|
156
193
|
return {
|
|
157
194
|
format: "pptx",
|
|
158
195
|
title,
|
|
@@ -176,6 +213,8 @@ export default defineAction({
|
|
|
176
213
|
imageNames: slide.images.map((img) => img.name),
|
|
177
214
|
notes: slide.notes,
|
|
178
215
|
layoutHint: slide.layoutHint,
|
|
216
|
+
transition: slide.transition,
|
|
217
|
+
splitByParagraph: slide.splitByParagraph,
|
|
179
218
|
})),
|
|
180
219
|
theme: presentation.theme,
|
|
181
220
|
deckId,
|
|
@@ -238,9 +277,15 @@ export default defineAction({
|
|
|
238
277
|
// typography) bake their visuals into vector/image page content with
|
|
239
278
|
// no reliable text/shape structure to reconstruct, so importing into a
|
|
240
279
|
// deck rasterizes each page instead of flattening it to generic bullet
|
|
241
|
-
// text.
|
|
242
|
-
//
|
|
243
|
-
|
|
280
|
+
// text. Do not silently fall back to text reconstruction when the
|
|
281
|
+
// renderer is unavailable: that is how a visually complete source deck
|
|
282
|
+
// turns into a misleading, content-lossy import.
|
|
283
|
+
if (importIntoDeck) {
|
|
284
|
+
if (!canvasFactory) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
"Source-faithful PDF import is unavailable in this runtime because the page renderer is not configured. Retry after connecting file storage or use a PDF export with a supported Slides deployment.",
|
|
287
|
+
);
|
|
288
|
+
}
|
|
244
289
|
if (!deckId) throw new Error("deckId is required to import into deck");
|
|
245
290
|
return importPdfPagesAsFullBleedSlides({
|
|
246
291
|
fileBuffer,
|
|
@@ -251,8 +296,6 @@ export default defineAction({
|
|
|
251
296
|
});
|
|
252
297
|
}
|
|
253
298
|
|
|
254
|
-
const { convertSectionsToSlides } =
|
|
255
|
-
await import("../server/handlers/import/html-converter.js");
|
|
256
299
|
const pdf = new PDFParse({
|
|
257
300
|
data: new Uint8Array(fileBuffer),
|
|
258
301
|
CanvasFactory: canvasFactory,
|
|
@@ -267,29 +310,6 @@ export default defineAction({
|
|
|
267
310
|
);
|
|
268
311
|
}
|
|
269
312
|
|
|
270
|
-
if (importIntoDeck) {
|
|
271
|
-
if (!deckId) throw new Error("deckId is required to import into deck");
|
|
272
|
-
const sections = textPages.map((p) => ({
|
|
273
|
-
heading: `Page ${p.num}`,
|
|
274
|
-
content: p.text,
|
|
275
|
-
}));
|
|
276
|
-
const slideHtmlArray = convertSectionsToSlides(sections);
|
|
277
|
-
const slides = slideHtmlArray.map((content) => ({
|
|
278
|
-
id: newSlideId(),
|
|
279
|
-
content,
|
|
280
|
-
layout: "content",
|
|
281
|
-
notes: "",
|
|
282
|
-
}));
|
|
283
|
-
await appendDeckSlides(deckId, title, slides, "import-file:pdf");
|
|
284
|
-
return {
|
|
285
|
-
format: "pdf",
|
|
286
|
-
title,
|
|
287
|
-
pageCount: pages.length,
|
|
288
|
-
slideCount: slides.length,
|
|
289
|
-
deckId,
|
|
290
|
-
imported: true,
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
313
|
const totalTextLength = textPages.reduce(
|
|
294
314
|
(sum, p) => sum + p.text.length,
|
|
295
315
|
0,
|
|
@@ -339,7 +359,7 @@ async function importPdfPagesAsFullBleedSlides(args: {
|
|
|
339
359
|
canvasFactory: object;
|
|
340
360
|
}) {
|
|
341
361
|
const { fileBuffer, title, deckId, PDFParse, canvasFactory } = args;
|
|
342
|
-
const {
|
|
362
|
+
const { buildFullPageImageSlideHtml } =
|
|
343
363
|
await import("../server/handlers/import/html-converter.js");
|
|
344
364
|
|
|
345
365
|
const pdf = new PDFParse({
|
|
@@ -347,69 +367,75 @@ async function importPdfPagesAsFullBleedSlides(args: {
|
|
|
347
367
|
CanvasFactory: canvasFactory,
|
|
348
368
|
});
|
|
349
369
|
let pages: { num: number; text: string }[];
|
|
350
|
-
let
|
|
370
|
+
let screenshotsByPage: Map<
|
|
351
371
|
number,
|
|
352
372
|
{ data: Uint8Array; width: number; height: number }
|
|
353
373
|
>;
|
|
354
374
|
try {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
375
|
+
let textPages: { num: number; text: string }[] = [];
|
|
376
|
+
try {
|
|
377
|
+
textPages = normalizePdfPages(await pdf.getText());
|
|
378
|
+
} catch (error) {
|
|
379
|
+
console.warn(
|
|
380
|
+
"[import-file] PDF text extraction failed; preserving rendered pages and leaving notes empty:",
|
|
381
|
+
error,
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
// Rasterize the complete page so positioned text, vector shapes, logos,
|
|
385
|
+
// photos, and the source page proportions survive the import together.
|
|
386
|
+
const screenshotResult = await pdf.getScreenshot({
|
|
387
|
+
desiredWidth: 1600,
|
|
361
388
|
imageBuffer: true,
|
|
362
389
|
imageDataUrl: false,
|
|
363
390
|
});
|
|
364
|
-
|
|
365
|
-
for (const page of
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
return best;
|
|
373
|
-
}, undefined);
|
|
374
|
-
if (largest) imagesByPage.set(page.pageNumber, largest);
|
|
391
|
+
screenshotsByPage = new Map();
|
|
392
|
+
for (const page of screenshotResult.pages) {
|
|
393
|
+
screenshotsByPage.set(page.pageNumber, {
|
|
394
|
+
data: page.data,
|
|
395
|
+
width: page.width,
|
|
396
|
+
height: page.height,
|
|
397
|
+
});
|
|
375
398
|
}
|
|
399
|
+
if (screenshotsByPage.size === 0) {
|
|
400
|
+
throw new Error("The PDF renderer returned no pages.");
|
|
401
|
+
}
|
|
402
|
+
pages = screenshotResult.pages.map((page) => ({
|
|
403
|
+
num: page.pageNumber,
|
|
404
|
+
text:
|
|
405
|
+
textPages.find((textPage) => textPage.num === page.pageNumber)?.text ??
|
|
406
|
+
"",
|
|
407
|
+
}));
|
|
376
408
|
} finally {
|
|
377
409
|
await pdf.destroy();
|
|
378
410
|
}
|
|
379
411
|
|
|
412
|
+
if (pages.length === 0) {
|
|
413
|
+
throw new Error("The PDF renderer returned no importable pages.");
|
|
414
|
+
}
|
|
415
|
+
|
|
380
416
|
// Source decks (e.g. Instagram carousel exports) are commonly portrait or
|
|
381
417
|
// square, not the deck editor's 16:9 default — match the canvas to the
|
|
382
|
-
// first
|
|
383
|
-
const
|
|
384
|
-
.map((page) =>
|
|
418
|
+
// first rendered page's own proportions instead of stretching/cropping it.
|
|
419
|
+
const firstScreenshot = pages
|
|
420
|
+
.map((page) => screenshotsByPage.get(page.num))
|
|
385
421
|
.find((image): image is NonNullable<typeof image> => Boolean(image));
|
|
386
|
-
const aspectRatio =
|
|
387
|
-
? nearestAspectRatio(
|
|
422
|
+
const aspectRatio = firstScreenshot
|
|
423
|
+
? nearestAspectRatio(firstScreenshot.width, firstScreenshot.height)
|
|
388
424
|
: undefined;
|
|
389
425
|
|
|
390
426
|
const ownerEmail = getRequestUserEmail();
|
|
391
|
-
const
|
|
427
|
+
const imported = await Promise.all(
|
|
392
428
|
pages.map(async (page) => {
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (!backgroundImage) {
|
|
400
|
-
const [content] = convertSectionsToSlides([
|
|
401
|
-
{ heading: lines[0] ?? `Page ${page.num}`, content: page.text },
|
|
402
|
-
]);
|
|
403
|
-
return {
|
|
404
|
-
id: newSlideId(),
|
|
405
|
-
content: content ?? '<div class="fmd-slide"></div>',
|
|
406
|
-
layout: "content",
|
|
407
|
-
notes: "",
|
|
408
|
-
};
|
|
429
|
+
const screenshot = screenshotsByPage.get(page.num);
|
|
430
|
+
|
|
431
|
+
if (!screenshot) {
|
|
432
|
+
throw new Error(
|
|
433
|
+
`The PDF renderer did not return page ${page.num}; refusing a partial source import.`,
|
|
434
|
+
);
|
|
409
435
|
}
|
|
410
436
|
|
|
411
437
|
const uploadResult = await uploadFile({
|
|
412
|
-
data: Buffer.from(
|
|
438
|
+
data: Buffer.from(screenshot.data),
|
|
413
439
|
filename: `slide-import-${Date.now()}-p${page.num}.png`,
|
|
414
440
|
mimeType: "image/png",
|
|
415
441
|
ownerEmail: ownerEmail ?? undefined,
|
|
@@ -420,29 +446,42 @@ async function importPdfPagesAsFullBleedSlides(args: {
|
|
|
420
446
|
"File storage is not configured. Connect Builder.io (free tier available) or another upload provider before importing PDF slides.",
|
|
421
447
|
);
|
|
422
448
|
}
|
|
423
|
-
|
|
424
|
-
// wrapped title from a heading followed by a body paragraph. Treat a
|
|
425
|
-
// couple of short lines as one wrapped title (join them so the
|
|
426
|
-
// sentence isn't cut off); three or more lines as a heading plus body
|
|
427
|
-
// text, rendered with distinct sizes so they don't collapse into one
|
|
428
|
-
// flat paragraph.
|
|
429
|
-
const heading =
|
|
430
|
-
lines.length > 2 ? lines[0] : lines.join(" ") || undefined;
|
|
431
|
-
const subtitle = lines.length > 2 ? lines.slice(1).join(" ") : undefined;
|
|
449
|
+
const id = newSlideId();
|
|
432
450
|
return {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
451
|
+
slide: {
|
|
452
|
+
id,
|
|
453
|
+
content: buildFullPageImageSlideHtml(
|
|
454
|
+
uploadResult.url,
|
|
455
|
+
screenshot.width,
|
|
456
|
+
screenshot.height,
|
|
457
|
+
),
|
|
458
|
+
layout: "full-image",
|
|
459
|
+
notes: page.text,
|
|
460
|
+
},
|
|
461
|
+
snapshot: {
|
|
462
|
+
id,
|
|
463
|
+
text: page.text,
|
|
464
|
+
notes: page.text,
|
|
465
|
+
imageUrls: [uploadResult.url],
|
|
466
|
+
editableText: false,
|
|
467
|
+
} satisfies SourceImportSlideSnapshot,
|
|
441
468
|
};
|
|
442
469
|
}),
|
|
443
470
|
);
|
|
471
|
+
const slides = imported.map((entry) => entry.slide);
|
|
472
|
+
const sourceImport = buildSourceImportMetadata({
|
|
473
|
+
format: "pdf",
|
|
474
|
+
slides: imported.map((entry) => entry.snapshot),
|
|
475
|
+
});
|
|
444
476
|
|
|
445
|
-
await appendDeckSlides(
|
|
477
|
+
await appendDeckSlides(
|
|
478
|
+
deckId,
|
|
479
|
+
title,
|
|
480
|
+
slides,
|
|
481
|
+
"import-file:pdf",
|
|
482
|
+
aspectRatio,
|
|
483
|
+
sourceImport,
|
|
484
|
+
);
|
|
446
485
|
|
|
447
486
|
return {
|
|
448
487
|
format: "pdf",
|
|
@@ -459,65 +498,44 @@ function newSlideId(): string {
|
|
|
459
498
|
return `slide-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
460
499
|
}
|
|
461
500
|
|
|
462
|
-
// EMF/WMF (Windows metafiles) and TIFF are valid PPTX embed formats but
|
|
463
|
-
// browsers can't render them in an <img> tag — uploading and linking one
|
|
464
|
-
// would just produce a broken image icon.
|
|
465
|
-
const PPTX_BROWSER_RENDERABLE_IMAGE_MIME_TYPES = new Set([
|
|
466
|
-
"image/png",
|
|
467
|
-
"image/jpeg",
|
|
468
|
-
"image/gif",
|
|
469
|
-
"image/webp",
|
|
470
|
-
"image/svg+xml",
|
|
471
|
-
"image/bmp",
|
|
472
|
-
]);
|
|
473
|
-
|
|
474
501
|
async function buildPptxSlide(
|
|
475
502
|
slide: import("../server/handlers/import/pptx-parser.js").ParsedSlide,
|
|
476
503
|
slideIndex: number,
|
|
477
504
|
ownerEmail: string,
|
|
478
505
|
themeFont: string | undefined,
|
|
479
506
|
): Promise<{
|
|
480
|
-
slide: {
|
|
507
|
+
slide: {
|
|
508
|
+
id: string;
|
|
509
|
+
content: string;
|
|
510
|
+
layout: string;
|
|
511
|
+
notes?: string;
|
|
512
|
+
transition?: "instant" | "none" | "fade" | "slide" | "zoom";
|
|
513
|
+
splitByParagraph?: boolean;
|
|
514
|
+
};
|
|
481
515
|
imageSkippedCount: number;
|
|
516
|
+
sourceText: string;
|
|
517
|
+
imageUrls: string[];
|
|
482
518
|
}> {
|
|
483
519
|
const { convertToSlideHtml } =
|
|
484
520
|
await import("../server/handlers/import/html-converter.js");
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const
|
|
491
|
-
? await uploadFile({
|
|
492
|
-
data: Buffer.from(uploadable.data),
|
|
493
|
-
filename:
|
|
494
|
-
"pptx-import-" +
|
|
495
|
-
Date.now() +
|
|
496
|
-
"-s" +
|
|
497
|
-
slideIndex +
|
|
498
|
-
"-" +
|
|
499
|
-
uploadable.name,
|
|
500
|
-
mimeType: uploadable.mimeType,
|
|
501
|
-
ownerEmail,
|
|
502
|
-
recordAsset: false,
|
|
503
|
-
})
|
|
504
|
-
.then((result) => result?.url)
|
|
505
|
-
// A single slide's upload failing (network/API/rate-limit)
|
|
506
|
-
// shouldn't abort the whole deck replacement — fall back to a
|
|
507
|
-
// placeholder like an unsupported format would.
|
|
508
|
-
.catch(() => undefined)
|
|
509
|
-
: undefined;
|
|
521
|
+
const uploadedImages = await uploadPptxSlideImages({
|
|
522
|
+
slide,
|
|
523
|
+
slideIndex,
|
|
524
|
+
ownerEmail,
|
|
525
|
+
});
|
|
526
|
+
const id = newSlideId();
|
|
510
527
|
return {
|
|
511
528
|
slide: {
|
|
512
|
-
id
|
|
513
|
-
content: convertToSlideHtml(slide,
|
|
529
|
+
id,
|
|
530
|
+
content: convertToSlideHtml(slide, uploadedImages.urls, themeFont),
|
|
514
531
|
layout: slide.layoutHint ?? "content",
|
|
515
532
|
notes: slide.notes,
|
|
533
|
+
...(slide.transition ? { transition: slide.transition } : {}),
|
|
534
|
+
...(slide.splitByParagraph ? { splitByParagraph: true } : {}),
|
|
516
535
|
},
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
imageSkippedCount: Math.max(0, slide.images.length - (imageUrl ? 1 : 0)),
|
|
536
|
+
imageSkippedCount: uploadedImages.imageSkippedCount,
|
|
537
|
+
sourceText: slide.texts.map((text) => text.content).join("\n"),
|
|
538
|
+
imageUrls: Object.values(uploadedImages.urls),
|
|
521
539
|
};
|
|
522
540
|
}
|
|
523
541
|
|
|
@@ -604,9 +622,12 @@ async function appendDeckSlides(
|
|
|
604
622
|
content: string;
|
|
605
623
|
layout: string;
|
|
606
624
|
notes?: string;
|
|
625
|
+
transition?: "instant" | "none" | "fade" | "slide" | "zoom";
|
|
626
|
+
splitByParagraph?: boolean;
|
|
607
627
|
}>,
|
|
608
628
|
source: string,
|
|
609
629
|
aspectRatio?: AspectRatio,
|
|
630
|
+
sourceImport?: ReturnType<typeof buildSourceImportMetadata>,
|
|
610
631
|
) {
|
|
611
632
|
await assertAccess("deck", deckId, "editor");
|
|
612
633
|
|
|
@@ -640,11 +661,18 @@ async function appendDeckSlides(
|
|
|
640
661
|
// every slide already on it.
|
|
641
662
|
const hadExistingSlides = previousSlides.length > 0;
|
|
642
663
|
const nextTitle = hadExistingSlides ? (existing[0].title ?? title) : title;
|
|
664
|
+
const nextSourceImport = sourceImport
|
|
665
|
+
? mergeSourceImportMetadata(
|
|
666
|
+
sourceImportForDeck(previousData.sourceImport),
|
|
667
|
+
sourceImport,
|
|
668
|
+
)
|
|
669
|
+
: sourceImportForDeck(previousData.sourceImport);
|
|
643
670
|
const data = {
|
|
644
671
|
...previousData,
|
|
645
672
|
title: nextTitle,
|
|
646
673
|
slides: [...previousSlides, ...slides],
|
|
647
674
|
...(!hadExistingSlides && aspectRatio ? { aspectRatio } : {}),
|
|
675
|
+
...(nextSourceImport ? { sourceImport: nextSourceImport } : {}),
|
|
648
676
|
updatedAt: writeNow,
|
|
649
677
|
};
|
|
650
678
|
|
|
@@ -665,12 +693,20 @@ async function appendDeckSlides(
|
|
|
665
693
|
}
|
|
666
694
|
|
|
667
695
|
function safeParseDeckData(raw: string): Record<string, unknown> {
|
|
696
|
+
let parsed: unknown;
|
|
668
697
|
try {
|
|
669
|
-
|
|
670
|
-
return parsed && typeof parsed === "object" ? parsed : {};
|
|
698
|
+
parsed = JSON.parse(raw);
|
|
671
699
|
} catch {
|
|
672
|
-
|
|
700
|
+
throw new Error(
|
|
701
|
+
"The target deck contains invalid JSON; refusing to overwrite it.",
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
705
|
+
throw new Error(
|
|
706
|
+
"The target deck data is invalid; refusing to overwrite it.",
|
|
707
|
+
);
|
|
673
708
|
}
|
|
709
|
+
return parsed as Record<string, unknown>;
|
|
674
710
|
}
|
|
675
711
|
|
|
676
712
|
function stripTags(html: string): string {
|