@agent-native/core 0.169.1 → 0.170.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/agent-native.eject.json +4 -1
- package/bin/agent-native.js +23 -5
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +28 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
- package/corpus/templates/analytics/app/routes/$.tsx +10 -0
- package/corpus/templates/analytics/app/routes.ts +3 -1
- package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
- package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
- package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
- package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
- package/corpus/templates/analytics/server/lib/slack.ts +4 -2
- package/corpus/templates/analytics/vitest.config.ts +6 -1
- package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/assets/app/routes/library.tsx +5 -3
- package/corpus/templates/assets/app/routes.ts +3 -1
- package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
- package/corpus/templates/assets/vitest.config.ts +6 -1
- package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/brain/app/routes/sources.tsx +8 -3
- package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
- package/corpus/templates/brain/vitest.config.ts +1 -0
- package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
- package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
- package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
- package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
- package/corpus/templates/calendar/app/routes.ts +3 -1
- package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
- package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
- package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
- package/corpus/templates/calendar/server/onboarding.ts +85 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/calendar/shared/api.ts +9 -1
- package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/chat/app/routes.ts +3 -1
- package/corpus/templates/chat/vitest.config.ts +8 -0
- package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/clips/actions/get-meeting.ts +9 -4
- package/corpus/templates/clips/actions/list-recordings.ts +16 -3
- package/corpus/templates/clips/actions/search-meetings.ts +1 -0
- package/corpus/templates/clips/actions/view-screen.ts +8 -1
- package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
- package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
- package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
- package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
- package/corpus/templates/clips/desktop/src/app.tsx +53 -24
- package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
- package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
- package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
- package/corpus/templates/clips/server/lib/emails.ts +17 -33
- package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
- package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
- package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
- package/corpus/templates/content/app/i18n-data.ts +25 -0
- package/corpus/templates/content/app/routes.ts +3 -1
- package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
- package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
- package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
- package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
- package/corpus/templates/content/vitest.config.ts +7 -1
- package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1383 -88
- package/corpus/templates/design/actions/generate-design.ts +98 -47
- package/corpus/templates/design/actions/get-design-system.ts +6 -1
- package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2057 -141
- package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
- package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -1
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
- package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -4
- package/corpus/templates/design/app/i18n-data.ts +1 -0
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
- package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +77 -35
- package/corpus/templates/design/app/pages/DesignSystems.tsx +136 -42
- package/corpus/templates/design/app/pages/Index.tsx +2 -0
- package/corpus/templates/design/app/pages/Templates.tsx +0 -10
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
- package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
- package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
- package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
- package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
- package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
- package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
- package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
- package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
- package/corpus/templates/design/app/routes.ts +3 -1
- package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
- package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
- package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
- package/corpus/templates/design/package.json +2 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
- package/corpus/templates/design/shared/canvas-math.ts +612 -206
- package/corpus/templates/design/shared/pen-path.ts +37 -0
- package/corpus/templates/design/vitest.config.ts +7 -1
- package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
- package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
- package/corpus/templates/dispatch/app/routes.ts +3 -1
- package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/factory/.env.example +2 -7
- package/corpus/templates/factory/AGENTS.md +3 -0
- package/corpus/templates/factory/README.md +5 -3
- package/corpus/templates/factory/actions/create-factory.ts +16 -3
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
- package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
- package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
- package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
- package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
- package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
- package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
- package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
- package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
- package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
- package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
- package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
- package/corpus/templates/factory/app/routes/factory.tsx +84 -11
- package/corpus/templates/factory/app/routes.ts +3 -1
- package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
- package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
- package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
- package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
- package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
- package/corpus/templates/factory/vitest.config.ts +17 -2
- package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
- package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
- package/corpus/templates/forms/vitest.config.ts +1 -0
- package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/macros/app/routes.ts +3 -1
- package/corpus/templates/macros/vitest.config.ts +6 -1
- package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
- package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
- package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
- package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
- package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
- package/corpus/templates/mail/app/routes/$.tsx +9 -0
- package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
- package/corpus/templates/mail/app/routes/$view.tsx +47 -1
- package/corpus/templates/mail/app/routes.ts +3 -1
- package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
- package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
- package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
- package/corpus/templates/mail/server/onboarding.ts +66 -18
- package/corpus/templates/mail/vitest.config.ts +6 -1
- package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/plan/app/routes/settings.tsx +4 -1
- package/corpus/templates/plan/app/routes.ts +3 -1
- package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/plan/netlify.toml +1 -1
- package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/slides/actions/patch-deck.ts +79 -10
- package/corpus/templates/slides/actions/update-slide.ts +11 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
- package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
- package/corpus/templates/slides/app/routes.ts +3 -1
- package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
- package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
- package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
- package/corpus/templates/slides/tsconfig.json +5 -0
- package/corpus/templates/slides/vitest.config.ts +6 -1
- package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
- package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
- package/corpus/templates/tasks/app/routes.ts +3 -1
- package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
- package/corpus/templates/tasks/vitest.config.ts +7 -1
- package/dist/action.d.ts +91 -0
- package/dist/action.js +50 -0
- package/dist/agent/abort-reasons.d.ts +38 -0
- package/dist/agent/abort-reasons.js +49 -0
- package/dist/agent/engine/ai-sdk-engine.js +8 -5
- package/dist/agent/engine/anthropic-engine.js +7 -5
- package/dist/agent/engine/first-event-timeout.d.ts +42 -17
- package/dist/agent/engine/first-event-timeout.js +67 -25
- package/dist/agent/production-agent.d.ts +23 -0
- package/dist/agent/production-agent.js +107 -102
- package/dist/agent/run-loop-with-resume.d.ts +2 -28
- package/dist/agent/run-loop-with-resume.js +25 -40
- package/dist/agent/run-manager.js +5 -4
- package/dist/agent/run-store.d.ts +55 -0
- package/dist/agent/run-store.js +124 -1
- package/dist/agent/tool-search.js +2 -1
- package/dist/agent/types.d.ts +9 -4
- package/dist/app-config/configuration-error.d.ts +11 -0
- package/dist/app-config/configuration-error.js +14 -0
- package/dist/app-config/index.d.ts +1 -0
- package/dist/app-config/index.js +1 -0
- package/dist/app-config/integrations.d.ts +1 -0
- package/dist/app-config/integrations.js +10 -0
- package/dist/app-config/plugins.d.ts +34 -0
- package/dist/app-config/plugins.js +39 -0
- package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
- package/dist/app-config/run-lifecycle-invariants.js +18 -25
- package/dist/app-config/schema.d.ts +16 -0
- package/dist/app-config/schema.js +2 -0
- package/dist/chat-threads/schema-migrations.js +20 -0
- package/dist/chat-threads/store.js +21 -4
- package/dist/cli/native-dependencies.d.ts +4 -0
- package/dist/cli/native-dependencies.js +15 -0
- package/dist/client/EnvironmentBadge.d.ts +1 -1
- package/dist/client/EnvironmentBadge.js +40 -5
- package/dist/client/MultiTabAssistantChat.d.ts +1 -1
- package/dist/client/MultiTabAssistantChat.js +35 -14
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/agent-page/use-jobs.d.ts +2 -1
- package/dist/client/agent-page/use-jobs.js +3 -5
- package/dist/client/agent-sidebar-state.js +3 -1
- package/dist/client/blocks/library/code-tabs.js +5 -0
- package/dist/client/blocks/library/code.js +1 -0
- package/dist/client/chat-first/apps-rail.js +2 -2
- package/dist/client/chat-model-groups.d.ts +12 -0
- package/dist/client/chat-model-groups.js +3 -2
- package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
- package/dist/client/integrations/GoogleProductLogo.js +45 -0
- package/dist/client/integrations/index.d.ts +2 -0
- package/dist/client/integrations/index.js +2 -0
- package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
- package/dist/client/integrations/workspace-provider-oauth.js +13 -0
- package/dist/client/resources/mcp-integration-catalog.js +0 -29
- package/dist/client/settings/SettingsTabsPage.js +10 -6
- package/dist/client/sharing/ShareButton.js +11 -2
- package/dist/client/use-chat-models.d.ts +6 -0
- package/dist/client/use-chat-models.js +10 -0
- package/dist/client/use-db-sync.js +27 -9
- package/dist/connections/catalog.d.ts +111 -9
- package/dist/connections/catalog.js +86 -30
- package/dist/db/create-get-db.js +18 -0
- package/dist/db/ddl-guard.d.ts +0 -4
- package/dist/db/ddl-guard.js +46 -0
- package/dist/deploy/build.d.ts +19 -0
- package/dist/deploy/build.js +190 -16
- package/dist/deploy/function-bundle.d.ts +45 -0
- package/dist/deploy/function-bundle.js +337 -0
- package/dist/deploy/workspace-deploy.js +19 -1
- package/dist/eject/workspace-connections.js +4 -0
- package/dist/email-catalog/registry.d.ts +4 -0
- package/dist/email-catalog/registry.js +79 -14
- package/dist/extensions/content-patch.js +14 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/plugin.d.ts +10 -0
- package/dist/integrations/plugin.js +40 -6
- package/dist/jobs/actions/run-automation-now.d.ts +2 -1
- package/dist/jobs/actions/run-automation-now.js +11 -5
- package/dist/jobs/frontmatter.js +53 -2
- package/dist/jobs/run-now.d.ts +11 -1
- package/dist/jobs/run-now.js +42 -7
- package/dist/jobs/scheduler.d.ts +1 -0
- package/dist/jobs/scheduler.js +2 -1
- package/dist/localization/core-messages/ar-SA.js +3 -0
- package/dist/localization/core-messages/de-DE.js +3 -0
- package/dist/localization/core-messages/en-US.d.ts +3 -0
- package/dist/localization/core-messages/en-US.js +3 -0
- package/dist/localization/core-messages/es-ES.js +3 -0
- package/dist/localization/core-messages/fr-FR.js +3 -0
- package/dist/localization/core-messages/hi-IN.js +3 -0
- package/dist/localization/core-messages/ja-JP.js +3 -0
- package/dist/localization/core-messages/ko-KR.js +3 -0
- package/dist/localization/core-messages/pt-BR.js +3 -0
- package/dist/localization/core-messages/zh-CN.js +3 -0
- package/dist/localization/core-messages/zh-TW.js +3 -0
- package/dist/localization/core-messages.d.ts +3 -0
- package/dist/localization/default-messages.d.ts +2 -5
- package/dist/localization/default-messages.js +2 -5
- package/dist/mcp/build-server.d.ts +9 -0
- package/dist/mcp/build-server.js +37 -8
- package/dist/mcp-client/oauth-client.d.ts +7 -0
- package/dist/mcp-client/oauth-client.js +12 -1
- package/dist/oauth-tokens/index.d.ts +1 -1
- package/dist/oauth-tokens/index.js +1 -1
- package/dist/oauth-tokens/lifecycle.d.ts +11 -0
- package/dist/oauth-tokens/lifecycle.js +17 -0
- package/dist/oauth-tokens/store.js +7 -0
- package/dist/observability/posthog-ai.d.ts +15 -1
- package/dist/observability/posthog-ai.js +24 -12
- package/dist/observability/routes.d.ts +3 -3
- package/dist/observability/traces.js +158 -28
- package/dist/onboarding/app-profile.js +2 -2
- package/dist/onboarding/plugin.js +10 -2
- package/dist/onboarding/types.d.ts +2 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/provider-api/index.js +2 -0
- package/dist/resources/store.js +13 -4
- package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/server/action-discovery.js +5 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
- package/dist/server/agent-chat/action-filters-a2a.js +48 -9
- package/dist/server/agent-chat-plugin.js +36 -9
- package/dist/server/agent-discovery.js +43 -20
- package/dist/server/auth.js +18 -16
- package/dist/server/beta-opt-out-html.js +45 -4
- package/dist/server/better-auth-instance.d.ts +2 -1
- package/dist/server/better-auth-instance.js +23 -7
- package/dist/server/builder-design-systems.d.ts +4 -1
- package/dist/server/builder-design-systems.js +87 -6
- package/dist/server/builder-oauth.d.ts +1 -7
- package/dist/server/builder-oauth.js +80 -163
- package/dist/server/core-routes-plugin.d.ts +29 -0
- package/dist/server/core-routes-plugin.js +100 -20
- package/dist/server/default-plugins.d.ts +18 -0
- package/dist/server/default-plugins.js +22 -0
- package/dist/server/edge.d.ts +1 -0
- package/dist/server/edge.js +1 -0
- package/dist/server/framework-request-handler.js +31 -3
- package/dist/server/google-oauth.d.ts +3 -0
- package/dist/server/google-oauth.js +3 -0
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +3 -3
- package/dist/server/onboarding-html.js +37 -3
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +6 -1
- package/dist/server/workspace-provider-oauth.js +72 -20
- package/dist/shared/agent-sidebar-url.d.ts +1 -0
- package/dist/shared/agent-sidebar-url.js +1 -0
- package/dist/shared/environment-lanes.d.ts +2 -0
- package/dist/shared/environment-lanes.js +3 -1
- package/dist/shared/index.d.ts +3 -1
- package/dist/shared/index.js +3 -1
- package/dist/shared/surface-visibility.d.ts +31 -0
- package/dist/shared/surface-visibility.js +57 -0
- package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/chat/app/routes.ts +3 -1
- package/dist/templates/chat/vitest.config.ts +8 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/default/app/routes.ts +3 -1
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
- package/dist/tracking/registry.d.ts +11 -0
- package/dist/tracking/registry.js +5 -2
- package/dist/triggers/actions.js +10 -3
- package/dist/usage/store.js +23 -3
- package/dist/user-profile/actions/get-auth-methods.js +18 -5
- package/dist/vite/client.js +24 -5
- package/docs/content/actions-access-control.mdx +43 -4
- package/docs/content/actions-defining.mdx +16 -0
- package/docs/content/template-clips-capture-everywhere.mdx +29 -30
- package/docs/content/template-clips-developers.mdx +4 -4
- package/docs/content/template-clips.mdx +3 -1
- package/package.json +2 -2
- package/src/eject/workspace-connections.ts +4 -0
- package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/chat/app/routes.ts +3 -1
- package/src/templates/chat/vitest.config.ts +8 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/default/app/routes.ts +3 -1
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
|
@@ -87,3 +87,340 @@ function copyTree(src, dest, placeFile, ancestorRealPaths = new Set()) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
/** Nitro's SSR page/asset route entries. Only the `/*` server function uses these. */
|
|
91
|
+
const SSR_ENTRY_FILES = [
|
|
92
|
+
"_...page_.get.mjs",
|
|
93
|
+
"_...page_.head.mjs",
|
|
94
|
+
"_...asset_.get.mjs",
|
|
95
|
+
];
|
|
96
|
+
// Rolldown emits `import(`./x.mjs`)` with BACKTICKS; a quote-only pattern
|
|
97
|
+
// under-reports the graph by tens of MB and would delete reachable chunks.
|
|
98
|
+
const SPECIFIER = /(?:from|import|require)\s*\(?\s*(["'`])([^"'`]*)\1/g;
|
|
99
|
+
// `import(`${pkg}/server`)` is a BARE specifier and can never name a local
|
|
100
|
+
// chunk. Only a specifier that is relative BEFORE the interpolation is
|
|
101
|
+
// genuinely unresolvable, and that is when we must not guess.
|
|
102
|
+
const RELATIVE_INTERPOLATED = /import\s*\(\s*`\s*[./][^`]*\$\{/;
|
|
103
|
+
/**
|
|
104
|
+
* Every file reachable from `main.mjs`, treating `removed` as already deleted.
|
|
105
|
+
* Returns null when the graph cannot be resolved statically, so the caller
|
|
106
|
+
* prunes nothing rather than deleting a chunk something still imports.
|
|
107
|
+
*/
|
|
108
|
+
function reachableFiles(dir, removed) {
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
const visit = (file) => {
|
|
111
|
+
if (seen.has(file))
|
|
112
|
+
return true;
|
|
113
|
+
seen.add(file);
|
|
114
|
+
let src;
|
|
115
|
+
try {
|
|
116
|
+
src = fs.readFileSync(file, "utf-8");
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
if (RELATIVE_INTERPOLATED.test(src))
|
|
122
|
+
return false;
|
|
123
|
+
SPECIFIER.lastIndex = 0;
|
|
124
|
+
for (let m; (m = SPECIFIER.exec(src));) {
|
|
125
|
+
const spec = m[2];
|
|
126
|
+
if (!spec.startsWith("."))
|
|
127
|
+
continue;
|
|
128
|
+
const base = path.resolve(path.dirname(file), spec);
|
|
129
|
+
const hit = [
|
|
130
|
+
base,
|
|
131
|
+
`${base}.mjs`,
|
|
132
|
+
`${base}.js`,
|
|
133
|
+
path.join(base, "index.mjs"),
|
|
134
|
+
].find((c) => fs.existsSync(c) && fs.statSync(c).isFile());
|
|
135
|
+
// Docs prose inside the bundle contains path-shaped strings that are not
|
|
136
|
+
// imports; a specifier resolving to nothing is not an edge.
|
|
137
|
+
if (!hit)
|
|
138
|
+
continue;
|
|
139
|
+
if (removed.has(path.relative(dir, hit)))
|
|
140
|
+
continue;
|
|
141
|
+
if (!visit(hit))
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
};
|
|
146
|
+
return visit(path.join(dir, "main.mjs")) ? seen : null;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Drop the SSR page/asset island from a clone that can never route to it.
|
|
150
|
+
*
|
|
151
|
+
* The background and integration-recovery entries overwrite `url.pathname`
|
|
152
|
+
* unconditionally before delegating to `main.mjs`, so those clones cannot reach
|
|
153
|
+
* the page or asset handlers — yet each shipped a full copy of that island, and
|
|
154
|
+
* Netlify zips and uploads every function separately. Deleting from the clone is
|
|
155
|
+
* safe under hard links: only an in-place WRITE would reach the source bundle.
|
|
156
|
+
*/
|
|
157
|
+
export function pruneSsrIslandFromRewritingClone(dest, entryText) {
|
|
158
|
+
if (!/^\s*url\.pathname\s*=/m.test(entryText)) {
|
|
159
|
+
throw new Error("[deploy] SSR prune requires a clone entry that rewrites url.pathname unconditionally");
|
|
160
|
+
}
|
|
161
|
+
const full = reachableFiles(dest, new Set());
|
|
162
|
+
const lean = reachableFiles(dest, new Set(SSR_ENTRY_FILES));
|
|
163
|
+
if (!full || !lean) {
|
|
164
|
+
console.warn("[deploy] SSR prune skipped: unresolvable relative dynamic import in the clone.");
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
let bytes = 0;
|
|
168
|
+
for (const file of full) {
|
|
169
|
+
if (lean.has(file))
|
|
170
|
+
continue;
|
|
171
|
+
try {
|
|
172
|
+
bytes += fs.statSync(file).size;
|
|
173
|
+
fs.rmSync(file, { force: true });
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// coercion-ok: a file already gone is the goal state, and its bytes were
|
|
177
|
+
// read before the unlink, so the reported total stays honest.
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const name of SSR_ENTRY_FILES) {
|
|
181
|
+
fs.rmSync(path.join(dest, name), { force: true });
|
|
182
|
+
}
|
|
183
|
+
return bytes;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Read a package's manifest, or null when it has none. Shared with build.ts's
|
|
187
|
+
* copyRuntimePackageTree, which is why this lives here rather than there:
|
|
188
|
+
* build.ts already imports from this file, and the reverse import would be
|
|
189
|
+
* circular.
|
|
190
|
+
*/
|
|
191
|
+
export function readPackageManifest(packageDir) {
|
|
192
|
+
const packageJsonPath = path.join(packageDir, "package.json");
|
|
193
|
+
if (!fs.existsSync(packageJsonPath))
|
|
194
|
+
return null;
|
|
195
|
+
const manifest = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
196
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
return manifest;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Every installed package name directly under `nodeModulesDir`, scoped packages
|
|
203
|
+
* expanded to `@scope/name`.
|
|
204
|
+
*
|
|
205
|
+
* Dot-prefixed entries are npm/pnpm bookkeeping, not packages — `.bin` holds
|
|
206
|
+
* executable links and has no manifest, so treating it as a package makes the
|
|
207
|
+
* closure walk throw on a perfectly normal bundle.
|
|
208
|
+
*/
|
|
209
|
+
function listTopLevelPackageNames(nodeModulesDir) {
|
|
210
|
+
if (!fs.existsSync(nodeModulesDir))
|
|
211
|
+
return [];
|
|
212
|
+
const names = [];
|
|
213
|
+
for (const entry of fs.readdirSync(nodeModulesDir, { withFileTypes: true })) {
|
|
214
|
+
if (!entry.isDirectory())
|
|
215
|
+
continue;
|
|
216
|
+
if (entry.name.startsWith("."))
|
|
217
|
+
continue;
|
|
218
|
+
if (!entry.name.startsWith("@")) {
|
|
219
|
+
names.push(entry.name);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const scopeDir = path.join(nodeModulesDir, entry.name);
|
|
223
|
+
for (const scoped of fs.readdirSync(scopeDir, { withFileTypes: true })) {
|
|
224
|
+
if (scoped.isDirectory())
|
|
225
|
+
names.push(`${entry.name}/${scoped.name}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return names;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Every package name reachable from `roots` by walking the given manifest
|
|
232
|
+
* fields — the same edge copyRuntimePackageTree (build.ts) follows to build the
|
|
233
|
+
* browser runtime tree in the first place, so a package that tree copied in is
|
|
234
|
+
* exactly a package this walk can find again.
|
|
235
|
+
*
|
|
236
|
+
* The two callers want deliberately different widths. "What might be dead"
|
|
237
|
+
* walks `dependencies` only, so a dev/optional/peer listing cannot pull an
|
|
238
|
+
* unrelated package into the browser's closure. "What must live" also walks
|
|
239
|
+
* `optionalDependencies`: an installed optional dependency is one a surviving
|
|
240
|
+
* package may still require at runtime, and deleting it is unrecoverable
|
|
241
|
+
* whereas keeping it costs bytes. Err narrow when deciding what to delete and
|
|
242
|
+
* wide when deciding what to spare.
|
|
243
|
+
*
|
|
244
|
+
* A dependency name with no directory here was never installed — the same
|
|
245
|
+
* BARE_RUNTIME_ONLY_PACKAGES / SERVERLESS_FUNCTION_PACKAGE_DENYLIST exclusions
|
|
246
|
+
* upstream leave real, expected gaps in a package's own "dependencies" field,
|
|
247
|
+
* and a gap is not a resolution failure. A directory that DOES exist without a
|
|
248
|
+
* readable package.json is one: the closure can no longer be trusted, so that
|
|
249
|
+
* throws instead of guessing which way is safe.
|
|
250
|
+
*/
|
|
251
|
+
function reachablePackageNames(nodeModulesDir, roots, fields = ["dependencies"]) {
|
|
252
|
+
const seen = new Set();
|
|
253
|
+
const visit = (packageName) => {
|
|
254
|
+
if (seen.has(packageName))
|
|
255
|
+
return;
|
|
256
|
+
seen.add(packageName);
|
|
257
|
+
const packageDir = path.join(nodeModulesDir, ...packageName.split("/"));
|
|
258
|
+
if (!fs.existsSync(packageDir))
|
|
259
|
+
return;
|
|
260
|
+
const manifest = readPackageManifest(packageDir);
|
|
261
|
+
if (!manifest) {
|
|
262
|
+
throw new Error(`[deploy] ${packageDir} has no readable package.json; cannot compute the runtime dependency closure it belongs to.`);
|
|
263
|
+
}
|
|
264
|
+
for (const field of fields) {
|
|
265
|
+
const dependencies = manifest[field];
|
|
266
|
+
if (!dependencies || typeof dependencies !== "object")
|
|
267
|
+
continue;
|
|
268
|
+
for (const dependencyName of Object.keys(dependencies)) {
|
|
269
|
+
visit(dependencyName);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
for (const root of roots)
|
|
274
|
+
visit(root);
|
|
275
|
+
return seen;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Drop a now-empty `@scope` directory. Never remove a scope that still holds a
|
|
279
|
+
* package: an unrelated `@sparticuz/*` some other dependency needs lives in the
|
|
280
|
+
* same scope as the browser runtime, and the closure walk cannot protect what a
|
|
281
|
+
* scope-wide delete takes.
|
|
282
|
+
*/
|
|
283
|
+
function removeScopeIfEmpty(nodeModulesDir, packageDir) {
|
|
284
|
+
const scopeDir = path.dirname(packageDir);
|
|
285
|
+
if (scopeDir === nodeModulesDir)
|
|
286
|
+
return;
|
|
287
|
+
if (fs.readdirSync(scopeDir).length > 0)
|
|
288
|
+
return;
|
|
289
|
+
fs.rmSync(scopeDir, { recursive: true, force: true });
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* The browser runtime copied into serverless functions, by exact package name.
|
|
293
|
+
*
|
|
294
|
+
* Exact names, never the `@sparticuz` scope: another dependency can install an
|
|
295
|
+
* unrelated package into the same scope, and a scope-wide delete takes it with
|
|
296
|
+
* no way for the closure walk to prove it is still needed. build.ts imports
|
|
297
|
+
* this rather than declaring its own copy, so the list that is copied in and
|
|
298
|
+
* the list that is pruned out cannot drift apart.
|
|
299
|
+
*/
|
|
300
|
+
export const SERVERLESS_BROWSER_RUNTIME_PACKAGES = [
|
|
301
|
+
// chromium-min, not chromium: the full package embeds a 66MB browser in every
|
|
302
|
+
// emitted function, paid on every cold start to serve a fallback most requests
|
|
303
|
+
// never take. The min package is 46KB and fetches the same pinned pack on
|
|
304
|
+
// first launch. See chromiumPackUrl() in creative-context's rendered-page.
|
|
305
|
+
// guard:allow-serverless-function-payload — -66.4MB per function, replaces "@sparticuz/chromium"
|
|
306
|
+
"@sparticuz/chromium-min",
|
|
307
|
+
"playwright-core",
|
|
308
|
+
];
|
|
309
|
+
/**
|
|
310
|
+
* Any path whose handler can reach an agent turn, directly or transitively.
|
|
311
|
+
* `_process-run` is the obvious one, but the integration sweep and the
|
|
312
|
+
* recurring-jobs sweep both resume tasks that run a full agent turn with the
|
|
313
|
+
* app's whole tool surface, so a path-shape check alone is not enough.
|
|
314
|
+
*/
|
|
315
|
+
const AGENT_CAPABLE_PATH = /_process-run|_process-task|\/integrations\/|recurring-jobs/;
|
|
316
|
+
function dirSize(dir) {
|
|
317
|
+
let total = 0;
|
|
318
|
+
const stack = [dir];
|
|
319
|
+
while (stack.length > 0) {
|
|
320
|
+
const cur = stack.pop();
|
|
321
|
+
let entries;
|
|
322
|
+
try {
|
|
323
|
+
entries = fs.readdirSync(cur, { withFileTypes: true });
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
for (const entry of entries) {
|
|
329
|
+
const full = path.join(cur, entry.name);
|
|
330
|
+
if (entry.isDirectory())
|
|
331
|
+
stack.push(full);
|
|
332
|
+
else {
|
|
333
|
+
try {
|
|
334
|
+
total += fs.statSync(full).size;
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// coercion-ok: an unreadable entry contributes no measurable bytes and
|
|
338
|
+
// must not abort a size report.
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return total;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Drop the serverless browser runtime — and everything installed only because
|
|
347
|
+
* the runtime needed it — from a clone that can never run an agent turn.
|
|
348
|
+
*
|
|
349
|
+
* Playwright and @sparticuz/chromium are reached only through NON-LITERAL
|
|
350
|
+
* dynamic imports in creative-context's rendered-page connector, so no static
|
|
351
|
+
* walk can prove them dead. The caller asserts it instead, and this refuses the
|
|
352
|
+
* prune when the entry rewrites to a route that could reach an agent — a
|
|
353
|
+
* scheduled report sweep can drop the runtime, an agent worker cannot.
|
|
354
|
+
*
|
|
355
|
+
* Deleting just the two known directories used to leave their whole
|
|
356
|
+
* dependency closure behind — packages like tar-fs and pump that exist in
|
|
357
|
+
* `node_modules` for no other reason than @sparticuz/chromium-min or
|
|
358
|
+
* playwright-core needing them. Those are orphaned the instant the runtime is
|
|
359
|
+
* gone, so this walks the closure and removes it too, keeping only what a
|
|
360
|
+
* still-present, unrelated package also depends on.
|
|
361
|
+
*/
|
|
362
|
+
export function pruneBrowserRuntimeFromNonAgentClone(dest, entryText) {
|
|
363
|
+
if (!/^\s*url\.pathname\s*=/m.test(entryText)) {
|
|
364
|
+
throw new Error("[deploy] browser-runtime prune requires a clone entry that rewrites url.pathname unconditionally");
|
|
365
|
+
}
|
|
366
|
+
if (AGENT_CAPABLE_PATH.test(entryText)) {
|
|
367
|
+
throw new Error("[deploy] refusing to prune the browser runtime from a clone whose entry names an agent-capable route");
|
|
368
|
+
}
|
|
369
|
+
const nodeModulesDir = path.join(dest, "node_modules");
|
|
370
|
+
const browserRoots = SERVERLESS_BROWSER_RUNTIME_PACKAGES.filter((name) => fs.existsSync(path.join(nodeModulesDir, ...name.split("/"))));
|
|
371
|
+
let bytes = 0;
|
|
372
|
+
if (browserRoots.length > 0) {
|
|
373
|
+
// Everything reachable from the runtime being deleted — e.g.
|
|
374
|
+
// @sparticuz/chromium-min's tar-fs, and everything tar-fs needs. A member
|
|
375
|
+
// of this set is dead UNLESS some other, unrelated top-level package also
|
|
376
|
+
// depends on it — `stillNeeded` proves that by walking every package that
|
|
377
|
+
// ISN'T itself downstream of the runtime, so it can never trivially
|
|
378
|
+
// "prove itself" reachable.
|
|
379
|
+
const browserClosure = reachablePackageNames(nodeModulesDir, browserRoots);
|
|
380
|
+
// The function's own manifest is a liveness root too. Its dependencies are
|
|
381
|
+
// what the emitted bundle traced directly, so a package that is BOTH in the
|
|
382
|
+
// browser closure and imported by the surviving server has no other package
|
|
383
|
+
// vouching for it and would be deleted out from under a live import. The
|
|
384
|
+
// browser roots are excluded — they are declared there as well, and keeping
|
|
385
|
+
// them would make the whole closure look alive.
|
|
386
|
+
const ownManifest = readPackageManifest(dest);
|
|
387
|
+
const ownDependencies = ["dependencies", "optionalDependencies"]
|
|
388
|
+
.flatMap((field) => Object.keys(ownManifest?.[field] ?? {}))
|
|
389
|
+
.filter((name) => !browserRoots.includes(name));
|
|
390
|
+
const otherRoots = [
|
|
391
|
+
...listTopLevelPackageNames(nodeModulesDir).filter((name) => !browserClosure.has(name)),
|
|
392
|
+
...ownDependencies,
|
|
393
|
+
];
|
|
394
|
+
const stillNeeded = reachablePackageNames(nodeModulesDir, otherRoots, [
|
|
395
|
+
"dependencies",
|
|
396
|
+
"optionalDependencies",
|
|
397
|
+
]);
|
|
398
|
+
for (const packageName of browserClosure) {
|
|
399
|
+
// The roots are deleted below, after their closure.
|
|
400
|
+
if (browserRoots.includes(packageName))
|
|
401
|
+
continue;
|
|
402
|
+
if (stillNeeded.has(packageName))
|
|
403
|
+
continue;
|
|
404
|
+
const packageDir = path.join(nodeModulesDir, ...packageName.split("/"));
|
|
405
|
+
if (!fs.existsSync(packageDir))
|
|
406
|
+
continue;
|
|
407
|
+
bytes += dirSize(packageDir);
|
|
408
|
+
fs.rmSync(packageDir, { recursive: true, force: true });
|
|
409
|
+
removeScopeIfEmpty(nodeModulesDir, packageDir);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// Delete the roots themselves by package name, never by scope directory: an
|
|
413
|
+
// unrelated @sparticuz/* package that some other dependency still needs would
|
|
414
|
+
// otherwise go with the scope, and `stillNeeded` has no way to protect it.
|
|
415
|
+
// The scope is removed afterwards only once nothing is left in it.
|
|
416
|
+
for (const name of browserRoots) {
|
|
417
|
+
const dir = path.join(nodeModulesDir, ...name.split("/"));
|
|
418
|
+
if (!fs.existsSync(dir))
|
|
419
|
+
continue;
|
|
420
|
+
bytes += dirSize(dir);
|
|
421
|
+
// Hard links: deleting the clone's link never touches the source bundle.
|
|
422
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
423
|
+
removeScopeIfEmpty(nodeModulesDir, dir);
|
|
424
|
+
}
|
|
425
|
+
return bytes;
|
|
426
|
+
}
|
|
@@ -24,7 +24,7 @@ import { findWorkspaceRoot } from "../scripts/utils.js";
|
|
|
24
24
|
import { DEFAULT_WORKSPACE_APP_AUDIENCE, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromPackageJson, } from "../shared/workspace-app-audience.js";
|
|
25
25
|
import { DISPATCH_WORKSPACE_ROOT_REDIRECTS } from "../shared/workspace-app-id.js";
|
|
26
26
|
import { assertEmittedBackgroundFunctionOnDisk, isRecurringJobsDeployEnabled, } from "./build.js";
|
|
27
|
-
import { cloneServerBundleForFunction } from "./function-bundle.js";
|
|
27
|
+
import { cloneServerBundleForFunction, pruneSsrIslandFromRewritingClone, } from "./function-bundle.js";
|
|
28
28
|
import { collectImmutableAssetPaths, IMMUTABLE_ASSET_CACHE_HEADERS, } from "./immutable-assets.js";
|
|
29
29
|
const NETLIFY_WORKSPACE_STATIC_DIR = "_workspace_static";
|
|
30
30
|
const DEFAULT_HOSTED_FEEDBACK_URL = "https://forms.agent-native.com/f/agent-native-feedback/_16ewV";
|
|
@@ -753,6 +753,15 @@ export const config = {
|
|
|
753
753
|
// is the function entrypoint, mirroring patchNetlifyFunctionEntry.
|
|
754
754
|
fs.rmSync(path.join(dest, "server.mjs"), { force: true });
|
|
755
755
|
fs.writeFileSync(path.join(dest, `${backgroundName}.mjs`), server);
|
|
756
|
+
{
|
|
757
|
+
// The clone rewrites url.pathname unconditionally, so it can never
|
|
758
|
+
// route to the SSR page/asset handlers it inherited. Netlify zips and
|
|
759
|
+
// uploads every function separately, so that island is paid for twice.
|
|
760
|
+
const freed = pruneSsrIslandFromRewritingClone(dest, server);
|
|
761
|
+
if (freed > 0) {
|
|
762
|
+
console.log(`[deploy] Pruned ${(freed / 1024 / 1024).toFixed(1)}MB of unroutable SSR modules from ${path.basename(dest)}.`);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
756
765
|
assertEmittedBackgroundFunctionOnDisk(dest, backgroundName);
|
|
757
766
|
console.log(`[workspace-deploy] Emitted durable-background function "${backgroundName}" ` +
|
|
758
767
|
`for app "${app}" with config { background:true } and NO custom path — ` +
|
|
@@ -848,6 +857,15 @@ export const config = {
|
|
|
848
857
|
};
|
|
849
858
|
`;
|
|
850
859
|
fs.writeFileSync(path.join(dest, `${functionName}.mjs`), entry);
|
|
860
|
+
{
|
|
861
|
+
// The clone rewrites url.pathname unconditionally, so it can never route to
|
|
862
|
+
// the SSR page/asset handlers it inherited. Netlify zips and uploads every
|
|
863
|
+
// function separately, so that island is paid for on every deploy.
|
|
864
|
+
const freed = pruneSsrIslandFromRewritingClone(dest, entry);
|
|
865
|
+
if (freed > 0) {
|
|
866
|
+
console.log(`[deploy] Pruned ${(freed / 1024 / 1024).toFixed(1)}MB of unroutable SSR modules from ${path.basename(dest)}.`);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
851
869
|
}
|
|
852
870
|
function patchNetlifyFunctionEntry(functionDir, app, workspaceApps, staticDir) {
|
|
853
871
|
const serverPath = path.join(functionDir, "server.mjs");
|
|
@@ -65,6 +65,10 @@ export type RegisteredTransactionalEmail = TransactionalEmailDefinition & {
|
|
|
65
65
|
* export it and reuse `id` when sending.
|
|
66
66
|
*/
|
|
67
67
|
export declare function defineTransactionalEmail(definition: TransactionalEmailDefinition): RegisteredTransactionalEmail;
|
|
68
|
+
/** Register a catalog as one atomic operation, allowing safe HMR refreshes. */
|
|
69
|
+
export declare function defineTransactionalEmails(definitions: readonly TransactionalEmailDefinition[]): RegisteredTransactionalEmail[];
|
|
70
|
+
/** Replace one app-owned catalog snapshot after validating the full replacement. */
|
|
71
|
+
export declare function replaceTransactionalEmails(ownerApp: string, idPrefix: string, definitions: readonly TransactionalEmailDefinition[]): RegisteredTransactionalEmail[];
|
|
68
72
|
/** Every registered email, sorted by app then name. */
|
|
69
73
|
export declare function listTransactionalEmails(): RegisteredTransactionalEmail[];
|
|
70
74
|
export declare function getTransactionalEmail(id: string): RegisteredTransactionalEmail | undefined;
|
|
@@ -23,27 +23,93 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import { getAppSlug } from "../server/app-name.js";
|
|
25
25
|
const registry = new Map();
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
function resolveDefinition(definition) {
|
|
27
|
+
return {
|
|
28
|
+
...definition,
|
|
29
|
+
app: definition.app ?? getAppSlug() ?? "unknown",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function assertCanRegister(resolved, existing) {
|
|
33
|
+
if (existing &&
|
|
34
|
+
(existing.app !== resolved.app ||
|
|
35
|
+
existing.name !== resolved.name ||
|
|
36
|
+
existing.trigger !== resolved.trigger ||
|
|
37
|
+
existing.recipient !== resolved.recipient ||
|
|
38
|
+
existing.recipientLabel !== resolved.recipientLabel ||
|
|
39
|
+
existing.sender !== resolved.sender ||
|
|
40
|
+
existing.senderLabel !== resolved.senderLabel)) {
|
|
41
|
+
// Two emails sharing an id would silently merge their metrics and make the
|
|
42
|
+
// catalog claim one exists when the other actually sent.
|
|
43
|
+
throw new Error(`Duplicate transactional email id "${resolved.id}". Ids must be unique across the app.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
28
46
|
/**
|
|
29
47
|
* Register a transactional email. Returns the definition so the call site can
|
|
30
48
|
* export it and reuse `id` when sending.
|
|
31
49
|
*/
|
|
32
50
|
export function defineTransactionalEmail(definition) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// catalog claim one exists when the other actually sent.
|
|
37
|
-
throw new Error(`Duplicate transactional email id "${definition.id}". Ids must be unique across the app.`);
|
|
38
|
-
}
|
|
39
|
-
const resolved = {
|
|
40
|
-
...definition,
|
|
41
|
-
app: definition.app ?? getAppSlug() ?? "unknown",
|
|
42
|
-
};
|
|
51
|
+
const resolved = resolveDefinition(definition);
|
|
52
|
+
// HMR recreates preview functions, so stable catalog metadata is the collision boundary.
|
|
53
|
+
assertCanRegister(resolved, registry.get(resolved.id));
|
|
43
54
|
registry.set(definition.id, resolved);
|
|
44
|
-
sources.set(definition.id, definition);
|
|
45
55
|
return resolved;
|
|
46
56
|
}
|
|
57
|
+
function resolveDefinitions(definitions) {
|
|
58
|
+
const resolved = definitions.map(resolveDefinition);
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
for (const definition of resolved) {
|
|
61
|
+
if (seen.has(definition.id)) {
|
|
62
|
+
throw new Error(`Duplicate transactional email id "${definition.id}". Ids must be unique across the app.`);
|
|
63
|
+
}
|
|
64
|
+
seen.add(definition.id);
|
|
65
|
+
}
|
|
66
|
+
return resolved;
|
|
67
|
+
}
|
|
68
|
+
function validateDefinitions(definitions) {
|
|
69
|
+
const resolved = resolveDefinitions(definitions);
|
|
70
|
+
for (const definition of resolved) {
|
|
71
|
+
assertCanRegister(definition, registry.get(definition.id));
|
|
72
|
+
}
|
|
73
|
+
return resolved;
|
|
74
|
+
}
|
|
75
|
+
function commitDefinitions(definitions) {
|
|
76
|
+
for (const definition of definitions) {
|
|
77
|
+
registry.set(definition.id, definition);
|
|
78
|
+
}
|
|
79
|
+
return [...definitions];
|
|
80
|
+
}
|
|
81
|
+
/** Register a catalog as one atomic operation, allowing safe HMR refreshes. */
|
|
82
|
+
export function defineTransactionalEmails(definitions) {
|
|
83
|
+
return commitDefinitions(validateDefinitions(definitions));
|
|
84
|
+
}
|
|
85
|
+
/** Replace one app-owned catalog snapshot after validating the full replacement. */
|
|
86
|
+
export function replaceTransactionalEmails(ownerApp, idPrefix, definitions) {
|
|
87
|
+
const runtimeApp = getAppSlug();
|
|
88
|
+
if (!ownerApp || ownerApp.includes(".") || idPrefix !== `${ownerApp}.`) {
|
|
89
|
+
throw new Error("Transactional email replacement requires an owner app and its exact namespace prefix.");
|
|
90
|
+
}
|
|
91
|
+
const resolved = resolveDefinitions(definitions);
|
|
92
|
+
if (resolved.some(({ id, app }) => app !== ownerApp || !id.startsWith(idPrefix))) {
|
|
93
|
+
throw new Error(`Transactional email replacement must contain only ${ownerApp} email definitions in the "${idPrefix}" scope.`);
|
|
94
|
+
}
|
|
95
|
+
for (const [id, existing] of registry) {
|
|
96
|
+
if (id.startsWith(idPrefix) && existing.app !== ownerApp) {
|
|
97
|
+
throw new Error(`Transactional email replacement cannot modify "${id}" owned by "${existing.app}".`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const hasExplicitOwner = resolved.length > 0 && resolved.every(({ app }) => app === ownerApp);
|
|
101
|
+
if ((runtimeApp && runtimeApp !== ownerApp) ||
|
|
102
|
+
(!runtimeApp && !hasExplicitOwner)) {
|
|
103
|
+
throw new Error("Transactional email replacement requires a recognized runtime owner or a non-empty snapshot with explicit owner metadata.");
|
|
104
|
+
}
|
|
105
|
+
const nextIds = new Set(resolved.map(({ id }) => id));
|
|
106
|
+
for (const id of registry.keys()) {
|
|
107
|
+
if (id.startsWith(idPrefix) && !nextIds.has(id)) {
|
|
108
|
+
registry.delete(id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return commitDefinitions(resolved);
|
|
112
|
+
}
|
|
47
113
|
/** Every registered email, sorted by app then name. */
|
|
48
114
|
export function listTransactionalEmails() {
|
|
49
115
|
return [...registry.values()].sort((a, b) => a.app.localeCompare(b.app) || a.name.localeCompare(b.name));
|
|
@@ -66,5 +132,4 @@ export function renderTransactionalEmailPreview(id) {
|
|
|
66
132
|
/** Test seam — drops all registrations. */
|
|
67
133
|
export function resetTransactionalEmailRegistry() {
|
|
68
134
|
registry.clear();
|
|
69
|
-
sources.clear();
|
|
70
135
|
}
|
|
@@ -46,10 +46,22 @@ async function applyExtensionContentUpdateUnchecked(currentContent, opts) {
|
|
|
46
46
|
}
|
|
47
47
|
export async function formatExtensionHtml(content) {
|
|
48
48
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// prettier's main entry `import()`s all 13 parser plugins, so a bundler
|
|
50
|
+
// inlines ~3.5MB of flow/typescript/yaml/markdown parsers just to format
|
|
51
|
+
// HTML. Load the standalone core plus only the plugins the HTML printer
|
|
52
|
+
// reaches, which still formats embedded <style> (postcss) and <script>
|
|
53
|
+
// (babel + estree).
|
|
54
|
+
const [{ format }, ...plugins] = await Promise.all([
|
|
55
|
+
import("prettier/standalone"),
|
|
56
|
+
import("prettier/plugins/html"),
|
|
57
|
+
import("prettier/plugins/postcss"),
|
|
58
|
+
import("prettier/plugins/babel"),
|
|
59
|
+
import("prettier/plugins/estree"),
|
|
60
|
+
]);
|
|
61
|
+
const formatted = await format(content, {
|
|
51
62
|
parser: "html",
|
|
52
63
|
htmlWhitespaceSensitivity: "ignore",
|
|
64
|
+
plugins,
|
|
53
65
|
});
|
|
54
66
|
return typeof formatted === "string" ? formatted : content;
|
|
55
67
|
}
|
|
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
17
17
|
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
|
-
error?: undefined;
|
|
21
20
|
configured?: undefined;
|
|
22
21
|
connectPath?: undefined;
|
|
23
22
|
url: string;
|
|
24
23
|
id: string;
|
|
25
24
|
provider: string;
|
|
25
|
+
error?: undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export default _default;
|
|
@@ -31,6 +31,16 @@ export declare const BUILT_IN_INTEGRATION_ADAPTER_FACTORIES: readonly [{
|
|
|
31
31
|
}];
|
|
32
32
|
export declare const BUILT_IN_INTEGRATION_ADAPTER_IDS: readonly ("discord" | "email" | "google-docs" | "microsoft-teams" | "slack" | "telegram" | "whatsapp")[];
|
|
33
33
|
export declare function createBuiltInIntegrationAdapters(): PlatformAdapter[];
|
|
34
|
+
/**
|
|
35
|
+
* Narrow the adapter set to `integrations.platforms`, when a deployment
|
|
36
|
+
* declares one.
|
|
37
|
+
*
|
|
38
|
+
* A configured name that matches no adapter throws instead of being ignored:
|
|
39
|
+
* the whole point of the allow-list is that the operator knows which platforms
|
|
40
|
+
* are live, and silently mounting a set nobody named — or mounting nothing
|
|
41
|
+
* because of a typo — is the failure this switch is supposed to prevent.
|
|
42
|
+
*/
|
|
43
|
+
export declare function applyConfiguredPlatformAllowList(adapters: PlatformAdapter[]): PlatformAdapter[];
|
|
34
44
|
type RemoteCodeCommandEnvelope = {
|
|
35
45
|
kind?: unknown;
|
|
36
46
|
ownerEmail?: unknown;
|