@agent-native/core 0.92.12 → 0.93.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +39 -0
- package/corpus/core/docs/content/automation-connectors.mdx +80 -0
- package/corpus/core/docs/content/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/ar-SA/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/ar-SA/messaging.mdx +84 -15
- package/corpus/core/docs/content/locales/ar-SA/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/de-DE/extensions.mdx +10 -0
- package/corpus/core/docs/content/locales/de-DE/messaging.mdx +92 -15
- package/corpus/core/docs/content/locales/de-DE/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/es-ES/extensions.mdx +10 -0
- package/corpus/core/docs/content/locales/es-ES/messaging.mdx +91 -15
- package/corpus/core/docs/content/locales/es-ES/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/fr-FR/extensions.mdx +10 -0
- package/corpus/core/docs/content/locales/fr-FR/messaging.mdx +91 -15
- package/corpus/core/docs/content/locales/fr-FR/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/hi-IN/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/hi-IN/messaging.mdx +81 -15
- package/corpus/core/docs/content/locales/hi-IN/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/ja-JP/extensions.mdx +9 -0
- package/corpus/core/docs/content/locales/ja-JP/messaging.mdx +81 -15
- package/corpus/core/docs/content/locales/ja-JP/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/ko-KR/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/ko-KR/messaging.mdx +80 -15
- package/corpus/core/docs/content/locales/ko-KR/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/pt-BR/extensions.mdx +9 -0
- package/corpus/core/docs/content/locales/pt-BR/messaging.mdx +88 -15
- package/corpus/core/docs/content/locales/pt-BR/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-CN/extensions.mdx +6 -0
- package/corpus/core/docs/content/locales/zh-CN/messaging.mdx +78 -15
- package/corpus/core/docs/content/locales/zh-CN/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-TW/extensions.mdx +6 -0
- package/corpus/core/docs/content/locales/zh-TW/messaging.mdx +78 -15
- package/corpus/core/docs/content/locales/zh-TW/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -0
- package/corpus/core/docs/content/messaging.mdx +227 -45
- package/corpus/core/docs/content/template-clips.mdx +3 -0
- package/corpus/core/docs/content/template-design.mdx +4 -0
- package/corpus/core/package.json +5 -1
- package/corpus/core/src/a2a/artifact-response.ts +131 -2
- package/corpus/core/src/a2a/client.ts +10 -0
- package/corpus/core/src/a2a/handlers.ts +40 -76
- package/corpus/core/src/a2a/types.ts +2 -0
- package/corpus/core/src/agent/durable-background.ts +24 -0
- package/corpus/core/src/agent/production-agent.ts +15 -3
- package/corpus/core/src/agent/run-manager.ts +130 -10
- package/corpus/core/src/agent/run-store.ts +225 -15
- package/corpus/core/src/agent/types.ts +23 -0
- package/corpus/core/src/audit/record.ts +31 -0
- package/corpus/core/src/audit/store.ts +69 -3
- package/corpus/core/src/audit/types.ts +13 -0
- package/corpus/core/src/automation/index.ts +802 -0
- package/corpus/core/src/cli/create.ts +12 -5
- package/corpus/core/src/cli/design-connect.ts +596 -36
- package/corpus/core/src/client/AgentPanel.tsx +51 -6
- package/corpus/core/src/client/AssistantChat.tsx +274 -147
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +3 -0
- package/corpus/core/src/client/RunStuckBanner.tsx +69 -20
- package/corpus/core/src/client/agent-chat-adapter.ts +54 -5
- package/corpus/core/src/client/automation.ts +22 -0
- package/corpus/core/src/client/chat/run-recovery.tsx +67 -50
- package/corpus/core/src/client/composer/TiptapComposer.tsx +8 -0
- package/corpus/core/src/client/index.ts +30 -0
- package/corpus/core/src/client/integrations/api.ts +295 -0
- package/corpus/core/src/client/integrations/index.ts +26 -0
- package/corpus/core/src/client/transcription/use-live-transcription.ts +68 -5
- package/corpus/core/src/client/use-run-stuck-detection.ts +41 -3
- package/corpus/core/src/deploy/build.ts +59 -3
- package/corpus/core/src/deploy/workspace-deploy.ts +37 -2
- package/corpus/core/src/file-upload/types.ts +2 -0
- package/corpus/core/src/index.ts +37 -0
- package/corpus/core/src/integrations/a2a-continuations-store.ts +6 -4
- package/corpus/core/src/integrations/adapters/discord.ts +362 -0
- package/corpus/core/src/integrations/adapters/index.ts +29 -0
- package/corpus/core/src/integrations/adapters/microsoft-teams.ts +411 -0
- package/corpus/core/src/integrations/adapters/slack.ts +861 -27
- package/corpus/core/src/integrations/adapters/telegram.ts +54 -15
- package/corpus/core/src/integrations/adapters/whatsapp.ts +41 -17
- package/corpus/core/src/integrations/catalog.ts +571 -0
- package/corpus/core/src/integrations/controls-store.ts +187 -0
- package/corpus/core/src/integrations/index.ts +100 -0
- package/corpus/core/src/integrations/installations-store.ts +677 -0
- package/corpus/core/src/integrations/integration-memory.ts +187 -0
- package/corpus/core/src/integrations/pending-tasks-retry-job.ts +6 -6
- package/corpus/core/src/integrations/pending-tasks-store.ts +83 -5
- package/corpus/core/src/integrations/plugin.ts +685 -47
- package/corpus/core/src/integrations/scope-store.ts +498 -0
- package/corpus/core/src/integrations/slack-manifest.ts +78 -0
- package/corpus/core/src/integrations/slack-oauth.ts +343 -0
- package/corpus/core/src/integrations/types.ts +179 -0
- package/corpus/core/src/integrations/usage-budget-store.ts +906 -0
- package/corpus/core/src/integrations/webhook-handler.ts +562 -51
- package/corpus/core/src/jobs/scheduler.ts +100 -2
- package/corpus/core/src/jobs/tools.ts +45 -9
- package/corpus/core/src/provider-api/index.ts +72 -1
- package/corpus/core/src/resources/handlers.ts +88 -14
- package/corpus/core/src/resources/script-helpers.ts +36 -7
- package/corpus/core/src/resources/store.ts +59 -52
- package/corpus/core/src/scripts/call-agent.ts +107 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +294 -119
- package/corpus/core/src/server/auth.ts +10 -14
- package/corpus/core/src/server/builder-design-systems.ts +16 -1
- package/corpus/core/src/server/edge.ts +18 -0
- package/corpus/core/src/server/index.ts +26 -0
- package/corpus/core/src/server/request-context.ts +18 -0
- package/corpus/core/src/server/social-og-image.ts +3 -2
- package/corpus/core/src/styles/agent-native.css +62 -44
- package/corpus/core/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/core/src/templates/default/AGENTS.md +7 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/core/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -2
- package/corpus/core/src/usage/store.ts +37 -2
- package/corpus/templates/analytics/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +23 -0
- package/corpus/templates/analytics/.builder/skills/provider-api/SKILL.md +15 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +25 -2
- package/corpus/templates/analytics/app/lib/data-sources.ts +28 -0
- package/corpus/templates/analytics/changelog/2026-07-10-agent-created-uptime-monitors-now-return-a-direct-link-to-th.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-dashboard-email-reports-still-arrive-when-screenshot-capture-temporarily-fails.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +3 -7
- package/corpus/templates/analytics/server/lib/credential-keys.ts +12 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +5 -1
- package/corpus/templates/analytics/server/lib/provider-credentials.ts +2 -0
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +16 -0
- package/corpus/templates/assets/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/brain/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/calendar/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/calendar/app/components/calendar/CommandPalette.tsx +98 -108
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +97 -90
- package/corpus/templates/calendar/changelog/2026-07-10-event-guest-details-and-option-menus-now-use-valid-accessibl.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-10-natural-language-event-phrases-stay-available-as-quick-creat.md +6 -0
- package/corpus/templates/chat/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
- package/corpus/templates/clips/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +17 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +8 -0
- package/corpus/templates/clips/AGENTS.md +8 -3
- package/corpus/templates/clips/actions/finalize-recording.ts +63 -23
- package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -2
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +72 -9
- package/corpus/templates/clips/actions/list-recordings.ts +19 -3
- package/corpus/templates/clips/actions/navigate.ts +2 -0
- package/corpus/templates/clips/actions/reprocess-recording.ts +20 -6
- package/corpus/templates/clips/actions/request-transcript.ts +16 -31
- package/corpus/templates/clips/actions/view-screen.ts +57 -5
- package/corpus/templates/clips/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/clips/app/components/library/empty-state.tsx +2 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +69 -42
- package/corpus/templates/clips/app/components/library/library-layout.tsx +15 -1
- package/corpus/templates/clips/app/components/library/recording-card.tsx +81 -68
- package/corpus/templates/clips/app/components/library/search-bar.tsx +4 -3
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +9 -3
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +1 -1
- package/corpus/templates/clips/app/hooks/use-library.ts +1 -1
- package/corpus/templates/clips/app/hooks/use-navigation-state.ts +10 -2
- package/corpus/templates/clips/app/i18n/ar-SA.ts +7 -1
- package/corpus/templates/clips/app/i18n/de-DE.ts +7 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +7 -1
- package/corpus/templates/clips/app/i18n/es-ES.ts +7 -1
- package/corpus/templates/clips/app/i18n/fr-FR.ts +7 -1
- package/corpus/templates/clips/app/i18n/hi-IN.ts +7 -1
- package/corpus/templates/clips/app/i18n/ja-JP.ts +7 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +7 -1
- package/corpus/templates/clips/app/i18n/pt-BR.ts +7 -1
- package/corpus/templates/clips/app/i18n/zh-CN.ts +8 -1
- package/corpus/templates/clips/app/i18n/zh-TW.ts +8 -1
- package/corpus/templates/clips/app/lib/recording-visibility.ts +70 -0
- package/corpus/templates/clips/app/routes/_app.shared.tsx +20 -0
- package/corpus/templates/clips/app/routes/download.tsx +24 -8
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +115 -2
- package/corpus/templates/clips/app/routes/record.tsx +62 -0
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +25 -16
- package/corpus/templates/clips/changelog/2026-07-10-clips-desktop-is-now-available-for-linux-with-appimage-debia.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-clips-downloads-updates-sooner-in-the-background-and-offers-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-clips-shared-with-you-now-appear-in-a-searchable-shared-with.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-clips-with-missing-mobile-video-frames-can-be-repaired-witho.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-mobile-camera-recordings-pause-while-backgrounded.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-mp4-downloads-now-show-progress-immediately-after-the-option.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-recording-pages-now-open-as-soon-as-you-stop-with-a-share-li.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-recordings-now-seek-smoothly-downloads-use-the-correct-file-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-s3-compatible-storage-now-saves-hosted-recordings-without-re.md +6 -0
- package/corpus/templates/clips/desktop/README.md +22 -6
- package/corpus/templates/clips/desktop/package.json +1 -1
- package/corpus/templates/clips/desktop/src/app.tsx +32 -19
- package/corpus/templates/clips/desktop/src/components/ReadinessPanel.tsx +15 -9
- package/corpus/templates/clips/desktop/src/lib/finalization-guard.ts +22 -0
- package/corpus/templates/clips/desktop/src/lib/permissions.ts +3 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +97 -120
- package/corpus/templates/clips/desktop/src/lib/updater.ts +26 -4
- package/corpus/templates/clips/desktop/src/overlays/finalizing.tsx +4 -8
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +2 -2
- package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +11 -7
- package/corpus/templates/clips/desktop/src-tauri/tauri.linux.conf.json +11 -0
- package/corpus/templates/clips/netlify.toml +3 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +106 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +9 -1
- package/corpus/templates/clips/server/lib/resumable-upload-provider.ts +52 -0
- package/corpus/templates/clips/server/lib/s3-upload-provider.ts +433 -85
- package/corpus/templates/clips/server/lib/video-remux.ts +114 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +109 -0
- package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +22 -11
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +4 -2
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +47 -5
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +10 -2
- package/corpus/templates/clips/shared/share-loader-response.ts +12 -0
- package/corpus/templates/clips/shared/transcript-status.ts +40 -0
- package/corpus/templates/content/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/content/.agents/skills/content/SKILL.md +57 -5
- package/corpus/templates/content/AGENTS.md +65 -55
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +10 -16
- package/corpus/templates/content/actions/_database-source-utils.ts +58 -11
- package/corpus/templates/content/actions/_property-utils.ts +30 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +312 -114
- package/corpus/templates/content/actions/submit-content-database-form.ts +497 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +8 -1
- package/corpus/templates/content/actions/view-screen.ts +4 -1
- package/corpus/templates/content/agent-native.app-skill.json +1 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +250 -64
- package/corpus/templates/content/app/components/editor/database/FormView.tsx +460 -0
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +3 -0
- package/corpus/templates/content/app/components/editor/database/settings.tsx +30 -37
- package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
- package/corpus/templates/content/app/components/editor/database/view-config.ts +29 -1
- package/corpus/templates/content/app/components/ui/textarea.tsx +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +22 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +21 -0
- package/corpus/templates/content/app/i18n-data.ts +225 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-backed-properties-now-load-current-source-values-as-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-database-refreshes-now-stay-explicit-and-accurate.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-database-form-views-now-collect-ordered-required-answers-and.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-database-tables-now-use-a-quieter-more-compact-layout-with-c.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-slack-intake-routes-to-content-database-forms.md +6 -0
- package/corpus/templates/content/parity/matrix.md +1 -0
- package/corpus/templates/content/parity/matrix.ts +18 -0
- package/corpus/templates/content/shared/api.ts +27 -1
- package/corpus/templates/content/shared/database-form.ts +53 -0
- package/corpus/templates/design/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +26 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +85 -12
- package/corpus/templates/design/AGENTS.md +72 -18
- package/corpus/templates/design/DESIGN.md +1 -1
- package/corpus/templates/design/DEVELOPING.md +1 -1
- package/corpus/templates/design/FIGMA_INTEROPERABILITY.md +116 -0
- package/corpus/templates/design/actions/create-design-from-template.ts +220 -0
- package/corpus/templates/design/actions/create-design-system.ts +92 -16
- package/corpus/templates/design/actions/delete-design-template.ts +28 -0
- package/corpus/templates/design/actions/delete-file.ts +7 -0
- package/corpus/templates/design/actions/edit-design.ts +3 -0
- package/corpus/templates/design/actions/export-design-as-figma-svg.ts +137 -5
- package/corpus/templates/design/actions/export-pdf.ts +1 -1
- package/corpus/templates/design/actions/generate-design.ts +3 -0
- package/corpus/templates/design/actions/get-design-snapshot.ts +9 -0
- package/corpus/templates/design/actions/get-figma-connection-status.ts +26 -0
- package/corpus/templates/design/actions/get-figma-design-context.ts +138 -0
- package/corpus/templates/design/actions/get-figma-styles.ts +2 -2
- package/corpus/templates/design/actions/import-figma-clipboard.ts +112 -16
- package/corpus/templates/design/actions/import-figma-frame.ts +15 -4
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +4 -0
- package/corpus/templates/design/actions/list-design-templates.ts +118 -0
- package/corpus/templates/design/actions/navigate.ts +16 -2
- package/corpus/templates/design/actions/provider-api-request.ts +11 -1
- package/corpus/templates/design/actions/save-design-as-template.ts +156 -0
- package/corpus/templates/design/actions/set-active-breakpoint.ts +13 -4
- package/corpus/templates/design/actions/take-design-screenshot.ts +73 -3
- package/corpus/templates/design/actions/update-file.ts +39 -22
- package/corpus/templates/design/actions/view-screen.ts +36 -1
- package/corpus/templates/design/actions/write-local-file.ts +50 -38
- package/corpus/templates/design/app/components/design/AutoLayoutSuggestionDialog.tsx +151 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +20 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +251 -22
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +3 -3
- package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +384 -9
- package/corpus/templates/design/app/components/design/EditPanel.tsx +105 -32
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +58 -28
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +6 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +539 -53
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +40 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +1 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +1 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +5 -1
- package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +2 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +3 -1
- package/corpus/templates/design/app/components/design/code-workbench/workspace/types.ts +2 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +19 -0
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +1 -0
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +27 -0
- package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +137 -81
- package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +25 -5
- package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +1 -1
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +220 -3
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +13 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +22 -1
- package/corpus/templates/design/app/components/design/types.ts +4 -0
- package/corpus/templates/design/app/components/design-system/ProductionDesignSystemShowcase.tsx +208 -0
- package/corpus/templates/design/app/components/editor/FigmaLinkComposerBubble.tsx +321 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +24 -4
- package/corpus/templates/design/app/components/layout/Layout.tsx +16 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -0
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +72 -0
- package/corpus/templates/design/app/global.css +2 -35
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +10 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +127 -5
- package/corpus/templates/design/app/i18n-breakpoints.ts +209 -0
- package/corpus/templates/design/app/i18n-data.ts +1317 -59
- package/corpus/templates/design/app/i18n-template-feature.ts +458 -0
- package/corpus/templates/design/app/lib/design-clipboard.ts +202 -0
- package/corpus/templates/design/app/lib/design-file-upload.ts +87 -0
- package/corpus/templates/design/app/lib/design-import.ts +168 -11
- package/corpus/templates/design/app/lib/desktop-design-preview.ts +423 -0
- package/corpus/templates/design/app/lib/figma-clipboard.ts +74 -8
- package/corpus/templates/design/app/lib/figma-connection.ts +161 -0
- package/corpus/templates/design/app/lib/figma-svg-copy.ts +814 -22
- package/corpus/templates/design/app/lib/figma-url.ts +77 -0
- package/corpus/templates/design/app/lib/pending-generation.ts +35 -0
- package/corpus/templates/design/app/pages/DesignSystems.tsx +236 -177
- package/corpus/templates/design/app/pages/Index.tsx +38 -0
- package/corpus/templates/design/app/pages/Templates.tsx +498 -0
- package/corpus/templates/design/app/pages/design-editor/auto-layout-suggestion.ts +328 -0
- package/corpus/templates/design/app/pages/design-editor/clone-idrefs.ts +113 -0
- package/corpus/templates/design/app/pages/design-editor/created-screen-navigation.ts +55 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +32 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +49 -2
- package/corpus/templates/design/app/pages/design-editor/export-capture.ts +296 -0
- package/corpus/templates/design/app/pages/design-editor/history.ts +101 -2
- package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +28 -1
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +34 -0
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +202 -6
- package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +92 -0
- package/corpus/templates/design/app/pages/design-editor/save-failure.ts +58 -0
- package/corpus/templates/design/app/routes/templates.tsx +4 -6
- package/corpus/templates/design/changelog/2026-07-10-app-workspaces-now-use-clean-borderless-main-surfaces-throug.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-ask-chat-what-s-in-a-figma-file-or-frame-structure-screensho.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-canvas-edits-now-reject-malformed-html-before-it-can-corrupt.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-complex-designs-now-export-as-valid-secure-svgs-and-crisp-ra.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-complex-figma-masks-arcs-rich-text-transformed-images-and-ad.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-copied-layers-paste-across-designs-and-browser-tabs.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-copy-and-download-editable-figma-svg.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-copying-design-text-now-pastes-readable-text-into-other-apps.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-deleted-screens-can-be-restored-with-undo-and-removed-again-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-design-changes-now-save-before-switching-apps-and-retry-when.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-design-stays-usable-on-phones-by-keeping-editor-panels-and-f.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-download-all-screens-as-one-multi-page-pdf-from-the-overview.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-duplicated-layers-now-keep-labels-aria-relationships-fragmen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fig-import-results-stay-compact.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-figma-imports-now-load-real-fonts-fix-rotated-gradient-dashe.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-figma-links-in-chat-and-the-import-tab-now-offer-secure-one-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-cmd-z-not-restoring-content-after-an-agent-driven-desi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-download-pdf-being-unreachable-from-the-export-panel-e.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-dragging-a-layer-out-of-an-auto-layout-row-column-no-l.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-figma-svg-export-text-wrapping-sizing-and-inner-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-hiding-or-locking-one-layer-no-longer-hides-or-blocks-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-png-screenshots-of-tall-screens-being-cropped-to-one-v.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-png-svg-exports-capturing-broken-layout-when-webfonts-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-frame-tool-now-offers-standard-ad-unit-size-presets-medium-r.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-full-view-controls-stay-within-their-frame-instead-of-coveri.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-hover-focus-focus-visible-pressed-and-disabled-states-now-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-layer-drops-now-land-in-the-intended-grid-row-stay-visually-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-local-code-workspaces-now-keep-unsaved-edits-across-panel-sw.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-local-visual-editing-now-keeps-authenticated-sessions-shared.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-long-running-agent-work-no-longer-shows-a-premature-stuck-wa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-managed-figma-connections-are-recognized-automatically.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-designs-can-open-directly-in-the-editor-without-a-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-screens-are-selected-and-revealed-immediately.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-text-layers-undo-as-one-safe-creation.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-preview-and-apply-inferred-auto-layout-without-changing-yo.md +5 -0
- package/corpus/templates/design/changelog/2026-07-10-print-pdf-exports-and-paper-size-presets-letter-a4-now-match.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-responsive-frame-editing.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-reusable-design-templates.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-screen-overview-frames-now-use-a-clearer-interact-action-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-start-designs-from-source-linked-material-3-carbon-or-primer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-tweaks-guidance.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-uploaded-fig-files-can-now-become-editable-design-screens-wi.md +6 -0
- package/corpus/templates/design/e2e/helpers.ts +3 -3
- package/corpus/templates/design/package.json +2 -0
- package/corpus/templates/design/scripts/qa-figma-stress-import.ts +96 -0
- package/corpus/templates/design/server/db/index.ts +10 -0
- package/corpus/templates/design/server/db/schema.ts +44 -0
- package/corpus/templates/design/server/handlers/import-design-file.ts +114 -80
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +19 -6
- package/corpus/templates/design/server/lib/design-export.ts +240 -3
- package/corpus/templates/design/server/lib/design-template-data.ts +89 -0
- package/corpus/templates/design/server/lib/design-to-figma-svg.ts +250 -26
- package/corpus/templates/design/server/lib/fig-file-decoder.ts +839 -0
- package/corpus/templates/design/server/lib/fig-file-import.ts +287 -0
- package/corpus/templates/design/server/lib/fig-file-limits.ts +3 -0
- package/corpus/templates/design/server/lib/fig-file-to-html.ts +2568 -0
- package/corpus/templates/design/server/lib/figma-design-context.ts +359 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +478 -22
- package/corpus/templates/design/server/lib/figma-node-to-html.ts +554 -29
- package/corpus/templates/design/server/lib/local-figma-qa-upload.ts +112 -0
- package/corpus/templates/design/server/lib/verify-write-grant.ts +16 -2
- package/corpus/templates/design/server/lib/visible-clipboard-html.ts +13 -3
- package/corpus/templates/design/server/plugins/agent-chat.ts +7 -0
- package/corpus/templates/design/server/plugins/db.ts +42 -0
- package/corpus/templates/design/server/plugins/local-figma-qa-upload.ts +7 -0
- package/corpus/templates/design/server/register-secrets.ts +8 -8
- package/corpus/templates/design/server/routes/api/qa-figma-import-assets/[assetId].get.ts +46 -0
- package/corpus/templates/design/server/source-workspace.ts +104 -12
- package/corpus/templates/design/shared/code-layer.ts +105 -28
- package/corpus/templates/design/shared/design-system-templates.ts +301 -0
- package/corpus/templates/design/shared/design-template-presets.ts +195 -0
- package/corpus/templates/design/shared/figma-url.ts +8 -0
- package/corpus/templates/design/shared/html-integrity.ts +306 -0
- package/corpus/templates/design/shared/interaction-states.ts +318 -23
- package/corpus/templates/design/shared/locked-layers.ts +151 -0
- package/corpus/templates/dispatch/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/dispatch/app/i18n/zh-TW.ts +48 -0
- package/corpus/templates/dispatch/app/i18n-data.ts +536 -1
- package/corpus/templates/dispatch/changelog/2026-07-10-connect-slack-workspaces-with-oauth-and-manage-channel-ident.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-10-microsoft-teams-bots-and-discord-slash-commands-can-now-conn.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-10-slack-and-telegram-now-route-uptime-monitor-requests-to-anal.md +6 -0
- package/corpus/templates/forms/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +7 -0
- package/corpus/templates/forms/AGENTS.md +4 -0
- package/corpus/templates/forms/actions/create-form.ts +44 -7
- package/corpus/templates/forms/actions/lib/assert-publishable-form.ts +38 -0
- package/corpus/templates/forms/actions/patch-form-fields.ts +4 -0
- package/corpus/templates/forms/actions/update-form.ts +2 -36
- package/corpus/templates/forms/app/i18n/ar-SA.ts +3 -0
- package/corpus/templates/forms/app/i18n/de-DE.ts +3 -0
- package/corpus/templates/forms/app/i18n/en-US.ts +3 -0
- package/corpus/templates/forms/app/i18n/es-ES.ts +3 -0
- package/corpus/templates/forms/app/i18n/fr-FR.ts +3 -0
- package/corpus/templates/forms/app/i18n/hi-IN.ts +3 -0
- package/corpus/templates/forms/app/i18n/ja-JP.ts +3 -0
- package/corpus/templates/forms/app/i18n/ko-KR.ts +3 -0
- package/corpus/templates/forms/app/i18n/pt-BR.ts +3 -0
- package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
- package/corpus/templates/forms/app/i18n/zh-TW.ts +3 -0
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +17 -0
- package/corpus/templates/forms/changelog/2026-07-10-agent-created-published-forms-now-return-the-anonymous-publi.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-10-published-forms-can-no-longer-be-edited-into-an-unusable-emp.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +4 -3
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/forms/shared/types.ts +5 -0
- package/corpus/templates/mail/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/mail/changelog/2026-07-10-mail-navigation-now-uses-a-clean-borderless-drawer.md +6 -0
- package/corpus/templates/plan/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/plan/app/lib/plan-local-bridge.ts +4 -1
- package/corpus/templates/plan/changelog/2026-07-10-local-plans-now-keep-valid-content-visible-when-one-generate.md +6 -0
- package/corpus/templates/plan/server/lib/local-plan-files.ts +4 -1
- package/corpus/templates/slides/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +88 -2
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/a2a/client.d.ts +9 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +1 -0
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +24 -69
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/types.d.ts +2 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/agent/durable-background.d.ts +11 -0
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +17 -0
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts +2 -2
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +15 -5
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +44 -2
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +90 -9
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +109 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +206 -15
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/types.d.ts +22 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/audit/record.d.ts.map +1 -1
- package/dist/audit/record.js +29 -0
- package/dist/audit/record.js.map +1 -1
- package/dist/audit/store.d.ts.map +1 -1
- package/dist/audit/store.js +62 -3
- package/dist/audit/store.js.map +1 -1
- package/dist/audit/types.d.ts +13 -0
- package/dist/audit/types.d.ts.map +1 -1
- package/dist/audit/types.js.map +1 -1
- package/dist/automation/index.d.ts +193 -0
- package/dist/automation/index.d.ts.map +1 -0
- package/dist/automation/index.js +464 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +10 -3
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +492 -35
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +7 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +32 -8
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +15 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +115 -47
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/RunStuckBanner.d.ts +14 -1
- package/dist/client/RunStuckBanner.d.ts.map +1 -1
- package/dist/client/RunStuckBanner.js +35 -7
- package/dist/client/RunStuckBanner.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts +4 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +49 -4
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/automation.d.ts +14 -0
- package/dist/client/automation.d.ts.map +1 -0
- package/dist/client/automation.js +9 -0
- package/dist/client/automation.js.map +1 -0
- package/dist/client/chat/run-recovery.d.ts +4 -0
- package/dist/client/chat/run-recovery.d.ts.map +1 -1
- package/dist/client/chat/run-recovery.js +12 -10
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +8 -0
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/api.d.ts +115 -0
- package/dist/client/integrations/api.d.ts.map +1 -0
- package/dist/client/integrations/api.js +123 -0
- package/dist/client/integrations/api.js.map +1 -0
- package/dist/client/integrations/index.d.ts +1 -0
- package/dist/client/integrations/index.d.ts.map +1 -1
- package/dist/client/integrations/index.js +1 -0
- package/dist/client/integrations/index.js.map +1 -1
- package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
- package/dist/client/transcription/use-live-transcription.js +59 -5
- package/dist/client/transcription/use-live-transcription.js.map +1 -1
- package/dist/client/use-run-stuck-detection.d.ts +16 -1
- package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
- package/dist/client/use-run-stuck-detection.js +23 -4
- package/dist/client/use-run-stuck-detection.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +49 -4
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/workspace-deploy.d.ts.map +1 -1
- package/dist/deploy/workspace-deploy.js +31 -2
- package/dist/deploy/workspace-deploy.js.map +1 -1
- package/dist/file-upload/types.d.ts +2 -0
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +6 -4
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/adapters/discord.d.ts +3 -0
- package/dist/integrations/adapters/discord.d.ts.map +1 -0
- package/dist/integrations/adapters/discord.js +261 -0
- package/dist/integrations/adapters/discord.js.map +1 -0
- package/dist/integrations/adapters/index.d.ts +4 -0
- package/dist/integrations/adapters/index.d.ts.map +1 -0
- package/dist/integrations/adapters/index.js +26 -0
- package/dist/integrations/adapters/index.js.map +1 -0
- package/dist/integrations/adapters/microsoft-teams.d.ts +5 -0
- package/dist/integrations/adapters/microsoft-teams.d.ts.map +1 -0
- package/dist/integrations/adapters/microsoft-teams.js +295 -0
- package/dist/integrations/adapters/microsoft-teams.js.map +1 -0
- package/dist/integrations/adapters/slack.d.ts +8 -2
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +736 -27
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/adapters/telegram.d.ts +0 -2
- package/dist/integrations/adapters/telegram.d.ts.map +1 -1
- package/dist/integrations/adapters/telegram.js +49 -15
- package/dist/integrations/adapters/telegram.js.map +1 -1
- package/dist/integrations/adapters/whatsapp.d.ts +0 -2
- package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
- package/dist/integrations/adapters/whatsapp.js +40 -17
- package/dist/integrations/adapters/whatsapp.js.map +1 -1
- package/dist/integrations/catalog.d.ts +75 -0
- package/dist/integrations/catalog.d.ts.map +1 -0
- package/dist/integrations/catalog.js +451 -0
- package/dist/integrations/catalog.js.map +1 -0
- package/dist/integrations/controls-store.d.ts +44 -0
- package/dist/integrations/controls-store.d.ts.map +1 -0
- package/dist/integrations/controls-store.js +129 -0
- package/dist/integrations/controls-store.js.map +1 -0
- package/dist/integrations/index.d.ts +13 -1
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js +9 -0
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/installations-store.d.ts +112 -0
- package/dist/integrations/installations-store.d.ts.map +1 -0
- package/dist/integrations/installations-store.js +493 -0
- package/dist/integrations/installations-store.js.map +1 -0
- package/dist/integrations/integration-memory.d.ts +24 -0
- package/dist/integrations/integration-memory.d.ts.map +1 -0
- package/dist/integrations/integration-memory.js +136 -0
- package/dist/integrations/integration-memory.js.map +1 -0
- package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.js +6 -5
- package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +17 -0
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +71 -5
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +520 -35
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/scope-store.d.ts +65 -0
- package/dist/integrations/scope-store.d.ts.map +1 -0
- package/dist/integrations/scope-store.js +361 -0
- package/dist/integrations/scope-store.js.map +1 -0
- package/dist/integrations/slack-manifest.d.ts +66 -0
- package/dist/integrations/slack-manifest.d.ts.map +1 -0
- package/dist/integrations/slack-manifest.js +70 -0
- package/dist/integrations/slack-manifest.js.map +1 -0
- package/dist/integrations/slack-oauth.d.ts +99 -0
- package/dist/integrations/slack-oauth.d.ts.map +1 -0
- package/dist/integrations/slack-oauth.js +226 -0
- package/dist/integrations/slack-oauth.js.map +1 -0
- package/dist/integrations/types.d.ts +144 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js +16 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/integrations/usage-budget-store.d.ts +84 -0
- package/dist/integrations/usage-budget-store.d.ts.map +1 -0
- package/dist/integrations/usage-budget-store.js +650 -0
- package/dist/integrations/usage-budget-store.js.map +1 -0
- package/dist/integrations/webhook-handler.d.ts +4 -0
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +415 -47
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/jobs/scheduler.d.ts +6 -0
- package/dist/jobs/scheduler.d.ts.map +1 -1
- package/dist/jobs/scheduler.js +83 -4
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/jobs/tools.d.ts.map +1 -1
- package/dist/jobs/tools.js +43 -11
- package/dist/jobs/tools.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/index.d.ts +4 -4
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +72 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/resources/handlers.d.ts.map +1 -1
- package/dist/resources/handlers.js +57 -15
- package/dist/resources/handlers.js.map +1 -1
- package/dist/resources/script-helpers.d.ts.map +1 -1
- package/dist/resources/script-helpers.js +34 -8
- package/dist/resources/script-helpers.js.map +1 -1
- package/dist/resources/store.d.ts +10 -0
- package/dist/resources/store.d.ts.map +1 -1
- package/dist/resources/store.js +54 -47
- package/dist/resources/store.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +106 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +15 -4
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +248 -113
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +10 -14
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +3 -1
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +9 -2
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/edge.d.ts +1 -1
- package/dist/server/edge.d.ts.map +1 -1
- package/dist/server/edge.js +1 -1
- package/dist/server/edge.js.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/request-context.d.ts +18 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/social-og-image.d.ts.map +1 -1
- package/dist/server/social-og-image.js +3 -2
- package/dist/server/social-og-image.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-native.css +62 -44
- package/dist/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/dist/templates/default/AGENTS.md +7 -3
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/dist/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
- package/dist/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -2
- package/dist/usage/store.d.ts +7 -0
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +24 -3
- package/dist/usage/store.js.map +1 -1
- package/docs/content/automation-connectors.mdx +80 -0
- package/docs/content/extensions.mdx +8 -0
- package/docs/content/locales/ar-SA/extensions.mdx +8 -0
- package/docs/content/locales/ar-SA/messaging.mdx +84 -15
- package/docs/content/locales/ar-SA/template-clips.mdx +1 -0
- package/docs/content/locales/ar-SA/template-design.mdx +1 -0
- package/docs/content/locales/de-DE/extensions.mdx +10 -0
- package/docs/content/locales/de-DE/messaging.mdx +92 -15
- package/docs/content/locales/de-DE/template-clips.mdx +1 -0
- package/docs/content/locales/de-DE/template-design.mdx +1 -0
- package/docs/content/locales/es-ES/extensions.mdx +10 -0
- package/docs/content/locales/es-ES/messaging.mdx +91 -15
- package/docs/content/locales/es-ES/template-clips.mdx +1 -0
- package/docs/content/locales/es-ES/template-design.mdx +1 -0
- package/docs/content/locales/fr-FR/extensions.mdx +10 -0
- package/docs/content/locales/fr-FR/messaging.mdx +91 -15
- package/docs/content/locales/fr-FR/template-clips.mdx +1 -0
- package/docs/content/locales/fr-FR/template-design.mdx +1 -0
- package/docs/content/locales/hi-IN/extensions.mdx +8 -0
- package/docs/content/locales/hi-IN/messaging.mdx +81 -15
- package/docs/content/locales/hi-IN/template-clips.mdx +1 -0
- package/docs/content/locales/hi-IN/template-design.mdx +1 -0
- package/docs/content/locales/ja-JP/extensions.mdx +9 -0
- package/docs/content/locales/ja-JP/messaging.mdx +81 -15
- package/docs/content/locales/ja-JP/template-clips.mdx +1 -0
- package/docs/content/locales/ja-JP/template-design.mdx +1 -0
- package/docs/content/locales/ko-KR/extensions.mdx +8 -0
- package/docs/content/locales/ko-KR/messaging.mdx +80 -15
- package/docs/content/locales/ko-KR/template-clips.mdx +1 -0
- package/docs/content/locales/ko-KR/template-design.mdx +1 -0
- package/docs/content/locales/pt-BR/extensions.mdx +9 -0
- package/docs/content/locales/pt-BR/messaging.mdx +88 -15
- package/docs/content/locales/pt-BR/template-clips.mdx +1 -0
- package/docs/content/locales/pt-BR/template-design.mdx +1 -0
- package/docs/content/locales/zh-CN/extensions.mdx +6 -0
- package/docs/content/locales/zh-CN/messaging.mdx +78 -15
- package/docs/content/locales/zh-CN/template-clips.mdx +1 -0
- package/docs/content/locales/zh-CN/template-design.mdx +1 -0
- package/docs/content/locales/zh-TW/extensions.mdx +6 -0
- package/docs/content/locales/zh-TW/messaging.mdx +78 -15
- package/docs/content/locales/zh-TW/template-clips.mdx +1 -0
- package/docs/content/locales/zh-TW/template-design.mdx +1 -0
- package/docs/content/messaging.mdx +227 -45
- package/docs/content/template-clips.mdx +3 -0
- package/docs/content/template-design.mdx +4 -0
- package/package.json +5 -1
- package/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/src/templates/default/AGENTS.md +7 -3
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
- package/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
- package/src/templates/workspace-core/AGENTS.md +3 -2
|
@@ -3,6 +3,7 @@ import crypto from "node:crypto";
|
|
|
3
3
|
import fsSync from "node:fs";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import http from "node:http";
|
|
6
|
+
import https from "node:https";
|
|
6
7
|
import path from "node:path";
|
|
7
8
|
const DEFAULT_BRIDGE_PORT = 7331;
|
|
8
9
|
const ROUTE_MANIFEST_FILE = path.join(".agent-native", "design-routes.json");
|
|
@@ -40,6 +41,7 @@ const MANIFEST_CAPABILITIES = {
|
|
|
40
41
|
writeTextFiles: true,
|
|
41
42
|
};
|
|
42
43
|
const PREVIEW_TOKEN_DOMAIN = "agent-native-design-preview-v1\0";
|
|
44
|
+
const PREVIEW_SESSION_COOKIE_NAME = "agent-native-preview-token";
|
|
43
45
|
/**
|
|
44
46
|
* Derive a read-only preview credential from the stronger filesystem token.
|
|
45
47
|
* The one-way hash keeps old `--bridge-token` launch commands compatible while
|
|
@@ -601,8 +603,8 @@ function configureBridgeCors(req, res, configuredOrigins) {
|
|
|
601
603
|
res[BRIDGE_CORS_HEADERS] = approved
|
|
602
604
|
? {
|
|
603
605
|
"access-control-allow-origin": origin,
|
|
604
|
-
"access-control-allow-methods": "GET, HEAD, POST, OPTIONS",
|
|
605
|
-
"access-control-allow-headers": "content-type, x-bridge-token, x-design-preview-token",
|
|
606
|
+
"access-control-allow-methods": "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
607
|
+
"access-control-allow-headers": "authorization, content-type, x-bridge-token, x-design-preview-token, x-csrf-token, x-xsrf-token, x-requested-with",
|
|
606
608
|
"access-control-allow-private-network": "true",
|
|
607
609
|
vary: "Origin",
|
|
608
610
|
}
|
|
@@ -619,17 +621,19 @@ function sendJson(res, statusCode, body) {
|
|
|
619
621
|
});
|
|
620
622
|
res.end(`${JSON.stringify(body, null, 2)}\n`);
|
|
621
623
|
}
|
|
622
|
-
function sendText(res, statusCode, body, contentType) {
|
|
624
|
+
function sendText(res, statusCode, body, contentType, setCookieHeaders = []) {
|
|
623
625
|
res.writeHead(statusCode, {
|
|
624
626
|
"content-type": contentType,
|
|
627
|
+
...(setCookieHeaders.length > 0 ? { "set-cookie": setCookieHeaders } : {}),
|
|
625
628
|
...bridgeCorsHeaders(res),
|
|
626
629
|
});
|
|
627
630
|
res.end(body);
|
|
628
631
|
}
|
|
629
|
-
function sendBytes(res, statusCode, body, headers, contentLength = body.length) {
|
|
632
|
+
function sendBytes(res, statusCode, body, headers, contentLength = body.length, setCookieHeaders = []) {
|
|
630
633
|
const responseHeaders = {
|
|
631
634
|
...bridgeCorsHeaders(res),
|
|
632
635
|
"content-length": String(contentLength),
|
|
636
|
+
...(setCookieHeaders.length > 0 ? { "set-cookie": setCookieHeaders } : {}),
|
|
633
637
|
};
|
|
634
638
|
for (const name of [
|
|
635
639
|
"content-type",
|
|
@@ -665,23 +669,232 @@ function readHeader(req, name) {
|
|
|
665
669
|
const value = req.headers[name];
|
|
666
670
|
return typeof value === "string" ? value : "";
|
|
667
671
|
}
|
|
672
|
+
function readRequestCookie(req, name) {
|
|
673
|
+
for (const rawPair of readHeader(req, "cookie").split(";")) {
|
|
674
|
+
const pair = rawPair.trim();
|
|
675
|
+
const separator = pair.indexOf("=");
|
|
676
|
+
if (separator <= 0 || pair.slice(0, separator).trim() !== name)
|
|
677
|
+
continue;
|
|
678
|
+
return pair.slice(separator + 1).trim();
|
|
679
|
+
}
|
|
680
|
+
return "";
|
|
681
|
+
}
|
|
682
|
+
function previewSessionSetCookie(previewToken) {
|
|
683
|
+
// Partitioned SameSite=None keeps the read-only bridge credential available
|
|
684
|
+
// to nested Design frames without granting an unpartitioned third-party
|
|
685
|
+
// cookie. Loopback origins are potentially trustworthy in Chromium, which
|
|
686
|
+
// permits Secure cookies for local development.
|
|
687
|
+
return `${PREVIEW_SESSION_COOKIE_NAME}=${previewToken}; HttpOnly; Path=/; SameSite=None; Secure; Partitioned`;
|
|
688
|
+
}
|
|
668
689
|
/**
|
|
669
|
-
* Preserve only
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
* the
|
|
673
|
-
*
|
|
674
|
-
*
|
|
690
|
+
* Preserve only browser metadata a local dev server needs to classify module
|
|
691
|
+
* requests and parse ordinary same-origin app mutations. Browser cookies and
|
|
692
|
+
* Authorization are forwarded only when Sec-Fetch-Site says the request came
|
|
693
|
+
* from the proxied app itself; cross-site callers cannot relay them. Bridge
|
|
694
|
+
* control tokens and referrers are never forwarded, and mutation origins are
|
|
695
|
+
* replaced with the connected dev-server origin. Cookie-backed login also
|
|
696
|
+
* uses the isolated in-memory upstream jar below so iframe cookie restrictions
|
|
697
|
+
* cannot split the session across URL-backed screens.
|
|
675
698
|
*/
|
|
676
|
-
function previewProxyRequestHeaders(req) {
|
|
699
|
+
function previewProxyRequestHeaders(req, devServerUrl, cookieHeader = "") {
|
|
677
700
|
const headers = {};
|
|
678
|
-
for (const name of [
|
|
701
|
+
for (const name of [
|
|
702
|
+
"accept",
|
|
703
|
+
"accept-language",
|
|
704
|
+
"content-type",
|
|
705
|
+
"sec-fetch-dest",
|
|
706
|
+
"sec-fetch-mode",
|
|
707
|
+
"sec-fetch-site",
|
|
708
|
+
"x-csrf-token",
|
|
709
|
+
"x-xsrf-token",
|
|
710
|
+
"x-requested-with",
|
|
711
|
+
]) {
|
|
679
712
|
const value = readHeader(req, name);
|
|
680
713
|
if (value)
|
|
681
714
|
headers[name] = value;
|
|
682
715
|
}
|
|
716
|
+
const browserSameOrigin = readHeader(req, "sec-fetch-site") === "same-origin";
|
|
717
|
+
const browserCookie = browserSameOrigin ? readHeader(req, "cookie") : "";
|
|
718
|
+
const mergedCookie = mergePreviewCookieHeaders(cookieHeader, browserCookie);
|
|
719
|
+
if (mergedCookie)
|
|
720
|
+
headers["cookie"] = mergedCookie;
|
|
721
|
+
// Same-origin app code may use localStorage-backed bearer auth. Forward it
|
|
722
|
+
// only from a browser request already classified as same-origin; cross-site
|
|
723
|
+
// callers still authenticate to the bridge with the separate preview token,
|
|
724
|
+
// which is never copied upstream.
|
|
725
|
+
if (browserSameOrigin) {
|
|
726
|
+
const authorization = readHeader(req, "authorization");
|
|
727
|
+
if (authorization && authorization.length <= 16 * 1024) {
|
|
728
|
+
headers["authorization"] = authorization;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (req.method && !["GET", "HEAD"].includes(req.method)) {
|
|
732
|
+
headers["origin"] = new URL(devServerUrl).origin;
|
|
733
|
+
}
|
|
683
734
|
return headers;
|
|
684
735
|
}
|
|
736
|
+
function mergePreviewCookieHeaders(jarCookieHeader, browserCookieHeader) {
|
|
737
|
+
const values = new Map();
|
|
738
|
+
const absorb = (header) => {
|
|
739
|
+
if (!header || Buffer.byteLength(header) > MAX_PREVIEW_COOKIE_BYTES)
|
|
740
|
+
return;
|
|
741
|
+
for (const rawPair of header.split(";")) {
|
|
742
|
+
const pair = rawPair.trim();
|
|
743
|
+
const separator = pair.indexOf("=");
|
|
744
|
+
if (separator <= 0)
|
|
745
|
+
continue;
|
|
746
|
+
const name = pair.slice(0, separator).trim();
|
|
747
|
+
const value = pair.slice(separator + 1).trim();
|
|
748
|
+
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name))
|
|
749
|
+
continue;
|
|
750
|
+
if (/^(?:x-)?agent-native-(?:bridge|preview)(?:-|$)/i.test(name)) {
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
values.set(name, value);
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
absorb(jarCookieHeader);
|
|
757
|
+
// A client-readable same-origin cookie is allowed to update the jar's stale
|
|
758
|
+
// value for this request. HttpOnly cookies arrive with the same value and
|
|
759
|
+
// remain effectively jar-owned.
|
|
760
|
+
absorb(browserCookieHeader);
|
|
761
|
+
return [...values].map(([name, value]) => `${name}=${value}`).join("; ");
|
|
762
|
+
}
|
|
763
|
+
const MAX_PREVIEW_SESSION_COOKIES = 128;
|
|
764
|
+
const MAX_PREVIEW_COOKIE_BYTES = 8 * 1024;
|
|
765
|
+
function responseSetCookieHeaders(headers) {
|
|
766
|
+
const withGetSetCookie = headers;
|
|
767
|
+
if (typeof withGetSetCookie.getSetCookie === "function") {
|
|
768
|
+
return withGetSetCookie.getSetCookie();
|
|
769
|
+
}
|
|
770
|
+
const single = headers.get("set-cookie");
|
|
771
|
+
return single ? [single] : [];
|
|
772
|
+
}
|
|
773
|
+
function defaultCookiePath(url) {
|
|
774
|
+
const pathname = url.pathname || "/";
|
|
775
|
+
const lastSlash = pathname.lastIndexOf("/");
|
|
776
|
+
return lastSlash <= 0 ? "/" : pathname.slice(0, lastSlash);
|
|
777
|
+
}
|
|
778
|
+
function sanitizedBridgeSetCookie(raw) {
|
|
779
|
+
return raw
|
|
780
|
+
.split(";")
|
|
781
|
+
.filter((part) => !/^\s*domain\s*=/i.test(part))
|
|
782
|
+
.join(";");
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Ephemeral cookie session for one connected dev-server origin. Cookies never
|
|
786
|
+
* enter SQL, disk, logs, or another target origin, and disappear when the
|
|
787
|
+
* local bridge exits. This keeps authenticated URL screens in one bridge
|
|
788
|
+
* process on the same upstream session even when browser third-party-cookie
|
|
789
|
+
* rules would otherwise isolate or reject the nested iframe cookies.
|
|
790
|
+
*/
|
|
791
|
+
class PreviewSessionCookieJar {
|
|
792
|
+
origin;
|
|
793
|
+
cookies = new Map();
|
|
794
|
+
constructor(devServerUrl) {
|
|
795
|
+
this.origin = new URL(devServerUrl).origin;
|
|
796
|
+
}
|
|
797
|
+
store(headers, responseUrl) {
|
|
798
|
+
const parsedUrl = new URL(responseUrl);
|
|
799
|
+
if (parsedUrl.origin !== this.origin)
|
|
800
|
+
return [];
|
|
801
|
+
const browserCookies = [];
|
|
802
|
+
for (const raw of responseSetCookieHeaders(headers)) {
|
|
803
|
+
if (!raw || Buffer.byteLength(raw) > MAX_PREVIEW_COOKIE_BYTES)
|
|
804
|
+
continue;
|
|
805
|
+
const parts = raw.split(";");
|
|
806
|
+
const first = parts.shift()?.trim() ?? "";
|
|
807
|
+
const separator = first.indexOf("=");
|
|
808
|
+
if (separator <= 0)
|
|
809
|
+
continue;
|
|
810
|
+
const name = first.slice(0, separator).trim();
|
|
811
|
+
const value = first.slice(separator + 1).trim();
|
|
812
|
+
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name))
|
|
813
|
+
continue;
|
|
814
|
+
let cookiePath = defaultCookiePath(parsedUrl);
|
|
815
|
+
let secure = false;
|
|
816
|
+
let expiresAt;
|
|
817
|
+
let deleteCookie = false;
|
|
818
|
+
for (const attribute of parts) {
|
|
819
|
+
const trimmed = attribute.trim();
|
|
820
|
+
const equals = trimmed.indexOf("=");
|
|
821
|
+
const key = (equals < 0 ? trimmed : trimmed.slice(0, equals))
|
|
822
|
+
.trim()
|
|
823
|
+
.toLowerCase();
|
|
824
|
+
const attributeValue = equals < 0 ? "" : trimmed.slice(equals + 1).trim();
|
|
825
|
+
if (key === "path" && attributeValue.startsWith("/")) {
|
|
826
|
+
cookiePath = attributeValue;
|
|
827
|
+
}
|
|
828
|
+
else if (key === "secure") {
|
|
829
|
+
secure = true;
|
|
830
|
+
}
|
|
831
|
+
else if (key === "max-age") {
|
|
832
|
+
const seconds = Number(attributeValue);
|
|
833
|
+
if (Number.isFinite(seconds)) {
|
|
834
|
+
deleteCookie = seconds <= 0;
|
|
835
|
+
expiresAt = Date.now() + seconds * 1000;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
else if (key === "expires" && expiresAt === undefined) {
|
|
839
|
+
const parsed = Date.parse(attributeValue);
|
|
840
|
+
if (Number.isFinite(parsed))
|
|
841
|
+
expiresAt = parsed;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
const mapKey = `${cookiePath}\u0000${name}`;
|
|
845
|
+
if (deleteCookie ||
|
|
846
|
+
(expiresAt !== undefined && expiresAt <= Date.now())) {
|
|
847
|
+
this.cookies.delete(mapKey);
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
this.cookies.delete(mapKey);
|
|
851
|
+
this.cookies.set(mapKey, {
|
|
852
|
+
name,
|
|
853
|
+
value,
|
|
854
|
+
path: cookiePath,
|
|
855
|
+
secure,
|
|
856
|
+
...(expiresAt !== undefined ? { expiresAt } : {}),
|
|
857
|
+
});
|
|
858
|
+
while (this.cookies.size > MAX_PREVIEW_SESSION_COOKIES) {
|
|
859
|
+
const oldest = this.cookies.keys().next().value;
|
|
860
|
+
if (typeof oldest !== "string")
|
|
861
|
+
break;
|
|
862
|
+
this.cookies.delete(oldest);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
browserCookies.push(sanitizedBridgeSetCookie(raw));
|
|
866
|
+
}
|
|
867
|
+
return browserCookies;
|
|
868
|
+
}
|
|
869
|
+
headerFor(targetUrl) {
|
|
870
|
+
const parsed = new URL(targetUrl);
|
|
871
|
+
if (parsed.origin !== this.origin)
|
|
872
|
+
return "";
|
|
873
|
+
const now = Date.now();
|
|
874
|
+
const matches = [];
|
|
875
|
+
for (const [key, cookie] of this.cookies) {
|
|
876
|
+
if (cookie.expiresAt !== undefined && cookie.expiresAt <= now) {
|
|
877
|
+
this.cookies.delete(key);
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
if (cookie.secure &&
|
|
881
|
+
parsed.protocol !== "https:" &&
|
|
882
|
+
!isLoopbackOrigin(parsed)) {
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
const pathMatches = cookie.path === "/" ||
|
|
886
|
+
parsed.pathname === cookie.path ||
|
|
887
|
+
(cookie.path.endsWith("/")
|
|
888
|
+
? parsed.pathname.startsWith(cookie.path)
|
|
889
|
+
: parsed.pathname.startsWith(`${cookie.path}/`));
|
|
890
|
+
if (!pathMatches)
|
|
891
|
+
continue;
|
|
892
|
+
matches.push(cookie);
|
|
893
|
+
}
|
|
894
|
+
matches.sort((a, b) => b.path.length - a.path.length);
|
|
895
|
+
return matches.map((cookie) => `${cookie.name}=${cookie.value}`).join("; ");
|
|
896
|
+
}
|
|
897
|
+
}
|
|
685
898
|
function resolvePreviewSnapshotUrl(devServerUrl, rawUrl) {
|
|
686
899
|
const base = normalizeHttpUrl(devServerUrl);
|
|
687
900
|
const parsed = new URL(rawUrl?.trim() || "/", `${base}/`);
|
|
@@ -704,7 +917,7 @@ function resolvePreviewProxyUrl(devServerUrl, requestUrl) {
|
|
|
704
917
|
}
|
|
705
918
|
return parsed.toString();
|
|
706
919
|
}
|
|
707
|
-
async function fetchPreviewSnapshot(devServerUrl, targetUrl, redirects = 0) {
|
|
920
|
+
async function fetchPreviewSnapshot(devServerUrl, targetUrl, cookieJar, redirects = 0) {
|
|
708
921
|
if (redirects > 5) {
|
|
709
922
|
throw new Error("Too many redirects while fetching preview snapshot.");
|
|
710
923
|
}
|
|
@@ -717,8 +930,12 @@ async function fetchPreviewSnapshot(devServerUrl, targetUrl, redirects = 0) {
|
|
|
717
930
|
signal: controller.signal,
|
|
718
931
|
headers: {
|
|
719
932
|
accept: "text/html,application/xhtml+xml;q=0.9,*/*;q=0.8",
|
|
933
|
+
...(cookieJar?.headerFor(targetUrl)
|
|
934
|
+
? { cookie: cookieJar.headerFor(targetUrl) }
|
|
935
|
+
: {}),
|
|
720
936
|
},
|
|
721
937
|
});
|
|
938
|
+
const setCookieHeaders = cookieJar?.store(response.headers, targetUrl) ?? [];
|
|
722
939
|
const location = response.headers.get("location");
|
|
723
940
|
if (location && response.status >= 300 && response.status < 400) {
|
|
724
941
|
const redirected = new URL(location, targetUrl);
|
|
@@ -726,20 +943,21 @@ async function fetchPreviewSnapshot(devServerUrl, targetUrl, redirects = 0) {
|
|
|
726
943
|
if (!sameOrigin(redirected.toString(), devServerUrl)) {
|
|
727
944
|
throw new Error("Snapshot redirect left the connected dev server.");
|
|
728
945
|
}
|
|
729
|
-
return fetchPreviewSnapshot(devServerUrl, redirected.toString(), redirects + 1);
|
|
946
|
+
return fetchPreviewSnapshot(devServerUrl, redirected.toString(), cookieJar, redirects + 1);
|
|
730
947
|
}
|
|
731
948
|
return {
|
|
732
949
|
url: response.url || targetUrl,
|
|
733
950
|
status: response.status,
|
|
734
951
|
contentType: response.headers.get("content-type") ?? "",
|
|
735
952
|
html: await response.text(),
|
|
953
|
+
setCookieHeaders,
|
|
736
954
|
};
|
|
737
955
|
}
|
|
738
956
|
finally {
|
|
739
957
|
clearTimeout(timeout);
|
|
740
958
|
}
|
|
741
959
|
}
|
|
742
|
-
async function fetchPreviewProxyResource(devServerUrl, targetUrl,
|
|
960
|
+
async function fetchPreviewProxyResource(devServerUrl, targetUrl, request, cookieJar, redirects = 0) {
|
|
743
961
|
if (redirects > 5) {
|
|
744
962
|
throw new Error("Too many redirects while proxying preview resource.");
|
|
745
963
|
}
|
|
@@ -747,11 +965,15 @@ async function fetchPreviewProxyResource(devServerUrl, targetUrl, requestHeaders
|
|
|
747
965
|
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
748
966
|
try {
|
|
749
967
|
const response = await fetch(targetUrl, {
|
|
750
|
-
method:
|
|
968
|
+
method: request.method,
|
|
751
969
|
redirect: "manual",
|
|
752
970
|
signal: controller.signal,
|
|
753
|
-
headers:
|
|
971
|
+
headers: request.headers,
|
|
972
|
+
body: request.method === "GET" || request.method === "HEAD"
|
|
973
|
+
? undefined
|
|
974
|
+
: request.body,
|
|
754
975
|
});
|
|
976
|
+
const setCookieHeaders = cookieJar?.store(response.headers, targetUrl) ?? [];
|
|
755
977
|
const location = response.headers.get("location");
|
|
756
978
|
if (location && response.status >= 300 && response.status < 400) {
|
|
757
979
|
const redirected = new URL(location, targetUrl);
|
|
@@ -759,13 +981,33 @@ async function fetchPreviewProxyResource(devServerUrl, targetUrl, requestHeaders
|
|
|
759
981
|
if (!sameOrigin(redirected.toString(), devServerUrl)) {
|
|
760
982
|
throw new Error("Proxy redirect left the connected dev server.");
|
|
761
983
|
}
|
|
762
|
-
|
|
984
|
+
const switchToGet = response.status === 303 ||
|
|
985
|
+
((response.status === 301 || response.status === 302) &&
|
|
986
|
+
request.method === "POST");
|
|
987
|
+
const redirectedResponse = await fetchPreviewProxyResource(devServerUrl, redirected.toString(), {
|
|
988
|
+
method: switchToGet ? "GET" : request.method,
|
|
989
|
+
headers: {
|
|
990
|
+
...(request.headers ?? {}),
|
|
991
|
+
...(cookieJar?.headerFor(redirected.toString())
|
|
992
|
+
? { cookie: cookieJar.headerFor(redirected.toString()) }
|
|
993
|
+
: {}),
|
|
994
|
+
},
|
|
995
|
+
body: switchToGet ? undefined : request.body,
|
|
996
|
+
}, cookieJar, redirects + 1);
|
|
997
|
+
return {
|
|
998
|
+
...redirectedResponse,
|
|
999
|
+
setCookieHeaders: [
|
|
1000
|
+
...setCookieHeaders,
|
|
1001
|
+
...redirectedResponse.setCookieHeaders,
|
|
1002
|
+
],
|
|
1003
|
+
};
|
|
763
1004
|
}
|
|
764
1005
|
return {
|
|
765
1006
|
url: response.url || targetUrl,
|
|
766
1007
|
status: response.status,
|
|
767
1008
|
headers: response.headers,
|
|
768
1009
|
body: Buffer.from(await response.arrayBuffer()),
|
|
1010
|
+
setCookieHeaders,
|
|
769
1011
|
};
|
|
770
1012
|
}
|
|
771
1013
|
finally {
|
|
@@ -829,6 +1071,39 @@ async function readRequestBody(req) {
|
|
|
829
1071
|
req.on("error", reject);
|
|
830
1072
|
});
|
|
831
1073
|
}
|
|
1074
|
+
const MAX_PREVIEW_PROXY_REQUEST_BYTES = 8 * 1024 * 1024;
|
|
1075
|
+
class PreviewProxyRequestTooLargeError extends Error {
|
|
1076
|
+
}
|
|
1077
|
+
async function readPreviewProxyRequestBody(req) {
|
|
1078
|
+
const declaredLength = Number(readHeader(req, "content-length"));
|
|
1079
|
+
if (Number.isFinite(declaredLength) &&
|
|
1080
|
+
declaredLength > MAX_PREVIEW_PROXY_REQUEST_BYTES) {
|
|
1081
|
+
throw new PreviewProxyRequestTooLargeError("Preview request body exceeds the 8 MB limit.");
|
|
1082
|
+
}
|
|
1083
|
+
return new Promise((resolve, reject) => {
|
|
1084
|
+
const chunks = [];
|
|
1085
|
+
let size = 0;
|
|
1086
|
+
let tooLarge = false;
|
|
1087
|
+
req.on("data", (chunk) => {
|
|
1088
|
+
size += chunk.length;
|
|
1089
|
+
if (size > MAX_PREVIEW_PROXY_REQUEST_BYTES) {
|
|
1090
|
+
tooLarge = true;
|
|
1091
|
+
chunks.length = 0;
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
if (!tooLarge)
|
|
1095
|
+
chunks.push(chunk);
|
|
1096
|
+
});
|
|
1097
|
+
req.on("end", () => {
|
|
1098
|
+
if (tooLarge) {
|
|
1099
|
+
reject(new PreviewProxyRequestTooLargeError("Preview request body exceeds the 8 MB limit."));
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
resolve(Buffer.concat(chunks));
|
|
1103
|
+
});
|
|
1104
|
+
req.on("error", reject);
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
832
1107
|
/**
|
|
833
1108
|
* Resolve `targetDir` under `rootPath` with realpath so that symlinks and
|
|
834
1109
|
* traversal sequences (../../etc) cannot escape the root. Throws if the
|
|
@@ -1055,8 +1330,13 @@ async function atomicWriteBridgeFile(args) {
|
|
|
1055
1330
|
await fs.rm(tempPath, { force: true }).catch(() => undefined);
|
|
1056
1331
|
}
|
|
1057
1332
|
}
|
|
1058
|
-
/**
|
|
1059
|
-
|
|
1333
|
+
/**
|
|
1334
|
+
* Extensions that are safe for creating a brand-new text/code file through
|
|
1335
|
+
* the bridge. Existing files are classified by their bytes instead, so the
|
|
1336
|
+
* Code workbench can edit languages and extensionless config files without a
|
|
1337
|
+
* permanently incomplete allowlist.
|
|
1338
|
+
*/
|
|
1339
|
+
const ALLOWED_NEW_TEXT_FILE_EXTENSIONS = new Set([
|
|
1060
1340
|
".html",
|
|
1061
1341
|
".htm",
|
|
1062
1342
|
".css",
|
|
@@ -1078,11 +1358,90 @@ const ALLOWED_WRITE_EXTENSIONS = new Set([
|
|
|
1078
1358
|
".yml",
|
|
1079
1359
|
".yaml",
|
|
1080
1360
|
".svg",
|
|
1361
|
+
".py",
|
|
1362
|
+
".rb",
|
|
1363
|
+
".php",
|
|
1364
|
+
".java",
|
|
1365
|
+
".kt",
|
|
1366
|
+
".kts",
|
|
1367
|
+
".go",
|
|
1368
|
+
".rs",
|
|
1369
|
+
".c",
|
|
1370
|
+
".h",
|
|
1371
|
+
".cc",
|
|
1372
|
+
".cpp",
|
|
1373
|
+
".hpp",
|
|
1374
|
+
".cs",
|
|
1375
|
+
".swift",
|
|
1376
|
+
".sh",
|
|
1377
|
+
".bash",
|
|
1378
|
+
".zsh",
|
|
1379
|
+
".fish",
|
|
1380
|
+
".sql",
|
|
1381
|
+
".toml",
|
|
1382
|
+
".xml",
|
|
1383
|
+
".graphql",
|
|
1384
|
+
".gql",
|
|
1385
|
+
".prisma",
|
|
1386
|
+
".properties",
|
|
1387
|
+
".ini",
|
|
1388
|
+
".conf",
|
|
1389
|
+
".env.example",
|
|
1390
|
+
]);
|
|
1391
|
+
const ALLOWED_NEW_EXTENSIONLESS_TEXT_FILES = new Set([
|
|
1392
|
+
"dockerfile",
|
|
1393
|
+
"makefile",
|
|
1394
|
+
"procfile",
|
|
1395
|
+
"gemfile",
|
|
1396
|
+
"rakefile",
|
|
1397
|
+
"license",
|
|
1398
|
+
"readme",
|
|
1081
1399
|
]);
|
|
1082
|
-
|
|
1400
|
+
const BLOCKED_BINARY_WRITE_EXTENSIONS = new Set([
|
|
1401
|
+
".png",
|
|
1402
|
+
".jpg",
|
|
1403
|
+
".jpeg",
|
|
1404
|
+
".gif",
|
|
1405
|
+
".webp",
|
|
1406
|
+
".ico",
|
|
1407
|
+
".woff",
|
|
1408
|
+
".woff2",
|
|
1409
|
+
".ttf",
|
|
1410
|
+
".otf",
|
|
1411
|
+
".eot",
|
|
1412
|
+
".mp3",
|
|
1413
|
+
".mp4",
|
|
1414
|
+
".mov",
|
|
1415
|
+
".webm",
|
|
1416
|
+
".zip",
|
|
1417
|
+
".gz",
|
|
1418
|
+
".tar",
|
|
1419
|
+
".pdf",
|
|
1420
|
+
".wasm",
|
|
1421
|
+
".fig",
|
|
1422
|
+
".sketch",
|
|
1423
|
+
".exe",
|
|
1424
|
+
".dll",
|
|
1425
|
+
".dylib",
|
|
1426
|
+
".so",
|
|
1427
|
+
".class",
|
|
1428
|
+
".jar",
|
|
1429
|
+
]);
|
|
1430
|
+
function assertEditableTextFile(relPath, existing) {
|
|
1083
1431
|
const ext = path.extname(relPath).toLowerCase();
|
|
1084
|
-
if (
|
|
1085
|
-
throw new Error(`Write rejected: extension "${ext
|
|
1432
|
+
if (BLOCKED_BINARY_WRITE_EXTENSIONS.has(ext)) {
|
|
1433
|
+
throw new Error(`Write rejected: extension "${ext}" is a binary file type.`);
|
|
1434
|
+
}
|
|
1435
|
+
if (existing) {
|
|
1436
|
+
if (existing.content.includes("\0")) {
|
|
1437
|
+
throw new Error("Write rejected: the existing file contains binary data.");
|
|
1438
|
+
}
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
const basename = path.basename(relPath).toLowerCase();
|
|
1442
|
+
if (!ALLOWED_NEW_TEXT_FILE_EXTENSIONS.has(ext) &&
|
|
1443
|
+
!ALLOWED_NEW_EXTENSIONLESS_TEXT_FILES.has(basename)) {
|
|
1444
|
+
throw new Error(`Write rejected: extension "${ext || "(no extension)"}" is not recognized for a new text/code file.`);
|
|
1086
1445
|
}
|
|
1087
1446
|
}
|
|
1088
1447
|
/**
|
|
@@ -1423,6 +1782,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1423
1782
|
// registered" (id changed, safe to transparently re-POST `/live-edit-bridge`
|
|
1424
1783
|
// and retry) — instead of guessing from the error text or retrying forever.
|
|
1425
1784
|
const bridgeInstanceId = crypto.randomBytes(16).toString("hex");
|
|
1785
|
+
const previewSessionCookies = new PreviewSessionCookieJar(manifest.devServerUrl);
|
|
1426
1786
|
const server = http.createServer((req, res) => {
|
|
1427
1787
|
const corsApproved = configureBridgeCors(req, res, configuredOrigins);
|
|
1428
1788
|
if (req.method === "OPTIONS") {
|
|
@@ -1435,6 +1795,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1435
1795
|
const pathname = requestUrl.pathname;
|
|
1436
1796
|
const providedPreviewToken = readHeader(req, "x-design-preview-token") ||
|
|
1437
1797
|
requestUrl.searchParams.get("previewToken") ||
|
|
1798
|
+
readRequestCookie(req, PREVIEW_SESSION_COOKIE_NAME) ||
|
|
1438
1799
|
"";
|
|
1439
1800
|
const previewTokenValid = constantTimeTokenMatches(providedPreviewToken, previewToken);
|
|
1440
1801
|
const rejectInvalidPreviewToken = () => {
|
|
@@ -1546,7 +1907,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1546
1907
|
try {
|
|
1547
1908
|
const targetUrl = resolvePreviewSnapshotUrl(manifest.devServerUrl, requestUrl.searchParams.get("url") ??
|
|
1548
1909
|
requestUrl.searchParams.get("path"));
|
|
1549
|
-
const snapshot = await fetchPreviewSnapshot(manifest.devServerUrl, targetUrl);
|
|
1910
|
+
const snapshot = await fetchPreviewSnapshot(manifest.devServerUrl, targetUrl, previewSessionCookies);
|
|
1550
1911
|
const includeEditorBridge = requestUrl.searchParams.get("bridge") !== "0";
|
|
1551
1912
|
const requestedBridgeKey = requestUrl.searchParams.get("bridgeKey")?.trim() ?? "";
|
|
1552
1913
|
const editorBridgeScript = requestedBridgeKey
|
|
@@ -1578,7 +1939,10 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1578
1939
|
const html = injectLiveEditBridge(snapshot.html, new URL("/", manifest.bridgeUrl).toString(), includeEditorBridge ? editorBridgeScript : "", targetPath);
|
|
1579
1940
|
sendText(res, snapshot.status >= 400 ? snapshot.status : 200, html, snapshot.contentType.includes("html")
|
|
1580
1941
|
? snapshot.contentType
|
|
1581
|
-
: "text/html; charset=utf-8"
|
|
1942
|
+
: "text/html; charset=utf-8", [
|
|
1943
|
+
...snapshot.setCookieHeaders,
|
|
1944
|
+
previewSessionSetCookie(previewToken),
|
|
1945
|
+
]);
|
|
1582
1946
|
}
|
|
1583
1947
|
catch (err) {
|
|
1584
1948
|
sendJson(res, 400, {
|
|
@@ -1600,7 +1964,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1600
1964
|
try {
|
|
1601
1965
|
const targetUrl = resolvePreviewSnapshotUrl(manifest.devServerUrl, requestUrl.searchParams.get("url") ??
|
|
1602
1966
|
requestUrl.searchParams.get("path"));
|
|
1603
|
-
const snapshot = await fetchPreviewSnapshot(manifest.devServerUrl, targetUrl);
|
|
1967
|
+
const snapshot = await fetchPreviewSnapshot(manifest.devServerUrl, targetUrl, previewSessionCookies);
|
|
1604
1968
|
sendJson(res, snapshot.status >= 400 ? snapshot.status : 200, {
|
|
1605
1969
|
ok: snapshot.status < 400,
|
|
1606
1970
|
source: manifest.source,
|
|
@@ -1683,8 +2047,6 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1683
2047
|
});
|
|
1684
2048
|
return;
|
|
1685
2049
|
}
|
|
1686
|
-
// write-file and apply-edit only allow known text/code extensions.
|
|
1687
|
-
assertAllowedExtension(relPath);
|
|
1688
2050
|
const expectedVersionHash = typeof body["expectedVersionHash"] === "string"
|
|
1689
2051
|
? body["expectedVersionHash"]
|
|
1690
2052
|
: undefined;
|
|
@@ -1695,6 +2057,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1695
2057
|
throw new Error("Bridge target changed while waiting for the write lock");
|
|
1696
2058
|
}
|
|
1697
2059
|
const existing = await readBridgeFileSnapshot(lockedTarget.absolutePath);
|
|
2060
|
+
assertEditableTextFile(relPath, existing);
|
|
1698
2061
|
assertExpectedBridgeVersion(expectedVersionHash, existing?.versionHash, requireExpectedVersionHash);
|
|
1699
2062
|
if (pathname === "/write-file") {
|
|
1700
2063
|
const content = typeof body["content"] === "string"
|
|
@@ -1821,9 +2184,9 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1821
2184
|
})();
|
|
1822
2185
|
return;
|
|
1823
2186
|
}
|
|
1824
|
-
if (req.method
|
|
1825
|
-
|
|
1826
|
-
if (!previewTokenValid
|
|
2187
|
+
if (req.method &&
|
|
2188
|
+
["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"].includes(req.method)) {
|
|
2189
|
+
if (!previewTokenValid) {
|
|
1827
2190
|
sendJson(res, 401, {
|
|
1828
2191
|
ok: false,
|
|
1829
2192
|
error: "invalid or missing preview token",
|
|
@@ -1832,12 +2195,31 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1832
2195
|
}
|
|
1833
2196
|
void (async () => {
|
|
1834
2197
|
try {
|
|
1835
|
-
const
|
|
1836
|
-
|
|
1837
|
-
|
|
2198
|
+
const proxyRequestUrl = new URL(req.url ?? "/", manifest.bridgeUrl);
|
|
2199
|
+
proxyRequestUrl.searchParams.delete("previewToken");
|
|
2200
|
+
const targetUrl = resolvePreviewProxyUrl(manifest.devServerUrl, `${proxyRequestUrl.pathname}${proxyRequestUrl.search}`);
|
|
2201
|
+
const method = req.method ?? "GET";
|
|
2202
|
+
const requestBody = method === "GET" || method === "HEAD"
|
|
2203
|
+
? undefined
|
|
2204
|
+
: await readPreviewProxyRequestBody(req);
|
|
2205
|
+
const cookieHeader = previewSessionCookies.headerFor(targetUrl);
|
|
2206
|
+
const proxied = await fetchPreviewProxyResource(manifest.devServerUrl, targetUrl, {
|
|
2207
|
+
method,
|
|
2208
|
+
headers: previewProxyRequestHeaders(req, manifest.devServerUrl, cookieHeader),
|
|
2209
|
+
body: requestBody,
|
|
2210
|
+
}, previewSessionCookies);
|
|
2211
|
+
const contentType = proxied.headers.get("content-type") ?? "";
|
|
2212
|
+
const documentNavigation = readHeader(req, "sec-fetch-dest") === "document";
|
|
2213
|
+
const responseBody = documentNavigation && contentType.includes("html")
|
|
2214
|
+
? Buffer.from(injectLiveEditBridge(proxied.body.toString("utf8"), new URL("/", manifest.bridgeUrl).toString(), liveEditBridgeScript, (() => {
|
|
2215
|
+
const parsed = new URL(proxied.url);
|
|
2216
|
+
return `${parsed.pathname}${parsed.search}` || "/";
|
|
2217
|
+
})()))
|
|
2218
|
+
: proxied.body;
|
|
2219
|
+
sendBytes(res, proxied.status, method === "HEAD" ? Buffer.alloc(0) : responseBody, proxied.headers, responseBody.length, proxied.setCookieHeaders);
|
|
1838
2220
|
}
|
|
1839
2221
|
catch (err) {
|
|
1840
|
-
sendJson(res, 400, {
|
|
2222
|
+
sendJson(res, err instanceof PreviewProxyRequestTooLargeError ? 413 : 400, {
|
|
1841
2223
|
ok: false,
|
|
1842
2224
|
error: err instanceof Error ? err.message : String(err),
|
|
1843
2225
|
});
|
|
@@ -1847,6 +2229,81 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
1847
2229
|
}
|
|
1848
2230
|
sendJson(res, 404, { ok: false, error: "not found" });
|
|
1849
2231
|
});
|
|
2232
|
+
// Vite's proxied /@vite/client derives its HMR socket from the document's
|
|
2233
|
+
// bridge origin. Tunnel WebSocket upgrades to the one connected dev-server
|
|
2234
|
+
// origin so Fast Refresh remains live inside URL-backed screens. The target
|
|
2235
|
+
// is never caller-controlled, bridge credentials are stripped, and only a
|
|
2236
|
+
// same-origin iframe (or an explicit preview-token caller) can open it.
|
|
2237
|
+
server.on("upgrade", (req, clientSocket, clientHead) => {
|
|
2238
|
+
const requestUrl = new URL(req.url ?? "/", manifest.bridgeUrl);
|
|
2239
|
+
const providedPreviewToken = readHeader(req, "x-design-preview-token") ||
|
|
2240
|
+
requestUrl.searchParams.get("previewToken") ||
|
|
2241
|
+
readRequestCookie(req, PREVIEW_SESSION_COOKIE_NAME) ||
|
|
2242
|
+
"";
|
|
2243
|
+
const browserOrigin = readHeader(req, "origin");
|
|
2244
|
+
const sameBridgeOrigin = browserOrigin === new URL(manifest.bridgeUrl).origin;
|
|
2245
|
+
if (!constantTimeTokenMatches(providedPreviewToken, previewToken)) {
|
|
2246
|
+
clientSocket.end("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2249
|
+
requestUrl.searchParams.delete("previewToken");
|
|
2250
|
+
let targetUrl;
|
|
2251
|
+
try {
|
|
2252
|
+
targetUrl = new URL(resolvePreviewProxyUrl(manifest.devServerUrl, `${requestUrl.pathname}${requestUrl.search}`));
|
|
2253
|
+
}
|
|
2254
|
+
catch {
|
|
2255
|
+
clientSocket.end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
const upstreamHeaders = { ...req.headers };
|
|
2259
|
+
delete upstreamHeaders["x-bridge-token"];
|
|
2260
|
+
delete upstreamHeaders["x-design-preview-token"];
|
|
2261
|
+
delete upstreamHeaders["authorization"];
|
|
2262
|
+
delete upstreamHeaders["cookie"];
|
|
2263
|
+
upstreamHeaders.host = targetUrl.host;
|
|
2264
|
+
upstreamHeaders.origin = new URL(manifest.devServerUrl).origin;
|
|
2265
|
+
const cookie = mergePreviewCookieHeaders(previewSessionCookies.headerFor(targetUrl.toString()), sameBridgeOrigin ? readHeader(req, "cookie") : "");
|
|
2266
|
+
if (cookie)
|
|
2267
|
+
upstreamHeaders.cookie = cookie;
|
|
2268
|
+
const requestImpl = targetUrl.protocol === "https:" ? https : http;
|
|
2269
|
+
const upstreamRequest = requestImpl.request({
|
|
2270
|
+
protocol: targetUrl.protocol,
|
|
2271
|
+
hostname: targetUrl.hostname,
|
|
2272
|
+
port: targetUrl.port,
|
|
2273
|
+
path: `${targetUrl.pathname}${targetUrl.search}`,
|
|
2274
|
+
method: "GET",
|
|
2275
|
+
headers: upstreamHeaders,
|
|
2276
|
+
});
|
|
2277
|
+
upstreamRequest.on("upgrade", (upstreamResponse, upstreamSocket, upstreamHead) => {
|
|
2278
|
+
const statusLine = `HTTP/1.1 ${upstreamResponse.statusCode ?? 101} ${upstreamResponse.statusMessage || "Switching Protocols"}\r\n`;
|
|
2279
|
+
const headerLines = [];
|
|
2280
|
+
for (let index = 0; index < upstreamResponse.rawHeaders.length; index += 2) {
|
|
2281
|
+
const name = upstreamResponse.rawHeaders[index];
|
|
2282
|
+
const value = upstreamResponse.rawHeaders[index + 1];
|
|
2283
|
+
if (name && value !== undefined)
|
|
2284
|
+
headerLines.push(`${name}: ${value}`);
|
|
2285
|
+
}
|
|
2286
|
+
clientSocket.write(`${statusLine}${headerLines.join("\r\n")}\r\n\r\n`);
|
|
2287
|
+
if (clientHead.length > 0)
|
|
2288
|
+
upstreamSocket.write(clientHead);
|
|
2289
|
+
if (upstreamHead.length > 0)
|
|
2290
|
+
clientSocket.write(upstreamHead);
|
|
2291
|
+
clientSocket.once("close", () => upstreamSocket.destroy());
|
|
2292
|
+
upstreamSocket.once("close", () => clientSocket.destroy());
|
|
2293
|
+
upstreamSocket.pipe(clientSocket);
|
|
2294
|
+
clientSocket.pipe(upstreamSocket);
|
|
2295
|
+
});
|
|
2296
|
+
upstreamRequest.on("response", (upstreamResponse) => {
|
|
2297
|
+
clientSocket.end(`HTTP/1.1 ${upstreamResponse.statusCode ?? 502} ${upstreamResponse.statusMessage || "WebSocket upgrade failed"}\r\nConnection: close\r\nContent-Length: 0\r\n\r\n`);
|
|
2298
|
+
upstreamResponse.resume();
|
|
2299
|
+
});
|
|
2300
|
+
upstreamRequest.on("error", () => {
|
|
2301
|
+
if (!clientSocket.destroyed) {
|
|
2302
|
+
clientSocket.end("HTTP/1.1 502 Bad Gateway\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
2303
|
+
}
|
|
2304
|
+
});
|
|
2305
|
+
upstreamRequest.end();
|
|
2306
|
+
});
|
|
1850
2307
|
await new Promise((resolve, reject) => {
|
|
1851
2308
|
server.once("error", reject);
|
|
1852
2309
|
server.listen(new URL(manifest.bridgeUrl).port, "127.0.0.1", () => {
|