@agent-native/core 0.164.3 → 0.164.11
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 +1 -1
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +36 -47
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +3 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +18 -1
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +256 -38
- package/corpus/templates/calendar/app/hooks/use-google-auth.ts +43 -3
- package/corpus/templates/calendar/app/i18n-data.ts +120 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +113 -0
- package/corpus/templates/calendar/server/handlers/google-auth.ts +119 -3
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +1 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +12 -0
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +18 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +114 -20
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -78
- package/corpus/templates/clips/changelog/2026-08-19-clips-nightly-builds-are-available-for-trying-the-latest-upd.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-19-social-preview-video-frames.md +6 -0
- package/corpus/templates/clips/desktop/README.md +19 -4
- package/corpus/templates/clips/desktop/src/app.tsx +78 -16
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -2
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -0
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +7 -13
- package/corpus/templates/clips/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +41 -3
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/callback.get.ts +22 -1
- package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +41 -22
- package/corpus/templates/clips/shared/share-meta.ts +67 -3
- package/corpus/templates/content/actions/list-content-databases.ts +95 -1
- package/corpus/templates/content/changelog/2026-08-11-content-mutations-delegated-from-verified-slack-dms-now-use-.md +6 -0
- package/corpus/templates/content/shared/api.ts +11 -0
- package/corpus/templates/factory/AGENTS.md +1 -1
- package/corpus/templates/factory/actions/list-factory-automations.ts +4 -0
- package/corpus/templates/factory/actions/start-builder-for-item.ts +19 -17
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +100 -36
- package/corpus/templates/factory/app/i18n/en-US.ts +4 -0
- package/corpus/templates/factory/app/routes/factory.tsx +209 -46
- package/corpus/templates/factory/server/connectors/slack.ts +44 -2
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -7
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +13 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +5 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +72 -4
- package/corpus/templates/mail/actions/view-screen.ts +1 -1
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -18
- package/corpus/templates/mail/server/handlers/google-auth.ts +125 -24
- package/corpus/templates/mail/server/lib/gmail-query.ts +5 -2
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +0 -12
- package/corpus/templates/plan/changelog/2026-08-19-plan-prompts-now-guide-you-to-connect-ai-before-sending-and-.md +6 -0
- package/corpus/templates/slides/actions/approve-deck-access-request.ts +234 -0
- package/corpus/templates/slides/actions/get-deck-access-status.ts +35 -2
- package/corpus/templates/slides/actions/request-deck-access.ts +263 -64
- package/corpus/templates/slides/app/components/editor/MissingDeckAccessPane.tsx +196 -0
- package/corpus/templates/slides/app/components/editor/RequestDeckAccessDialog.tsx +101 -0
- package/corpus/templates/slides/app/hooks/use-deck-access.ts +7 -4
- package/corpus/templates/slides/app/i18n/en-US.ts +29 -6
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +147 -169
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +250 -0
- package/corpus/templates/slides/server/db/schema.ts +8 -0
- package/corpus/templates/slides/server/lib/access-request-email.ts +36 -0
- package/corpus/templates/slides/server/lib/emails.ts +26 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +7 -0
- package/corpus/templates/slides/server/plugins/db.ts +50 -0
- package/corpus/templates/slides/shared/deck-access.ts +31 -0
- package/dist/a2a/artifact-response.d.ts +50 -0
- package/dist/a2a/artifact-response.js +266 -39
- package/dist/a2a/index.d.ts +2 -0
- package/dist/a2a/index.js +1 -0
- package/dist/a2a/task-store.d.ts +1 -0
- package/dist/a2a/task-store.js +1 -1
- package/dist/agent/observational-memory/store.d.ts +1 -0
- package/dist/agent/observational-memory/store.js +1 -1
- package/dist/agent/run-store.d.ts +1 -0
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/tool-approval-store.d.ts +1 -0
- package/dist/agent/tool-approval-store.js +1 -1
- package/dist/application-state/store.d.ts +1 -0
- package/dist/application-state/store.js +1 -1
- package/dist/browser-sessions/store.d.ts +1 -0
- package/dist/browser-sessions/store.js +1 -1
- package/dist/checkpoints/store.d.ts +1 -0
- package/dist/checkpoints/store.js +1 -1
- package/dist/cli/code-agent-schedules.d.ts +11 -0
- package/dist/cli/code-agent-schedules.js +44 -5
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AssistantChat.d.ts +5 -1
- package/dist/client/AssistantChat.js +40 -6
- package/dist/client/EnvironmentBadge.d.ts +7 -13
- package/dist/client/EnvironmentBadge.js +43 -92
- package/dist/client/agent-chat/index.d.ts +1 -0
- package/dist/client/agent-chat/index.js +1 -0
- package/dist/client/agent-chat-adapter.js +76 -50
- package/dist/client/app-providers.js +4 -4
- package/dist/client/chat/message-components.d.ts +4 -0
- package/dist/client/chat/message-components.js +28 -1
- package/dist/client/chat/run-recovery.js +26 -0
- package/dist/client/chat-first/apps-rail.d.ts +1 -0
- package/dist/client/chat-first/apps-rail.js +28 -2
- package/dist/client/sse-event-processor.js +13 -8
- package/dist/client/use-active-agent-chat-run.d.ts +2 -0
- package/dist/client/use-active-agent-chat-run.js +22 -0
- package/dist/coding-tools/sandbox/executions-store.d.ts +1 -0
- package/dist/coding-tools/sandbox/executions-store.js +1 -1
- package/dist/collab/awareness-store.d.ts +1 -0
- package/dist/collab/awareness-store.js +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +1 -0
- package/dist/collab/storage.js +1 -1
- package/dist/db/client.js +3 -3
- package/dist/db/ddl-guard.js +8 -0
- package/dist/db/migration-runtime.d.ts +23 -0
- package/dist/db/migration-runtime.js +41 -0
- package/dist/db/migrations.d.ts +1 -2
- package/dist/db/migrations.js +2 -24
- package/dist/email-catalog/log.d.ts +1 -0
- package/dist/email-catalog/log.js +1 -1
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.js +1 -0
- package/dist/guards/release-schema-complete.d.ts +22 -0
- package/dist/guards/release-schema-complete.js +144 -0
- package/dist/integrations/a2a-continuations-store.d.ts +1 -0
- package/dist/integrations/a2a-continuations-store.js +1 -1
- package/dist/integrations/adapters/slack.js +58 -7
- package/dist/integrations/awaiting-input-store.d.ts +1 -0
- package/dist/integrations/awaiting-input-store.js +1 -1
- package/dist/integrations/config-store.d.ts +1 -0
- package/dist/integrations/config-store.js +1 -1
- package/dist/integrations/controls-store.d.ts +1 -0
- package/dist/integrations/controls-store.js +1 -1
- package/dist/integrations/identity-links-store.d.ts +1 -0
- package/dist/integrations/identity-links-store.js +1 -1
- package/dist/integrations/installations-store.d.ts +1 -0
- package/dist/integrations/installations-store.js +1 -1
- package/dist/integrations/remote-commands-store.d.ts +1 -0
- package/dist/integrations/remote-commands-store.js +1 -1
- package/dist/integrations/remote-devices-store.d.ts +1 -0
- package/dist/integrations/remote-devices-store.js +1 -1
- package/dist/integrations/remote-push-store.d.ts +1 -0
- package/dist/integrations/remote-push-store.js +1 -1
- package/dist/integrations/remote-run-events-store.d.ts +1 -0
- package/dist/integrations/remote-run-events-store.js +1 -1
- package/dist/integrations/scope-store.d.ts +1 -0
- package/dist/integrations/scope-store.js +1 -1
- package/dist/integrations/thread-mapping-store.d.ts +1 -0
- package/dist/integrations/thread-mapping-store.js +1 -1
- package/dist/integrations/usage-budget-store.d.ts +1 -0
- package/dist/integrations/usage-budget-store.js +1 -1
- package/dist/jobs/background-automation-runner.js +111 -9
- package/dist/jobs/run-history.d.ts +1 -0
- package/dist/jobs/run-history.js +1 -1
- package/dist/jobs/scheduler-health.d.ts +1 -0
- package/dist/jobs/scheduler-health.js +1 -1
- package/dist/mcp/approval-store.d.ts +1 -0
- package/dist/mcp/approval-store.js +1 -1
- package/dist/mcp/connect-store.d.ts +1 -0
- package/dist/mcp/connect-store.js +1 -1
- package/dist/mcp/oauth-store.d.ts +1 -0
- package/dist/mcp/oauth-store.js +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/notifications/store.d.ts +1 -0
- package/dist/notifications/store.js +1 -1
- package/dist/oauth-tokens/store.d.ts +1 -0
- package/dist/oauth-tokens/store.js +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/progress/store.d.ts +1 -0
- package/dist/progress/store.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +5 -5
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/provider-api/corpus-jobs-store.d.ts +1 -0
- package/dist/provider-api/corpus-jobs-store.js +1 -1
- package/dist/provider-api/custom-registry.d.ts +1 -0
- package/dist/provider-api/custom-registry.js +1 -1
- package/dist/provider-api/quota-governor.d.ts +1 -0
- package/dist/provider-api/quota-governor.js +1 -1
- package/dist/provider-api/staged-datasets-store.d.ts +1 -0
- package/dist/provider-api/staged-datasets-store.js +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/resources/store.d.ts +1 -0
- package/dist/resources/store.js +1 -1
- package/dist/scripts/dev/index.js +15 -1
- package/dist/search/index.js +3 -0
- package/dist/secrets/storage.d.ts +1 -0
- package/dist/secrets/storage.js +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +2 -1
- package/dist/server/agent-chat/action-filters-a2a.js +10 -2
- package/dist/server/agent-chat-plugin.js +71 -20
- package/dist/server/agent-teams-run-queue.d.ts +1 -0
- package/dist/server/agent-teams-run-queue.js +1 -1
- package/dist/server/auth-marketing.js +3 -1
- package/dist/server/auth.d.ts +18 -1
- package/dist/server/auth.js +370 -154
- package/dist/server/embed-session.d.ts +1 -0
- package/dist/server/embed-session.js +1 -1
- package/dist/server/google-auth-plugin.js +3 -1
- package/dist/server/google-oauth.d.ts +10 -0
- package/dist/server/google-oauth.js +25 -1
- package/dist/server/identity-sso-store.d.ts +1 -0
- package/dist/server/identity-sso-store.js +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/onboarding-html.js +200 -31
- package/dist/server/poll.d.ts +2 -0
- package/dist/server/poll.js +19 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +5 -0
- package/dist/server/release-schema.d.ts +46 -0
- package/dist/server/release-schema.js +307 -0
- package/dist/settings/store.d.ts +1 -0
- package/dist/settings/store.js +1 -1
- package/dist/shared/environment-lanes.d.ts +28 -0
- package/dist/shared/environment-lanes.js +61 -0
- package/dist/sharing/actions/share-resource.js +22 -2
- package/dist/styles/agent-native.css +17 -15
- package/dist/triggers/routes.d.ts +11 -0
- package/dist/triggers/routes.js +10 -0
- package/dist/usage/alerts-store.d.ts +1 -0
- package/dist/usage/alerts-store.js +1 -1
- package/dist/usage/store.d.ts +1 -0
- package/dist/usage/store.js +1 -1
- package/docs/content/drop-in-agent.mdx +4 -4
- package/docs/content/faq.mdx +15 -15
- package/docs/content/getting-started.mdx +173 -41
- package/docs/content/key-concepts.mdx +10 -10
- package/docs/content/using-your-agent.mdx +2 -2
- package/docs/content/what-is-agent-native.mdx +79 -228
- package/package.json +2 -2
|
@@ -748,8 +748,10 @@ const enUS = {
|
|
|
748
748
|
customEllipsis: "Custom...",
|
|
749
749
|
customRepeatGoogleCalendar:
|
|
750
750
|
"Custom repeat schedules must be edited in Google Calendar.",
|
|
751
|
+
customRecurrenceTitle: "Custom recurrence",
|
|
751
752
|
customSchedule: "Custom schedule",
|
|
752
753
|
daily: "Daily",
|
|
754
|
+
day: "day",
|
|
753
755
|
default: "Default",
|
|
754
756
|
delete: "Delete",
|
|
755
757
|
description: "Description",
|
|
@@ -800,6 +802,7 @@ const enUS = {
|
|
|
800
802
|
location: "Location",
|
|
801
803
|
meet: "Meet",
|
|
802
804
|
monthly: "Monthly",
|
|
805
|
+
month: "month",
|
|
803
806
|
newEvent: "New Event",
|
|
804
807
|
newEventLower: "New event",
|
|
805
808
|
noGuests: "No guests",
|
|
@@ -832,6 +835,13 @@ const enUS = {
|
|
|
832
835
|
recurringResponseScope: "Recurring response scope",
|
|
833
836
|
repeats: "Repeats",
|
|
834
837
|
repeat: "Repeat",
|
|
838
|
+
repeatEvery: "Repeat every",
|
|
839
|
+
repeatOn: "Repeat on",
|
|
840
|
+
ends: "Ends",
|
|
841
|
+
never: "Never",
|
|
842
|
+
on: "On",
|
|
843
|
+
after: "After",
|
|
844
|
+
occurrences: "occurrences",
|
|
835
845
|
reviewInvite: "Review Invite",
|
|
836
846
|
responseAwaitingCount: "{{count}} awaiting",
|
|
837
847
|
responseMaybeCount: "{{count}} maybe",
|
|
@@ -888,12 +898,14 @@ const enUS = {
|
|
|
888
898
|
onMonthDay: "on the {{day}}",
|
|
889
899
|
weekdaysShort: "Mon–Fri",
|
|
890
900
|
weekly: "Weekly",
|
|
901
|
+
week: "week",
|
|
891
902
|
workingFrom: "Working from",
|
|
892
903
|
workingLocation: "Working location",
|
|
893
904
|
workingLocationDesk: "Desk {{desk}}",
|
|
894
905
|
workingLocationFloor: "Floor {{floor}}",
|
|
895
906
|
workingLocationTitle: "Working location: {{location}}",
|
|
896
907
|
yearly: "Yearly",
|
|
908
|
+
year: "year",
|
|
897
909
|
zoom: "Zoom",
|
|
898
910
|
zoomAdded: "Zoom added",
|
|
899
911
|
zoomAddFailed: "Failed to add Zoom",
|
|
@@ -6141,6 +6153,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6141
6153
|
"zh-CN": {
|
|
6142
6154
|
eventForm: {
|
|
6143
6155
|
addGuest: "添加客人",
|
|
6156
|
+
customRecurrenceTitle: "自定义重复",
|
|
6157
|
+
day: "天",
|
|
6158
|
+
month: "月",
|
|
6159
|
+
repeatEvery: "每隔",
|
|
6160
|
+
repeatOn: "重复于",
|
|
6161
|
+
ends: "结束",
|
|
6162
|
+
never: "从不",
|
|
6163
|
+
on: "于",
|
|
6164
|
+
after: "之后",
|
|
6165
|
+
occurrences: "次",
|
|
6166
|
+
week: "周",
|
|
6167
|
+
year: "年",
|
|
6144
6168
|
everyTwoWeeks: "每两周",
|
|
6145
6169
|
repeat: "重复",
|
|
6146
6170
|
onDate: "于 {{date}}",
|
|
@@ -6152,6 +6176,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6152
6176
|
"es-ES": {
|
|
6153
6177
|
eventForm: {
|
|
6154
6178
|
addGuest: "Añadir invitado",
|
|
6179
|
+
customRecurrenceTitle: "Repetición personalizada",
|
|
6180
|
+
day: "día",
|
|
6181
|
+
month: "mes",
|
|
6182
|
+
repeatEvery: "Repetir cada",
|
|
6183
|
+
repeatOn: "Repetir el",
|
|
6184
|
+
ends: "Termina",
|
|
6185
|
+
never: "Nunca",
|
|
6186
|
+
on: "El",
|
|
6187
|
+
after: "Después de",
|
|
6188
|
+
occurrences: "repeticiones",
|
|
6189
|
+
week: "semana",
|
|
6190
|
+
year: "año",
|
|
6155
6191
|
everyTwoWeeks: "Cada 2 semanas",
|
|
6156
6192
|
repeat: "Repetir",
|
|
6157
6193
|
onDate: "el {{date}}",
|
|
@@ -6163,6 +6199,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6163
6199
|
"fr-FR": {
|
|
6164
6200
|
eventForm: {
|
|
6165
6201
|
addGuest: "Ajouter un invité",
|
|
6202
|
+
customRecurrenceTitle: "Répétition personnalisée",
|
|
6203
|
+
day: "jour",
|
|
6204
|
+
month: "mois",
|
|
6205
|
+
repeatEvery: "Répéter tous les",
|
|
6206
|
+
repeatOn: "Répéter le",
|
|
6207
|
+
ends: "Se termine",
|
|
6208
|
+
never: "Jamais",
|
|
6209
|
+
on: "Le",
|
|
6210
|
+
after: "Après",
|
|
6211
|
+
occurrences: "occurrences",
|
|
6212
|
+
week: "semaine",
|
|
6213
|
+
year: "an",
|
|
6166
6214
|
everyTwoWeeks: "Toutes les 2 semaines",
|
|
6167
6215
|
repeat: "Répéter",
|
|
6168
6216
|
onDate: "le {{date}}",
|
|
@@ -6174,6 +6222,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6174
6222
|
"de-DE": {
|
|
6175
6223
|
eventForm: {
|
|
6176
6224
|
addGuest: "Gast hinzufügen",
|
|
6225
|
+
customRecurrenceTitle: "Benutzerdefinierte Wiederholung",
|
|
6226
|
+
day: "Tag",
|
|
6227
|
+
month: "Monat",
|
|
6228
|
+
repeatEvery: "Wiederholen alle",
|
|
6229
|
+
repeatOn: "Wiederholen am",
|
|
6230
|
+
ends: "Endet",
|
|
6231
|
+
never: "Nie",
|
|
6232
|
+
on: "Am",
|
|
6233
|
+
after: "Nach",
|
|
6234
|
+
occurrences: "Vorkommen",
|
|
6235
|
+
week: "Woche",
|
|
6236
|
+
year: "Jahr",
|
|
6177
6237
|
everyTwoWeeks: "Alle 2 Wochen",
|
|
6178
6238
|
repeat: "Wiederholen",
|
|
6179
6239
|
onDate: "am {{date}}",
|
|
@@ -6185,6 +6245,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6185
6245
|
"ja-JP": {
|
|
6186
6246
|
eventForm: {
|
|
6187
6247
|
addGuest: "ゲストを追加",
|
|
6248
|
+
customRecurrenceTitle: "カスタム繰り返し",
|
|
6249
|
+
day: "日",
|
|
6250
|
+
month: "月",
|
|
6251
|
+
repeatEvery: "繰り返す間隔",
|
|
6252
|
+
repeatOn: "繰り返す曜日",
|
|
6253
|
+
ends: "終了",
|
|
6254
|
+
never: "なし",
|
|
6255
|
+
on: "指定日",
|
|
6256
|
+
after: "次の",
|
|
6257
|
+
occurrences: "回",
|
|
6258
|
+
week: "週",
|
|
6259
|
+
year: "年",
|
|
6188
6260
|
everyTwoWeeks: "2週間ごと",
|
|
6189
6261
|
repeat: "繰り返し",
|
|
6190
6262
|
onDate: "{{date}}",
|
|
@@ -6196,6 +6268,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6196
6268
|
"ko-KR": {
|
|
6197
6269
|
eventForm: {
|
|
6198
6270
|
addGuest: "게스트 추가",
|
|
6271
|
+
customRecurrenceTitle: "맞춤 반복",
|
|
6272
|
+
day: "일",
|
|
6273
|
+
month: "월",
|
|
6274
|
+
repeatEvery: "반복 간격",
|
|
6275
|
+
repeatOn: "반복 요일",
|
|
6276
|
+
ends: "종료",
|
|
6277
|
+
never: "안 함",
|
|
6278
|
+
on: "날짜",
|
|
6279
|
+
after: "후",
|
|
6280
|
+
occurrences: "회",
|
|
6281
|
+
week: "주",
|
|
6282
|
+
year: "년",
|
|
6199
6283
|
everyTwoWeeks: "2주마다",
|
|
6200
6284
|
repeat: "반복",
|
|
6201
6285
|
onDate: "{{date}}",
|
|
@@ -6207,6 +6291,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6207
6291
|
"pt-BR": {
|
|
6208
6292
|
eventForm: {
|
|
6209
6293
|
addGuest: "Adicionar convidado",
|
|
6294
|
+
customRecurrenceTitle: "Repetição personalizada",
|
|
6295
|
+
day: "dia",
|
|
6296
|
+
month: "mês",
|
|
6297
|
+
repeatEvery: "Repetir a cada",
|
|
6298
|
+
repeatOn: "Repetir em",
|
|
6299
|
+
ends: "Termina",
|
|
6300
|
+
never: "Nunca",
|
|
6301
|
+
on: "Em",
|
|
6302
|
+
after: "Após",
|
|
6303
|
+
occurrences: "ocorrências",
|
|
6304
|
+
week: "semana",
|
|
6305
|
+
year: "ano",
|
|
6210
6306
|
everyTwoWeeks: "A cada 2 semanas",
|
|
6211
6307
|
repeat: "Repetir",
|
|
6212
6308
|
onDate: "em {{date}}",
|
|
@@ -6218,6 +6314,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6218
6314
|
"hi-IN": {
|
|
6219
6315
|
eventForm: {
|
|
6220
6316
|
addGuest: "अतिथि जोड़ें",
|
|
6317
|
+
customRecurrenceTitle: "कस्टम दोहराव",
|
|
6318
|
+
day: "दिन",
|
|
6319
|
+
month: "महीना",
|
|
6320
|
+
repeatEvery: "हर",
|
|
6321
|
+
repeatOn: "इन दिनों दोहराएं",
|
|
6322
|
+
ends: "समाप्त",
|
|
6323
|
+
never: "कभी नहीं",
|
|
6324
|
+
on: "इस दिन",
|
|
6325
|
+
after: "के बाद",
|
|
6326
|
+
occurrences: "बार",
|
|
6327
|
+
week: "सप्ताह",
|
|
6328
|
+
year: "वर्ष",
|
|
6221
6329
|
everyTwoWeeks: "हर 2 सप्ताह",
|
|
6222
6330
|
repeat: "दोहराएं",
|
|
6223
6331
|
onDate: "{{date}} को",
|
|
@@ -6229,6 +6337,18 @@ const translatedCalendarInlineEditorLabels = {
|
|
|
6229
6337
|
"ar-SA": {
|
|
6230
6338
|
eventForm: {
|
|
6231
6339
|
addGuest: "إضافة ضيف",
|
|
6340
|
+
customRecurrenceTitle: "تكرار مخصص",
|
|
6341
|
+
day: "يوم",
|
|
6342
|
+
month: "شهر",
|
|
6343
|
+
repeatEvery: "تكرار كل",
|
|
6344
|
+
repeatOn: "تكرار في",
|
|
6345
|
+
ends: "ينتهي",
|
|
6346
|
+
never: "أبدًا",
|
|
6347
|
+
on: "في",
|
|
6348
|
+
after: "بعد",
|
|
6349
|
+
occurrences: "مرات",
|
|
6350
|
+
week: "أسبوع",
|
|
6351
|
+
year: "سنة",
|
|
6232
6352
|
everyTwoWeeks: "كل أسبوعين",
|
|
6233
6353
|
repeat: "تكرار",
|
|
6234
6354
|
onDate: "في {{date}}",
|
|
@@ -12,6 +12,18 @@ export type RecurrencePreset =
|
|
|
12
12
|
| "yearly"
|
|
13
13
|
| "custom";
|
|
14
14
|
|
|
15
|
+
export type RecurrenceUnit = "day" | "week" | "month" | "year";
|
|
16
|
+
export type RecurrenceEndMode = "never" | "date" | "count";
|
|
17
|
+
|
|
18
|
+
export interface CustomRecurrenceDraft {
|
|
19
|
+
interval: number;
|
|
20
|
+
unit: RecurrenceUnit;
|
|
21
|
+
days: string[];
|
|
22
|
+
endMode: RecurrenceEndMode;
|
|
23
|
+
endDate: string;
|
|
24
|
+
count: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
export interface ReminderDraft {
|
|
16
28
|
id: string;
|
|
17
29
|
method: ReminderMethod;
|
|
@@ -387,6 +399,107 @@ export function getRecurrencePreset(recurrence?: string[]): RecurrencePreset {
|
|
|
387
399
|
return "custom";
|
|
388
400
|
}
|
|
389
401
|
|
|
402
|
+
function recurrenceFieldValue(rule: string, key: string): string | undefined {
|
|
403
|
+
return rule.match(new RegExp(`${key}=([^;]+)`, "i"))?.[1];
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function recurrenceWeekday(startIso: string, timeZone?: string) {
|
|
407
|
+
return eventWeekdayCode(startIso, timeZone);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export function createCustomRecurrenceDraft(
|
|
411
|
+
startIso: string,
|
|
412
|
+
timeZone?: string,
|
|
413
|
+
): CustomRecurrenceDraft {
|
|
414
|
+
return {
|
|
415
|
+
interval: 1,
|
|
416
|
+
unit: "week",
|
|
417
|
+
days: [recurrenceWeekday(startIso, timeZone)],
|
|
418
|
+
endMode: "never",
|
|
419
|
+
endDate: "",
|
|
420
|
+
count: 13,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export function parseCustomRecurrence(
|
|
425
|
+
recurrence: string[] | undefined,
|
|
426
|
+
startIso: string,
|
|
427
|
+
timeZone?: string,
|
|
428
|
+
): CustomRecurrenceDraft {
|
|
429
|
+
const draft = createCustomRecurrenceDraft(startIso, timeZone);
|
|
430
|
+
const rule = recurrenceRule(recurrence);
|
|
431
|
+
if (!rule) return draft;
|
|
432
|
+
|
|
433
|
+
const freq = recurrenceFieldValue(rule, "FREQ")?.toLowerCase();
|
|
434
|
+
const unit: RecurrenceUnit =
|
|
435
|
+
freq === "daily"
|
|
436
|
+
? "day"
|
|
437
|
+
: freq === "weekly"
|
|
438
|
+
? "week"
|
|
439
|
+
: freq === "monthly"
|
|
440
|
+
? "month"
|
|
441
|
+
: freq === "yearly"
|
|
442
|
+
? "year"
|
|
443
|
+
: draft.unit;
|
|
444
|
+
const interval = Number.parseInt(
|
|
445
|
+
recurrenceFieldValue(rule, "INTERVAL") || "1",
|
|
446
|
+
10,
|
|
447
|
+
);
|
|
448
|
+
const count = Number.parseInt(
|
|
449
|
+
recurrenceFieldValue(rule, "COUNT") || String(draft.count),
|
|
450
|
+
10,
|
|
451
|
+
);
|
|
452
|
+
const until = recurrenceFieldValue(rule, "UNTIL");
|
|
453
|
+
const byDay = recurrenceFieldValue(rule, "BYDAY")
|
|
454
|
+
?.split(",")
|
|
455
|
+
.map((day) => day.replace(/^[+-]?\d+/, "").toUpperCase())
|
|
456
|
+
.filter(Boolean);
|
|
457
|
+
|
|
458
|
+
return {
|
|
459
|
+
interval: Number.isFinite(interval) ? Math.max(1, interval) : 1,
|
|
460
|
+
unit,
|
|
461
|
+
days: byDay && byDay.length > 0 ? byDay : unit === "week" ? draft.days : [],
|
|
462
|
+
endMode: until
|
|
463
|
+
? "date"
|
|
464
|
+
: recurrenceFieldValue(rule, "COUNT")
|
|
465
|
+
? "count"
|
|
466
|
+
: "never",
|
|
467
|
+
endDate:
|
|
468
|
+
until && /^\d{8}/.test(until)
|
|
469
|
+
? `${until.slice(0, 4)}-${until.slice(4, 6)}-${until.slice(6, 8)}`
|
|
470
|
+
: "",
|
|
471
|
+
count: Number.isFinite(count) ? Math.max(1, count) : draft.count,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export function buildCustomRecurrenceRules(
|
|
476
|
+
draft: CustomRecurrenceDraft,
|
|
477
|
+
): string[] {
|
|
478
|
+
const interval = Math.max(1, Math.round(draft.interval));
|
|
479
|
+
const frequency = {
|
|
480
|
+
day: "DAILY",
|
|
481
|
+
week: "WEEKLY",
|
|
482
|
+
month: "MONTHLY",
|
|
483
|
+
year: "YEARLY",
|
|
484
|
+
}[draft.unit];
|
|
485
|
+
const parts = [
|
|
486
|
+
`FREQ=${frequency}`,
|
|
487
|
+
...(interval > 1 ? [`INTERVAL=${interval}`] : []),
|
|
488
|
+
];
|
|
489
|
+
if (draft.unit === "week" && draft.days.length > 0) {
|
|
490
|
+
parts.push(`BYDAY=${draft.days.join(",")}`);
|
|
491
|
+
}
|
|
492
|
+
if (draft.unit === "month" && draft.days.length > 0) {
|
|
493
|
+
parts.push(`BYDAY=${draft.days.join(",")}`);
|
|
494
|
+
}
|
|
495
|
+
if (draft.endMode === "date" && /^\d{4}-\d{2}-\d{2}$/.test(draft.endDate)) {
|
|
496
|
+
parts.push(`UNTIL=${draft.endDate.replace(/-/g, "")}T235959Z`);
|
|
497
|
+
} else if (draft.endMode === "count") {
|
|
498
|
+
parts.push(`COUNT=${Math.max(1, Math.round(draft.count))}`);
|
|
499
|
+
}
|
|
500
|
+
return [`RRULE:${parts.join(";")}`];
|
|
501
|
+
}
|
|
502
|
+
|
|
390
503
|
export function buildRecurrenceRules(
|
|
391
504
|
preset: RecurrencePreset,
|
|
392
505
|
startIso: string,
|
|
@@ -16,6 +16,9 @@ import {
|
|
|
16
16
|
oauthCallbackResponse,
|
|
17
17
|
oauthDesktopExchangePage,
|
|
18
18
|
oauthErrorPage,
|
|
19
|
+
registerDesktopExchange,
|
|
20
|
+
prepareDesktopOAuthBrowserBinding,
|
|
21
|
+
matchesDesktopOAuthBrowserBinding,
|
|
19
22
|
setDesktopExchange,
|
|
20
23
|
setDesktopExchangeError,
|
|
21
24
|
safeReturnPath,
|
|
@@ -23,6 +26,8 @@ import {
|
|
|
23
26
|
} from "@agent-native/core/server";
|
|
24
27
|
import {
|
|
25
28
|
defineEventHandler,
|
|
29
|
+
getHeader,
|
|
30
|
+
getMethod,
|
|
26
31
|
getQuery,
|
|
27
32
|
setResponseStatus,
|
|
28
33
|
type H3Event,
|
|
@@ -55,6 +60,8 @@ type CalendarOAuthStateOptions = {
|
|
|
55
60
|
app?: string;
|
|
56
61
|
returnUrl?: string;
|
|
57
62
|
flowId?: string;
|
|
63
|
+
desktopVerifierHash?: string;
|
|
64
|
+
desktopBrowserBindingHash?: string;
|
|
58
65
|
};
|
|
59
66
|
|
|
60
67
|
function encodeCalendarOAuthState(options: CalendarOAuthStateOptions): string {
|
|
@@ -226,6 +233,7 @@ function missingCredentialsResponse(
|
|
|
226
233
|
export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
|
|
227
234
|
try {
|
|
228
235
|
const q = getQuery(event);
|
|
236
|
+
const method = getMethod(event);
|
|
229
237
|
const redirectUri = resolveOAuthRedirectUri(event);
|
|
230
238
|
if (!redirectUri) {
|
|
231
239
|
setResponseStatus(event, 400);
|
|
@@ -241,6 +249,10 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
|
|
|
241
249
|
isElectron(event) || q.desktop === "1" || q.desktop === "true";
|
|
242
250
|
const mobile = q.mobile === "1" || q.mobile === "true";
|
|
243
251
|
const flowId = desktop ? (q.flow_id as string) || undefined : undefined;
|
|
252
|
+
if (method === "POST" && (!desktop || !flowId)) {
|
|
253
|
+
setResponseStatus(event, 400);
|
|
254
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
255
|
+
}
|
|
244
256
|
const calendarConnect = isCalendarConnectRequest(q, owner);
|
|
245
257
|
const credentials = calendarConnect
|
|
246
258
|
? await resolveCalendarOAuthCredentials(event)
|
|
@@ -264,6 +276,31 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
|
|
|
264
276
|
};
|
|
265
277
|
}
|
|
266
278
|
|
|
279
|
+
let desktopVerifierHash: string | undefined;
|
|
280
|
+
let desktopBrowserBindingHash: string | undefined;
|
|
281
|
+
if (flowId) {
|
|
282
|
+
if (method !== "POST" || q.redirect !== undefined) {
|
|
283
|
+
setResponseStatus(event, 400);
|
|
284
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
285
|
+
}
|
|
286
|
+
const verifier = getHeader(event, "x-agent-native-desktop-verifier");
|
|
287
|
+
if (!verifier || q.verifier !== undefined) {
|
|
288
|
+
setResponseStatus(event, 400);
|
|
289
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
desktopBrowserBindingHash = prepareDesktopOAuthBrowserBinding(event);
|
|
293
|
+
desktopVerifierHash = await registerDesktopExchange(
|
|
294
|
+
flowId,
|
|
295
|
+
verifier,
|
|
296
|
+
desktopBrowserBindingHash,
|
|
297
|
+
);
|
|
298
|
+
} catch {
|
|
299
|
+
setResponseStatus(event, 400);
|
|
300
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
267
304
|
const requestedReturn =
|
|
268
305
|
typeof q.return === "string" ? safeReturnPath(q.return) : "/";
|
|
269
306
|
const returnUrl = requestedReturn !== "/" ? requestedReturn : undefined;
|
|
@@ -279,6 +316,8 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
|
|
|
279
316
|
app: OAUTH_STATE_APP_ID,
|
|
280
317
|
returnUrl,
|
|
281
318
|
flowId,
|
|
319
|
+
desktopVerifierHash,
|
|
320
|
+
desktopBrowserBindingHash,
|
|
282
321
|
});
|
|
283
322
|
|
|
284
323
|
const url = calendarConnect
|
|
@@ -316,6 +355,17 @@ export const handleGoogleCallback = defineEventHandler(
|
|
|
316
355
|
desktop = state.desktop ?? false;
|
|
317
356
|
mobile = state.mobile ?? false;
|
|
318
357
|
flowId = state.flowId;
|
|
358
|
+
if (
|
|
359
|
+
flowId &&
|
|
360
|
+
(!state.desktopVerifierHash ||
|
|
361
|
+
!state.desktopBrowserBindingHash ||
|
|
362
|
+
!matchesDesktopOAuthBrowserBinding(
|
|
363
|
+
event,
|
|
364
|
+
state.desktopBrowserBindingHash,
|
|
365
|
+
))
|
|
366
|
+
) {
|
|
367
|
+
throw new Error("Desktop OAuth browser binding is invalid.");
|
|
368
|
+
}
|
|
319
369
|
|
|
320
370
|
const googleError = query.error as string | undefined;
|
|
321
371
|
if (googleError) {
|
|
@@ -366,7 +416,15 @@ export const handleGoogleCallback = defineEventHandler(
|
|
|
366
416
|
);
|
|
367
417
|
|
|
368
418
|
if (flowId && sessionToken) {
|
|
369
|
-
|
|
419
|
+
if (!state.desktopVerifierHash) {
|
|
420
|
+
throw new Error("Missing desktop exchange challenge.");
|
|
421
|
+
}
|
|
422
|
+
await setDesktopExchange(
|
|
423
|
+
flowId,
|
|
424
|
+
sessionToken,
|
|
425
|
+
identity.email,
|
|
426
|
+
state.desktopVerifierHash,
|
|
427
|
+
);
|
|
370
428
|
}
|
|
371
429
|
|
|
372
430
|
return oauthCallbackResponse(event, identity.email, {
|
|
@@ -410,7 +468,15 @@ export const handleGoogleCallback = defineEventHandler(
|
|
|
410
468
|
: { sessionToken: undefined };
|
|
411
469
|
|
|
412
470
|
if (flowId && sessionToken) {
|
|
413
|
-
|
|
471
|
+
if (!state.desktopVerifierHash) {
|
|
472
|
+
throw new Error("Missing desktop exchange challenge.");
|
|
473
|
+
}
|
|
474
|
+
await setDesktopExchange(
|
|
475
|
+
flowId,
|
|
476
|
+
sessionToken,
|
|
477
|
+
sessionOwner,
|
|
478
|
+
state.desktopVerifierHash,
|
|
479
|
+
);
|
|
414
480
|
}
|
|
415
481
|
|
|
416
482
|
// 4. Return platform-appropriate response
|
|
@@ -436,10 +502,15 @@ export const getGoogleAddAccountUrl = defineEventHandler(
|
|
|
436
502
|
return { error: "Must be logged in to add an account" };
|
|
437
503
|
}
|
|
438
504
|
const q = getQuery(event);
|
|
505
|
+
const method = getMethod(event);
|
|
439
506
|
const desktop =
|
|
440
507
|
isElectron(event) || q.desktop === "1" || q.desktop === "true";
|
|
441
508
|
const mobile = q.mobile === "1" || q.mobile === "true";
|
|
442
509
|
const flowId = desktop ? (q.flow_id as string) || undefined : undefined;
|
|
510
|
+
if (method === "POST" && (!desktop || !flowId)) {
|
|
511
|
+
setResponseStatus(event, 400);
|
|
512
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
513
|
+
}
|
|
443
514
|
if (!(await resolveCalendarOAuthCredentials(event))) {
|
|
444
515
|
return missingCredentialsResponse(
|
|
445
516
|
event,
|
|
@@ -456,6 +527,30 @@ export const getGoogleAddAccountUrl = defineEventHandler(
|
|
|
456
527
|
message: "redirect_uri must stay on this app's _agent-native routes.",
|
|
457
528
|
};
|
|
458
529
|
}
|
|
530
|
+
let desktopVerifierHash: string | undefined;
|
|
531
|
+
let desktopBrowserBindingHash: string | undefined;
|
|
532
|
+
if (flowId) {
|
|
533
|
+
if (method !== "POST" || q.redirect !== undefined) {
|
|
534
|
+
setResponseStatus(event, 400);
|
|
535
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
536
|
+
}
|
|
537
|
+
const verifier = getHeader(event, "x-agent-native-desktop-verifier");
|
|
538
|
+
if (!verifier || q.verifier !== undefined) {
|
|
539
|
+
setResponseStatus(event, 400);
|
|
540
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
desktopBrowserBindingHash = prepareDesktopOAuthBrowserBinding(event);
|
|
544
|
+
desktopVerifierHash = await registerDesktopExchange(
|
|
545
|
+
flowId,
|
|
546
|
+
verifier,
|
|
547
|
+
desktopBrowserBindingHash,
|
|
548
|
+
);
|
|
549
|
+
} catch {
|
|
550
|
+
setResponseStatus(event, 400);
|
|
551
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
552
|
+
}
|
|
553
|
+
}
|
|
459
554
|
const state = encodeCalendarOAuthState({
|
|
460
555
|
redirectUri,
|
|
461
556
|
owner: session.email,
|
|
@@ -465,6 +560,8 @@ export const getGoogleAddAccountUrl = defineEventHandler(
|
|
|
465
560
|
addAccount: true,
|
|
466
561
|
app: OAUTH_STATE_APP_ID,
|
|
467
562
|
flowId,
|
|
563
|
+
desktopVerifierHash,
|
|
564
|
+
desktopBrowserBindingHash,
|
|
468
565
|
});
|
|
469
566
|
const url = await getAuthUrl(
|
|
470
567
|
undefined,
|
|
@@ -499,6 +596,17 @@ export const handleGoogleAddAccountCallback = defineEventHandler(
|
|
|
499
596
|
desktop = state.desktop ?? false;
|
|
500
597
|
mobile = state.mobile ?? false;
|
|
501
598
|
flowId = state.flowId;
|
|
599
|
+
if (
|
|
600
|
+
flowId &&
|
|
601
|
+
(!state.desktopVerifierHash ||
|
|
602
|
+
!state.desktopBrowserBindingHash ||
|
|
603
|
+
!matchesDesktopOAuthBrowserBinding(
|
|
604
|
+
event,
|
|
605
|
+
state.desktopBrowserBindingHash,
|
|
606
|
+
))
|
|
607
|
+
) {
|
|
608
|
+
throw new Error("Desktop OAuth browser binding is invalid.");
|
|
609
|
+
}
|
|
502
610
|
|
|
503
611
|
const googleError = query.error as string | undefined;
|
|
504
612
|
if (googleError) {
|
|
@@ -547,7 +655,15 @@ export const handleGoogleAddAccountCallback = defineEventHandler(
|
|
|
547
655
|
: { sessionToken: undefined };
|
|
548
656
|
|
|
549
657
|
if (flowId && sessionToken) {
|
|
550
|
-
|
|
658
|
+
if (!state.desktopVerifierHash) {
|
|
659
|
+
throw new Error("Missing desktop exchange challenge.");
|
|
660
|
+
}
|
|
661
|
+
await setDesktopExchange(
|
|
662
|
+
flowId,
|
|
663
|
+
sessionToken,
|
|
664
|
+
ownerEmail,
|
|
665
|
+
state.desktopVerifierHash,
|
|
666
|
+
);
|
|
551
667
|
}
|
|
552
668
|
|
|
553
669
|
return oauthCallbackResponse(event, addedEmail, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../../_agent-native/google/add-account/auth-url.post.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../_agent-native/google/auth-url.post.js";
|
package/corpus/templates/calendar/server/routes/_agent-native/google/add-account/auth-url.post.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getGoogleAddAccountUrl as default } from "../../../../handlers/google-auth";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getGoogleAuthUrl as default } from "../../../handlers/google-auth";
|
|
@@ -176,7 +176,7 @@ The playable Slack embed is deliberately narrower than the share page:
|
|
|
176
176
|
|
|
177
177
|
- Only `ready` recordings with `visibility === "public"` can produce a video block.
|
|
178
178
|
- Password-protected, expired, archived, trashed, private, org-only, or still-processing clips must not produce a playable Slack block.
|
|
179
|
-
- Slack thumbnails use the stored
|
|
179
|
+
- Slack thumbnails use the same-origin proxy for stored thumbnails, or a public video frame when no stored thumbnail exists; normal share-page metadata remains the fallback when no Slack app is installed.
|
|
180
180
|
- Do not put passwords, short-lived share tokens, raw provider URLs, or transcript text in Slack unfurl payloads.
|
|
181
181
|
|
|
182
182
|
Required Slack app setup:
|
|
@@ -168,6 +168,7 @@ export interface VideoPlayerHandle {
|
|
|
168
168
|
play: () => Promise<void> | void;
|
|
169
169
|
pause: () => void;
|
|
170
170
|
seek: (ms: number) => void;
|
|
171
|
+
getCurrentOriginalMs: () => number;
|
|
171
172
|
setSpeed: (rate: number) => void;
|
|
172
173
|
toggleMute: () => void;
|
|
173
174
|
toggleCaptions: () => void;
|
|
@@ -1159,6 +1160,17 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1159
1160
|
play: requestPlay,
|
|
1160
1161
|
pause: pauseVideo,
|
|
1161
1162
|
seek: seekToVisibleMs,
|
|
1163
|
+
getCurrentOriginalMs: () => {
|
|
1164
|
+
const v = videoRef.current;
|
|
1165
|
+
const liveOriginalMs =
|
|
1166
|
+
v &&
|
|
1167
|
+
Number.isFinite(v.currentTime) &&
|
|
1168
|
+
v.currentTime >= 0 &&
|
|
1169
|
+
v.currentTime < 1e7
|
|
1170
|
+
? Math.floor(v.currentTime * 1000)
|
|
1171
|
+
: currentMsRef.current;
|
|
1172
|
+
return liveOriginalMs;
|
|
1173
|
+
},
|
|
1162
1174
|
setSpeed: applySpeed,
|
|
1163
1175
|
toggleMute: () => {
|
|
1164
1176
|
if (videoRef.current) {
|
|
@@ -159,6 +159,10 @@ function dayBucket(iso: string): string {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
export function dictationsRefetchInterval(isActive: boolean): number | false {
|
|
163
|
+
return isActive ? 2_000 : false;
|
|
164
|
+
}
|
|
165
|
+
|
|
162
166
|
function sourceMeta(
|
|
163
167
|
source: string | undefined,
|
|
164
168
|
t: ReturnType<typeof useT>,
|
|
@@ -694,10 +698,6 @@ function DownloadDesktopAppCard() {
|
|
|
694
698
|
|
|
695
699
|
export default function DictateRoute() {
|
|
696
700
|
const t = useT();
|
|
697
|
-
const { data, isLoading, isError } = useActionQuery<
|
|
698
|
-
{ dictations: Dictation[] } | Dictation[] | undefined
|
|
699
|
-
>("list-dictations", {}, { retry: false });
|
|
700
|
-
|
|
701
701
|
const { isDesktopApp } = useDesktopPromo();
|
|
702
702
|
const [filter, setFilter] = useState<SourceFilter>("all");
|
|
703
703
|
const [listening, setListening] = useState(false);
|
|
@@ -706,6 +706,20 @@ export default function DictateRoute() {
|
|
|
706
706
|
const [speechSupported, setSpeechSupported] = useState(false);
|
|
707
707
|
const qc = useQueryClient();
|
|
708
708
|
const createDictation = useActionMutation("create-dictation");
|
|
709
|
+
const { data, isLoading, isError } = useActionQuery<
|
|
710
|
+
{ dictations: Dictation[] } | Dictation[] | undefined
|
|
711
|
+
>(
|
|
712
|
+
"list-dictations",
|
|
713
|
+
{},
|
|
714
|
+
{
|
|
715
|
+
retry: false,
|
|
716
|
+
// Action-backed mutations invalidate this query when a desktop-created
|
|
717
|
+
// dictation lands. Poll only while browser work is active or saving,
|
|
718
|
+
// rather than running a permanent interval over idle history.
|
|
719
|
+
refetchInterval: () =>
|
|
720
|
+
dictationsRefetchInterval(listening || createDictation.isPending),
|
|
721
|
+
},
|
|
722
|
+
);
|
|
709
723
|
|
|
710
724
|
const recognitionRef = useRef<SpeechRecognitionLike | null>(null);
|
|
711
725
|
const transcriptRef = useRef("");
|