@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
|
@@ -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,24 @@ 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-pdf="true"')) {
|
|
186
|
+
return parseImportedPdfSlideHtml(html, dims);
|
|
187
|
+
}
|
|
188
|
+
if (html.includes('data-imported-pptx="true"')) {
|
|
189
|
+
return parseImportedSlideHtml(html, dims);
|
|
190
|
+
}
|
|
191
|
+
|
|
144
192
|
const texts: TextElement[] = [];
|
|
145
193
|
const images: ImageElement[] = [];
|
|
194
|
+
const shapes: ShapeElement[] = [];
|
|
146
195
|
let bgColor = "000000";
|
|
147
196
|
|
|
148
|
-
const dims = getAspectRatioDims(aspectRatio);
|
|
149
197
|
const slideW = dims.pptxInches.w;
|
|
150
198
|
const slideH = dims.pptxInches.h;
|
|
151
199
|
|
|
@@ -321,7 +369,306 @@ export function parseSlideHtml(
|
|
|
321
369
|
}
|
|
322
370
|
}
|
|
323
371
|
|
|
324
|
-
return { texts, images, bgColor };
|
|
372
|
+
return { texts, images, shapes, bgColor };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
type SlideDims = ReturnType<typeof getAspectRatioDims>;
|
|
376
|
+
|
|
377
|
+
function parseImportedPdfSlideHtml(
|
|
378
|
+
html: string,
|
|
379
|
+
dims: SlideDims,
|
|
380
|
+
): {
|
|
381
|
+
texts: TextElement[];
|
|
382
|
+
images: ImageElement[];
|
|
383
|
+
shapes: ShapeElement[];
|
|
384
|
+
grid?: GridElement;
|
|
385
|
+
bgColor: string;
|
|
386
|
+
} {
|
|
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 - imported PDF fallback
|
|
393
|
+
: "#000000", // guard:allow-raw-color - imported PDF fallback
|
|
394
|
+
);
|
|
395
|
+
const src = html.match(/<img\b[^>]*\bsrc=["']([^"']+)["'][^>]*>/i)?.[1];
|
|
396
|
+
const outerAttrs = html.match(/<div\b([^>]*)>/i)?.[1] ?? "";
|
|
397
|
+
const sourceWidth = Number.parseFloat(
|
|
398
|
+
getAttribute(outerAttrs, "data-source-width") ?? "",
|
|
399
|
+
);
|
|
400
|
+
const sourceHeight = Number.parseFloat(
|
|
401
|
+
getAttribute(outerAttrs, "data-source-height") ?? "",
|
|
402
|
+
);
|
|
403
|
+
let x = 0;
|
|
404
|
+
let y = 0;
|
|
405
|
+
let w = dims.pptxInches.w;
|
|
406
|
+
let h = dims.pptxInches.h;
|
|
407
|
+
if (
|
|
408
|
+
Number.isFinite(sourceWidth) &&
|
|
409
|
+
Number.isFinite(sourceHeight) &&
|
|
410
|
+
sourceWidth > 0 &&
|
|
411
|
+
sourceHeight > 0
|
|
412
|
+
) {
|
|
413
|
+
const sourceAspect = sourceWidth / sourceHeight;
|
|
414
|
+
const deckAspect = dims.pptxInches.w / dims.pptxInches.h;
|
|
415
|
+
if (sourceAspect > deckAspect) {
|
|
416
|
+
h = w / sourceAspect;
|
|
417
|
+
y = (dims.pptxInches.h - h) / 2;
|
|
418
|
+
} else {
|
|
419
|
+
w = h * sourceAspect;
|
|
420
|
+
x = (dims.pptxInches.w - w) / 2;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return {
|
|
424
|
+
texts: [],
|
|
425
|
+
images: src
|
|
426
|
+
? [
|
|
427
|
+
{
|
|
428
|
+
src: decodeHtmlText(src),
|
|
429
|
+
x,
|
|
430
|
+
y,
|
|
431
|
+
w,
|
|
432
|
+
h,
|
|
433
|
+
order: 0,
|
|
434
|
+
},
|
|
435
|
+
]
|
|
436
|
+
: [],
|
|
437
|
+
shapes: [],
|
|
438
|
+
bgColor,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function parseImportedSlideHtml(
|
|
443
|
+
html: string,
|
|
444
|
+
dims: SlideDims,
|
|
445
|
+
): {
|
|
446
|
+
texts: TextElement[];
|
|
447
|
+
images: ImageElement[];
|
|
448
|
+
shapes: ShapeElement[];
|
|
449
|
+
grid?: GridElement;
|
|
450
|
+
bgColor: string;
|
|
451
|
+
} {
|
|
452
|
+
const texts: TextElement[] = [];
|
|
453
|
+
const images: ImageElement[] = [];
|
|
454
|
+
const shapes: ShapeElement[] = [];
|
|
455
|
+
const outerStyle = html.match(
|
|
456
|
+
/class=["'][^"']*\bfmd-slide\b[^"']*["'][^>]*style=["']([^"']*)["']/i,
|
|
457
|
+
)?.[1];
|
|
458
|
+
const bgColor = colorToHex(
|
|
459
|
+
outerStyle
|
|
460
|
+
? (getStyle(outerStyle, "background(?:-color)?") ?? "#000000") // guard:allow-raw-color - PPTX background fallback
|
|
461
|
+
: "#000000", // guard:allow-raw-color - PPTX background fallback
|
|
462
|
+
);
|
|
463
|
+
const grid = outerStyle ? parseImportedGrid(outerStyle) : undefined;
|
|
464
|
+
const elementRegex =
|
|
465
|
+
/<div\b([^>]*\bdata-pptx-element-kind=["'](text|image|shape)["'][^>]*)>([\s\S]*?)<\/div>/gi;
|
|
466
|
+
let match: RegExpExecArray | null;
|
|
467
|
+
while ((match = elementRegex.exec(html)) !== null) {
|
|
468
|
+
const attrs = match[1];
|
|
469
|
+
const kind = match[2].toLowerCase();
|
|
470
|
+
const innerHtml = match[3];
|
|
471
|
+
const style = getAttribute(attrs, "style") ?? "";
|
|
472
|
+
const geometry = importedGeometry(style, dims);
|
|
473
|
+
if (!geometry) continue;
|
|
474
|
+
|
|
475
|
+
if (kind === "image") {
|
|
476
|
+
const imageAttrs = innerHtml.match(/<img\b([^>]*)>/i)?.[1] ?? "";
|
|
477
|
+
const src = getAttribute(imageAttrs, "src");
|
|
478
|
+
if (src) {
|
|
479
|
+
images.push({ src, ...geometry, order: match.index });
|
|
480
|
+
}
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (kind === "shape") {
|
|
485
|
+
const fill = getStyle(style, "background(?:-color)?");
|
|
486
|
+
const border = getStyle(style, "border");
|
|
487
|
+
const borderMatch = border?.match(/([\d.]+)px\s+solid\s+(.+)/i);
|
|
488
|
+
shapes.push({
|
|
489
|
+
...geometry,
|
|
490
|
+
...(fill && !fill.includes("gradient")
|
|
491
|
+
? { fill: colorToHex(fill) }
|
|
492
|
+
: {}),
|
|
493
|
+
...(borderMatch
|
|
494
|
+
? {
|
|
495
|
+
lineColor: colorToHex(borderMatch[2]),
|
|
496
|
+
lineWidth: Number(borderMatch[1]),
|
|
497
|
+
}
|
|
498
|
+
: {}),
|
|
499
|
+
rounded: style.includes("border-radius"),
|
|
500
|
+
order: match.index,
|
|
501
|
+
});
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const runs = importedTextRuns(innerHtml);
|
|
506
|
+
const firstRun = runs.find((run) => run.text.trim()) ?? runs[0];
|
|
507
|
+
const firstParagraph = innerHtml.match(
|
|
508
|
+
/<p\b[^>]*style=["']([^"']*)["']/i,
|
|
509
|
+
)?.[1];
|
|
510
|
+
const lineHeight = firstParagraph
|
|
511
|
+
? getStyle(firstParagraph, "line-height")
|
|
512
|
+
: null;
|
|
513
|
+
const fontSize = firstRun?.options.fontSize ?? 18;
|
|
514
|
+
const alignValue = getStyle(style, "text-align");
|
|
515
|
+
texts.push({
|
|
516
|
+
text: runs.map((run) => run.text).join(""),
|
|
517
|
+
fontSize,
|
|
518
|
+
fontFace: firstRun?.options.fontFace ?? "Poppins",
|
|
519
|
+
color: firstRun?.options.color ?? "FFFFFF",
|
|
520
|
+
bold: firstRun?.options.bold ?? false,
|
|
521
|
+
align:
|
|
522
|
+
alignValue === "center" || alignValue === "right" ? alignValue : "left",
|
|
523
|
+
lineSpacing: lineHeight ? Number(lineHeight) * fontSize : undefined,
|
|
524
|
+
x: geometry.x,
|
|
525
|
+
y: geometry.y,
|
|
526
|
+
w: geometry.w,
|
|
527
|
+
h: geometry.h,
|
|
528
|
+
runs,
|
|
529
|
+
order: match.index,
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return { texts, images, shapes, grid, bgColor };
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function parseImportedGrid(style: string): GridElement | undefined {
|
|
537
|
+
const backgroundImage = getStyle(style, "background-image");
|
|
538
|
+
const size = getStyle(style, "background-size")
|
|
539
|
+
?.split(/\s+/)
|
|
540
|
+
.map((value) => Number.parseFloat(value));
|
|
541
|
+
const position = getStyle(style, "background-position")
|
|
542
|
+
?.split(/\s+/)
|
|
543
|
+
.map((value) => Number.parseFloat(value));
|
|
544
|
+
const color = backgroundImage?.match(/#[0-9a-f]{6}|rgb\([^)]*\)/i)?.[0];
|
|
545
|
+
const lineWidth = backgroundImage?.match(/\s0\s+([\d.]+)px/i)?.[1];
|
|
546
|
+
if (
|
|
547
|
+
!color ||
|
|
548
|
+
!size ||
|
|
549
|
+
size.length < 2 ||
|
|
550
|
+
!Number.isFinite(size[0]) ||
|
|
551
|
+
!Number.isFinite(size[1]) ||
|
|
552
|
+
size[0] <= 0 ||
|
|
553
|
+
size[1] <= 0 ||
|
|
554
|
+
!position ||
|
|
555
|
+
position.length < 2 ||
|
|
556
|
+
!Number.isFinite(position[0]) ||
|
|
557
|
+
!Number.isFinite(position[1]) ||
|
|
558
|
+
!lineWidth
|
|
559
|
+
) {
|
|
560
|
+
return undefined;
|
|
561
|
+
}
|
|
562
|
+
return {
|
|
563
|
+
color: colorToHex(color),
|
|
564
|
+
stepX: size[0],
|
|
565
|
+
stepY: size[1],
|
|
566
|
+
offsetX: position[0],
|
|
567
|
+
offsetY: position[1],
|
|
568
|
+
lineWidth: Number.parseFloat(lineWidth),
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function importedGeometry(
|
|
573
|
+
style: string,
|
|
574
|
+
dims: SlideDims,
|
|
575
|
+
): { x: number; y: number; w: number; h: number } | null {
|
|
576
|
+
const left = cssPx(style, "left");
|
|
577
|
+
const top = cssPx(style, "top");
|
|
578
|
+
const width = cssPx(style, "width");
|
|
579
|
+
const height = cssPx(style, "height");
|
|
580
|
+
if (left == null || top == null || width == null || height == null)
|
|
581
|
+
return null;
|
|
582
|
+
return {
|
|
583
|
+
x: pxToIn(left, dims),
|
|
584
|
+
y: pxToInY(top, dims),
|
|
585
|
+
w: pxToIn(width, dims),
|
|
586
|
+
h: pxToInY(height, dims),
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function pxToInY(px: number, dims: SlideDims): number {
|
|
591
|
+
return (px / dims.height) * dims.pptxInches.h;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function importedTextRuns(html: string): TextRunElement[] {
|
|
595
|
+
const paragraphs = [...html.matchAll(/<p\b[^>]*>([\s\S]*?)<\/p>/gi)].map(
|
|
596
|
+
(match) => match[1],
|
|
597
|
+
);
|
|
598
|
+
const blocks = paragraphs.length > 0 ? paragraphs : [html];
|
|
599
|
+
const runs: TextRunElement[] = [];
|
|
600
|
+
blocks.forEach((block, paragraphIndex) => {
|
|
601
|
+
if (paragraphIndex > 0) runs.push({ text: "\n", options: {} });
|
|
602
|
+
const spans = [...block.matchAll(/<span\b([^>]*)>([\s\S]*?)<\/span>/gi)];
|
|
603
|
+
if (spans.length === 0) {
|
|
604
|
+
const text = decodeHtmlText(stripTags(block));
|
|
605
|
+
if (text) runs.push({ text, options: {} });
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
for (const span of spans) {
|
|
609
|
+
const attrs = span[1];
|
|
610
|
+
const style = getAttribute(attrs, "style") ?? "";
|
|
611
|
+
const text = decodeHtmlText(stripTags(span[2]));
|
|
612
|
+
if (!text) continue;
|
|
613
|
+
runs.push({ text, options: importedRunOptions(style) });
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
return runs;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function importedRunOptions(style: string): TextRunElement["options"] {
|
|
620
|
+
const fontSizePx = cssPx(style, "font-size");
|
|
621
|
+
const fontFamily = getStyle(style, "font-family")
|
|
622
|
+
?.replace(/["']/g, "")
|
|
623
|
+
.split(",")[0]
|
|
624
|
+
?.trim();
|
|
625
|
+
const fontWeight = getStyle(style, "font-weight");
|
|
626
|
+
return {
|
|
627
|
+
...(fontSizePx != null ? { fontSize: pxToPt(fontSizePx) } : {}),
|
|
628
|
+
...(fontFamily ? { fontFace: fontFamily } : {}),
|
|
629
|
+
...(getStyle(style, "color")
|
|
630
|
+
? { color: colorToHex(getStyle(style, "color") ?? "#FFFFFF") } // guard:allow-raw-color - PPTX text fallback
|
|
631
|
+
: {}),
|
|
632
|
+
...(fontWeight
|
|
633
|
+
? {
|
|
634
|
+
bold: Number.parseInt(fontWeight, 10) >= 700 || fontWeight === "bold",
|
|
635
|
+
}
|
|
636
|
+
: {}),
|
|
637
|
+
...(getStyle(style, "font-style") === "italic" ? { italic: true } : {}),
|
|
638
|
+
...(getStyle(style, "text-decoration")?.includes("underline")
|
|
639
|
+
? { underline: { style: "sng" as const } }
|
|
640
|
+
: {}),
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function cssPx(style: string, property: string): number | null {
|
|
645
|
+
const value = getStyle(style, property);
|
|
646
|
+
if (!value) return null;
|
|
647
|
+
const parsed = Number.parseFloat(value);
|
|
648
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function getAttribute(attrs: string, name: string): string | null {
|
|
652
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
653
|
+
const match = attrs.match(
|
|
654
|
+
new RegExp(`\\b${escapedName}\\s*=\\s*(["'])(.*?)\\1`, "i"),
|
|
655
|
+
);
|
|
656
|
+
return match?.[2] ?? null;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function stripTags(value: string): string {
|
|
660
|
+
return value.replace(/<br\s*\/?\s*>/gi, "\n").replace(/<[^>]+>/g, "");
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function decodeHtmlText(value: string): string {
|
|
664
|
+
return value
|
|
665
|
+
.replace(/ /gi, " ")
|
|
666
|
+
.replace(/&/gi, "&")
|
|
667
|
+
.replace(/</gi, "<")
|
|
668
|
+
.replace(/>/gi, ">")
|
|
669
|
+
.replace(/"/gi, '"')
|
|
670
|
+
.replace(/'|'/gi, "'")
|
|
671
|
+
.replace(/●/gi, "●");
|
|
325
672
|
}
|
|
326
673
|
|
|
327
674
|
/**
|
|
@@ -334,8 +681,23 @@ export function parseSlideHtml(
|
|
|
334
681
|
* image so a 200 OK from an internal HTML / JSON endpoint can't smuggle bytes
|
|
335
682
|
* into the .pptx.
|
|
336
683
|
*/
|
|
337
|
-
export async function fetchImageAsBase64(
|
|
684
|
+
export async function fetchImageAsBase64(
|
|
685
|
+
url: string,
|
|
686
|
+
ownerEmail?: string,
|
|
687
|
+
): Promise<string | null> {
|
|
338
688
|
try {
|
|
689
|
+
const parsedUrl = new URL(url, "http://slides.local");
|
|
690
|
+
if (parsedUrl.pathname.startsWith("/api/import-assets/") && ownerEmail) {
|
|
691
|
+
const token = parsedUrl.pathname.slice("/api/import-assets/".length);
|
|
692
|
+
const localAsset = await readLocalImportedAsset({
|
|
693
|
+
token,
|
|
694
|
+
email: ownerEmail,
|
|
695
|
+
});
|
|
696
|
+
if (localAsset) {
|
|
697
|
+
return `data:${localAsset.mimeType};base64,${Buffer.from(localAsset.data).toString("base64")}`;
|
|
698
|
+
}
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
339
701
|
const response = await ssrfSafeFetch(
|
|
340
702
|
url,
|
|
341
703
|
{ signal: AbortSignal.timeout(10_000) },
|
|
@@ -356,7 +718,7 @@ export async function fetchImageAsBase64(url: string): Promise<string | null> {
|
|
|
356
718
|
|
|
357
719
|
export default defineAction({
|
|
358
720
|
description:
|
|
359
|
-
"Export a
|
|
721
|
+
"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
722
|
schema: z.object({
|
|
361
723
|
deckId: z.string().describe("Deck ID to export"),
|
|
362
724
|
includeNotes: z
|
|
@@ -409,7 +771,7 @@ export default defineAction({
|
|
|
409
771
|
slide && typeof slide === "object" && typeof slide.content === "string"
|
|
410
772
|
? slide.content
|
|
411
773
|
: "";
|
|
412
|
-
const { texts, images, bgColor } = parseSlideHtml(
|
|
774
|
+
const { texts, images, shapes, grid, bgColor } = parseSlideHtml(
|
|
413
775
|
slideContent,
|
|
414
776
|
aspectRatio,
|
|
415
777
|
slideIndex + 1,
|
|
@@ -417,39 +779,111 @@ export default defineAction({
|
|
|
417
779
|
|
|
418
780
|
pptxSlide.background = { color: bgColor };
|
|
419
781
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
782
|
+
if (grid) {
|
|
783
|
+
const gridWidth = pxToIn(grid.stepX, dims);
|
|
784
|
+
const gridHeight = pxToInY(grid.stepY, dims);
|
|
785
|
+
const gridX = pxToIn(grid.offsetX, dims);
|
|
786
|
+
const gridY = pxToInY(grid.offsetY, dims);
|
|
787
|
+
const lineWidth = Math.max(0.5, grid.lineWidth * 0.75);
|
|
788
|
+
|
|
789
|
+
for (let x = gridX; x < dims.pptxInches.w; x += gridWidth) {
|
|
790
|
+
pptxSlide.addShape(pptx.ShapeType.line, {
|
|
791
|
+
x,
|
|
792
|
+
y: 0,
|
|
793
|
+
w: 0,
|
|
794
|
+
h: dims.pptxInches.h,
|
|
795
|
+
line: { color: grid.color, width: lineWidth },
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
for (let y = gridY; y < dims.pptxInches.h; y += gridHeight) {
|
|
799
|
+
pptxSlide.addShape(pptx.ShapeType.line, {
|
|
800
|
+
x: 0,
|
|
801
|
+
y,
|
|
802
|
+
w: dims.pptxInches.w,
|
|
803
|
+
h: 0,
|
|
804
|
+
line: { color: grid.color, width: lineWidth },
|
|
805
|
+
});
|
|
806
|
+
}
|
|
439
807
|
}
|
|
440
808
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
809
|
+
const orderedTexts = [...texts].sort(
|
|
810
|
+
(a, b) => (a.order ?? 0) - (b.order ?? 0),
|
|
811
|
+
);
|
|
812
|
+
const orderedImages = [...images].sort(
|
|
813
|
+
(a, b) => (a.order ?? 0) - (b.order ?? 0),
|
|
814
|
+
);
|
|
815
|
+
const orderedShapes = [...shapes].sort(
|
|
816
|
+
(a, b) => (a.order ?? 0) - (b.order ?? 0),
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
// Imported elements are parsed separately because PptxGenJS needs real
|
|
820
|
+
// slide objects. Keep their source order so overlapping objects retain
|
|
821
|
+
// the same paint order as the editor preview.
|
|
822
|
+
const orderedObjects = [
|
|
823
|
+
...orderedTexts.map((value) => ({ kind: "text" as const, value })),
|
|
824
|
+
...orderedImages.map((value) => ({ kind: "image" as const, value })),
|
|
825
|
+
...orderedShapes.map((value) => ({ kind: "shape" as const, value })),
|
|
826
|
+
].sort((a, b) => (a.value.order ?? 0) - (b.value.order ?? 0));
|
|
827
|
+
|
|
828
|
+
for (const object of orderedObjects) {
|
|
829
|
+
if (object.kind === "text") {
|
|
830
|
+
const t = object.value;
|
|
831
|
+
const options = {
|
|
832
|
+
x: t.x,
|
|
833
|
+
y: t.y,
|
|
834
|
+
w: t.w,
|
|
835
|
+
h: t.h,
|
|
836
|
+
fontSize: t.fontSize,
|
|
837
|
+
fontFace: t.fontFace,
|
|
838
|
+
color: t.color,
|
|
839
|
+
bold: t.bold,
|
|
840
|
+
align: t.align || "left",
|
|
841
|
+
valign: "top" as const,
|
|
842
|
+
wrap: true,
|
|
843
|
+
...(t.letterSpacing != null
|
|
844
|
+
? { charSpacing: t.letterSpacing }
|
|
845
|
+
: {}),
|
|
846
|
+
...(t.lineSpacing != null
|
|
847
|
+
? { lineSpacingMultiple: t.lineSpacing / t.fontSize }
|
|
848
|
+
: {}),
|
|
849
|
+
};
|
|
850
|
+
if (t.runs?.length) {
|
|
851
|
+
pptxSlide.addText(t.runs, options);
|
|
852
|
+
} else {
|
|
853
|
+
pptxSlide.addText(t.text, options);
|
|
854
|
+
}
|
|
855
|
+
} else if (object.kind === "image") {
|
|
856
|
+
const img = object.value;
|
|
857
|
+
const dataUri = await fetchImageAsBase64(img.src, userEmail);
|
|
858
|
+
if (dataUri) {
|
|
859
|
+
pptxSlide.addImage({
|
|
860
|
+
data: dataUri,
|
|
861
|
+
x: img.x,
|
|
862
|
+
y: img.y,
|
|
863
|
+
w: img.w,
|
|
864
|
+
h: img.h,
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
const shape = object.value;
|
|
869
|
+
pptxSlide.addShape(
|
|
870
|
+
shape.rounded ? pptx.ShapeType.roundRect : pptx.ShapeType.rect,
|
|
871
|
+
{
|
|
872
|
+
x: shape.x,
|
|
873
|
+
y: shape.y,
|
|
874
|
+
w: shape.w,
|
|
875
|
+
h: shape.h,
|
|
876
|
+
...(shape.fill ? { fill: { color: shape.fill } } : {}),
|
|
877
|
+
...(shape.lineColor
|
|
878
|
+
? {
|
|
879
|
+
line: {
|
|
880
|
+
color: shape.lineColor,
|
|
881
|
+
width: shape.lineWidth ?? 1,
|
|
882
|
+
},
|
|
883
|
+
}
|
|
884
|
+
: {}),
|
|
885
|
+
},
|
|
886
|
+
);
|
|
453
887
|
}
|
|
454
888
|
}
|
|
455
889
|
|
|
@@ -68,6 +68,18 @@ export default defineAction({
|
|
|
68
68
|
title: row.title || data?.title,
|
|
69
69
|
visibility: row.visibility,
|
|
70
70
|
designSystemId: row.designSystemId ?? null,
|
|
71
|
+
sourceImport: data?.sourceImport
|
|
72
|
+
? {
|
|
73
|
+
mode: data.sourceImport.mode,
|
|
74
|
+
format: data.sourceImport.format,
|
|
75
|
+
fidelity: data.sourceImport.fidelity,
|
|
76
|
+
slideCount: data.sourceImport.slideCount,
|
|
77
|
+
slideIds: data.sourceImport.slideIds,
|
|
78
|
+
...(typeof data.sourceImport.imagesSkipped === "number"
|
|
79
|
+
? { imagesSkipped: data.sourceImport.imagesSkipped }
|
|
80
|
+
: {}),
|
|
81
|
+
}
|
|
82
|
+
: null,
|
|
71
83
|
slideCount: slides.length,
|
|
72
84
|
slideNumbering:
|
|
73
85
|
'User-visible slide numbers are 1-based and match the UI. "Slide 1" means slideNumber 1 / zeroBasedIndex 0. Use slideId for edits.',
|