@agent-native/core 0.149.6 → 0.151.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  3. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +83 -45
  4. package/corpus/templates/analytics/changelog/2026-08-11-analytics-dashboards-keep-the-selected-tab-when-reopened.md +6 -0
  5. package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  6. package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  7. package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  8. package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  9. package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  10. package/corpus/templates/clips/changelog/2026-08-11-clips-recovers-from-transient-updates-and-avoids-macos-priva.md +6 -0
  11. package/corpus/templates/clips/desktop/src/app.tsx +32 -176
  12. package/corpus/templates/clips/desktop/src/lib/updater.ts +52 -37
  13. package/corpus/templates/clips/desktop/src/styles.css +1 -166
  14. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -0
  15. package/corpus/templates/clips/desktop/src-tauri/Info.plist +4 -0
  16. package/corpus/templates/clips/desktop/src-tauri/src/eventkit.rs +28 -1
  17. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
  18. package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +48 -1
  19. package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +3 -0
  20. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +5 -0
  21. package/corpus/templates/clips/server/plugins/auth.ts +3 -0
  22. package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  23. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +2 -1
  24. package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  25. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +5 -1
  26. package/corpus/templates/design/changelog/2026-08-11-design-agent-prompts-copy-successfully-in-the-desktop-app.md +6 -0
  27. package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  28. package/corpus/templates/dispatch/app/global.css +2 -2
  29. package/corpus/templates/dispatch/changelog/2026-08-10-desktop-workspace-sign-in.md +6 -0
  30. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-no-longer-shows-the-generic-chat-starter-among-defa.md +6 -0
  31. package/corpus/templates/dispatch/changelog/2026-08-11-integrations-and-scheduled-work-open-as-first-class-electron-pages.md +6 -0
  32. package/corpus/templates/dispatch/changelog/2026-08-11-sidebar-text-is-slightly-easier-to-read-in-light-and-dark-mo.md +6 -0
  33. package/corpus/templates/dispatch/server/lib/identity-sso.ts +57 -31
  34. package/corpus/templates/dispatch/server/plugins/feature-flags.ts +5 -0
  35. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +82 -33
  36. package/corpus/templates/dispatch/server/plugins/org-apps-directory.ts +7 -15
  37. package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +9 -1
  38. package/corpus/templates/dispatch/shared/feature-flags.ts +15 -0
  39. package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  40. package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  41. package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +8 -7
  42. package/corpus/templates/forms/app/hooks/use-forms.ts +8 -1
  43. package/corpus/templates/forms/changelog/2026-08-11-fixed-public-forms-so-conditional-questions-stay-hidden-unti.md +6 -0
  44. package/corpus/templates/forms/server/handlers/submissions.ts +2 -1
  45. package/corpus/templates/forms/server/lib/public-form-ssr.ts +37 -2
  46. package/corpus/templates/forms/shared/page-url.ts +54 -0
  47. package/corpus/templates/forms/shared/types.ts +4 -4
  48. package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  49. package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  50. package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  51. package/corpus/templates/slides/actions/add-slide.ts +0 -27
  52. package/corpus/templates/slides/actions/import-file.ts +28 -9
  53. package/corpus/templates/slides/actions/view-screen.ts +4 -4
  54. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +8 -1
  55. package/corpus/templates/slides/app/components/editor/AiEditingMarker.tsx +25 -0
  56. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +43 -48
  57. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +9 -6
  58. package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -9
  59. package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +2 -0
  60. package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +0 -26
  61. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +904 -217
  62. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  63. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +11 -0
  64. package/corpus/templates/slides/app/components/editor/inline-edit-session.ts +16 -0
  65. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +22 -6
  66. package/corpus/templates/slides/app/components/editor/style-clipboard.ts +61 -0
  67. package/corpus/templates/slides/app/components/layout/Layout.tsx +26 -2
  68. package/corpus/templates/slides/app/components/ui/context-menu.tsx +1 -0
  69. package/corpus/templates/slides/app/context/DeckContext.tsx +75 -25
  70. package/corpus/templates/slides/app/global.css +1 -1
  71. package/corpus/templates/slides/app/i18n/en-US.ts +6 -1
  72. package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
  73. package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +12 -12
  74. package/corpus/templates/slides/app/lib/slide-agent-context.ts +52 -0
  75. package/corpus/templates/slides/app/lib/slide-image-replacement.ts +61 -0
  76. package/corpus/templates/slides/app/pages/DeckEditor.tsx +55 -116
  77. package/corpus/templates/slides/app/pages/Index.tsx +28 -3
  78. package/corpus/templates/slides/changelog/2026-08-11-agent-chat-now-follows-the-current-slide-and-selection.md +6 -0
  79. package/corpus/templates/slides/changelog/2026-08-11-deck-titles-now-use-slide-content-instead-of-placeholder-filenames.md +6 -0
  80. package/corpus/templates/slides/changelog/2026-08-11-history-now-opens-from-the-deck-overflow-menu.md +6 -0
  81. package/corpus/templates/slides/changelog/2026-08-11-images-can-be-dropped-directly-onto-slides-and-resized-or-re.md +6 -0
  82. package/corpus/templates/slides/changelog/2026-08-11-new-decks-now-transition-directly-to-a-full-page-editor-load.md +6 -0
  83. package/corpus/templates/slides/changelog/2026-08-11-selected-slide-layers-can-be-nudged-precisely-with-arrow-key.md +6 -0
  84. package/corpus/templates/slides/changelog/2026-08-11-slides-can-copy-and-paste-element-styles-with-cmd-option-c-v.md +6 -0
  85. package/corpus/templates/slides/changelog/2026-08-11-slides-shows-one-compact-ai-marker-and-keeps-your-current-sl.md +6 -0
  86. package/corpus/templates/slides/changelog/2026-08-11-text-edits-preserve-slide-layout-when-no-changes-are-made.md +6 -0
  87. package/corpus/templates/slides/changelog/2026-08-11-the-style-toolbar-now-uses-the-full-available-width.md +6 -0
  88. package/corpus/templates/slides/changelog/2026-08-11-undo-and-redo-now-move-one-visible-slide-state-at-a-time.md +6 -0
  89. package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -2
  90. package/corpus/templates/slides/shared/deck-title.ts +56 -0
  91. package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  92. package/dist/agent/run-store.js +6 -1
  93. package/dist/agent/thread-data-builder.js +19 -44
  94. package/dist/agent/types.d.ts +13 -0
  95. package/dist/catalog.json +1 -0
  96. package/dist/cli/create.js +1 -1
  97. package/dist/client/AssistantChat.js +58 -10
  98. package/dist/client/FileStorageSetupCard.d.ts +6 -0
  99. package/dist/client/FileStorageSetupCard.js +18 -0
  100. package/dist/client/NewWorkspaceAppFlow.js +10 -0
  101. package/dist/client/agent-chat-adapter.js +87 -11
  102. package/dist/client/agent-chat.d.ts +1 -1
  103. package/dist/client/agent-chat.js +8 -3
  104. package/dist/client/chat/attachment-adapters.js +10 -0
  105. package/dist/client/chat/message-components.d.ts +4 -1
  106. package/dist/client/chat/message-components.js +37 -13
  107. package/dist/client/chat/tool-call-display.js +14 -0
  108. package/dist/client/chat-first/apps-rail.d.ts +1 -1
  109. package/dist/client/chat-first/apps-rail.js +6 -6
  110. package/dist/client/chat-first/copy.js +1 -0
  111. package/dist/client/chat-first/types.d.ts +1 -0
  112. package/dist/client/extensions/EmbeddedExtension.js +1 -1
  113. package/dist/client/extensions/ExtensionViewer.js +1 -1
  114. package/dist/client/extensions/InlineExtensionFrame.js +1 -1
  115. package/dist/client/onboarding/FirstRunOnboarding.js +17 -2
  116. package/dist/client/settings/FileStorageSettingsForm.d.ts +2 -0
  117. package/dist/client/settings/FileStorageSettingsForm.js +113 -0
  118. package/dist/client/settings/SettingsPanel.js +2 -1
  119. package/dist/client/sse-event-processor.js +21 -0
  120. package/dist/collab/struct-routes.d.ts +1 -1
  121. package/dist/extensions/actions.js +2 -2
  122. package/dist/extensions/html-shell.js +3 -1
  123. package/dist/file-upload/pre-upload-attachments.d.ts +15 -10
  124. package/dist/file-upload/pre-upload-attachments.js +68 -24
  125. package/dist/file-upload/registry.d.ts +4 -5
  126. package/dist/file-upload/registry.js +7 -14
  127. package/dist/file-upload/s3.d.ts +9 -0
  128. package/dist/file-upload/s3.js +168 -0
  129. package/dist/file-upload/types.d.ts +3 -3
  130. package/dist/file-upload/types.js +2 -2
  131. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  132. package/dist/notifications/routes.d.ts +3 -3
  133. package/dist/onboarding/app-profile.js +23 -1
  134. package/dist/onboarding/default-steps.js +69 -0
  135. package/dist/onboarding/types.d.ts +2 -0
  136. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  137. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  138. package/dist/secrets/routes.d.ts +3 -3
  139. package/dist/server/agent-chat/browser-team-tools.js +20 -0
  140. package/dist/server/agent-chat-plugin.js +12 -3
  141. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  142. package/dist/server/auth.js +45 -21
  143. package/dist/server/better-auth-instance.d.ts +2 -0
  144. package/dist/server/better-auth-instance.js +2 -2
  145. package/dist/server/core-routes-plugin.d.ts +1 -0
  146. package/dist/server/core-routes-plugin.js +26 -16
  147. package/dist/server/identity-sso-store.d.ts +3 -0
  148. package/dist/server/identity-sso-store.js +45 -0
  149. package/dist/server/identity-sso.d.ts +20 -10
  150. package/dist/server/identity-sso.js +79 -31
  151. package/dist/server/index.d.ts +1 -1
  152. package/dist/server/index.js +1 -1
  153. package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  154. package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  155. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
  156. package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  157. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
  158. package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
  159. package/dist/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
  160. package/docs/content/authentication.mdx +27 -0
  161. package/docs/content/cross-app-sso.mdx +38 -8
  162. package/docs/content/extensions.mdx +15 -15
  163. package/docs/content/file-uploads.mdx +10 -12
  164. package/docs/content/generative-ui.mdx +6 -1
  165. package/docs/content/key-concepts.mdx +141 -83
  166. package/package.json +2 -2
  167. package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  168. package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  169. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
  170. package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
  171. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
  172. package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
  173. package/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
@@ -14,6 +14,15 @@ const DESIGN_SYSTEM_INTELLIGENCE_CAPABILITY = {
14
14
  keySummary: "Builder Design System Intelligence",
15
15
  why: "Uses your brand and design-system guidance to keep generated work on brand.",
16
16
  };
17
+ const FILE_UPLOAD_STORAGE_CAPABILITY = {
18
+ id: "file-storage",
19
+ label: "File uploads and storage",
20
+ required: false,
21
+ suggested: true,
22
+ builderIncluded: true,
23
+ keySummary: "Builder file storage or an S3-compatible bucket, credentials, and public base URL",
24
+ why: "Uploaded images and files need durable object storage so the agent can reuse them throughout a thread.",
25
+ };
17
26
  const PROFILES = {
18
27
  analytics: {
19
28
  appId: "analytics",
@@ -381,8 +390,21 @@ export function resolveOnboardingAppId(explicit) {
381
390
  export function getOnboardingAppProfile(appId) {
382
391
  const resolvedId = resolveOnboardingAppId(appId);
383
392
  const profile = PROFILES[resolvedId] ?? FALLBACK_PROFILE;
393
+ const capabilities = profile.capabilities.some((capability) => capability.id === FILE_UPLOAD_STORAGE_CAPABILITY.id)
394
+ ? profile.capabilities.map((capability) => capability.id === FILE_UPLOAD_STORAGE_CAPABILITY.id
395
+ ? {
396
+ ...FILE_UPLOAD_STORAGE_CAPABILITY,
397
+ // Assets and other domain-specific profiles can still make
398
+ // storage required while sharing the framework-wide contract.
399
+ required: capability.required,
400
+ builderIncluded: capability.builderIncluded,
401
+ }
402
+ : { ...capability })
403
+ : profile.capabilities.flatMap((capability, index) => index === 0
404
+ ? [{ ...capability }, { ...FILE_UPLOAD_STORAGE_CAPABILITY }]
405
+ : [{ ...capability }]);
384
406
  return {
385
407
  ...profile,
386
- capabilities: profile.capabilities.map((capability) => ({ ...capability })),
408
+ capabilities,
387
409
  };
388
410
  }
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { PROVIDER_ENV_META, PROVIDER_ENV_VARS, } from "../agent/engine/provider-env-vars.js";
9
9
  import { detectEngineFromUserSecrets, isAgentEngineSettingConfigured, } from "../agent/engine/registry.js";
10
+ import { getActiveFileUploadProviderForRequest, registerFileUploadProvider, } from "../file-upload/registry.js";
11
+ import { s3FileUploadProvider } from "../file-upload/s3.js";
10
12
  import { canUseDeployCredentialFallbackForRequest, readDeployCredentialEnv, resolveSecret, } from "../server/credential-provider.js";
11
13
  import { getSetting } from "../settings/store.js";
12
14
  import { registerOnboardingStep } from "./registry.js";
@@ -374,13 +376,80 @@ const githubRepositoryStep = {
374
376
  readDeployCredentialEnv("GH_TOKEN"));
375
377
  },
376
378
  };
379
+ const fileStorageStep = {
380
+ id: "file-storage",
381
+ order: 15,
382
+ required: false,
383
+ title: "File uploads and storage",
384
+ description: "Keep uploaded images and files available throughout the thread with Builder or S3-compatible object storage.",
385
+ methods: [
386
+ {
387
+ id: "builder",
388
+ kind: "builder-cli-auth",
389
+ label: "Connect Builder",
390
+ description: "Builder includes managed file storage alongside its AI connection.",
391
+ primary: true,
392
+ badge: "free",
393
+ payload: { scope: "llm" },
394
+ },
395
+ {
396
+ id: "s3",
397
+ kind: "form",
398
+ label: "Use custom storage keys",
399
+ description: "Connect AWS S3, Cloudflare R2, MinIO, or another S3-compatible bucket with a stable public base URL.",
400
+ payload: {
401
+ writeScope: "workspace",
402
+ saveTo: "scoped-secrets",
403
+ secretDescription: "S3-compatible object storage for file uploads",
404
+ fields: [
405
+ {
406
+ key: "S3_ENDPOINT",
407
+ label: "Endpoint URL",
408
+ placeholder: "https://s3.us-east-1.amazonaws.com",
409
+ },
410
+ {
411
+ key: "S3_BUCKET",
412
+ label: "Bucket name",
413
+ placeholder: "my-uploads-bucket",
414
+ },
415
+ {
416
+ key: "S3_ACCESS_KEY_ID",
417
+ label: "Access key ID",
418
+ placeholder: "AKIA...",
419
+ },
420
+ {
421
+ key: "S3_SECRET_ACCESS_KEY",
422
+ label: "Secret access key",
423
+ secret: true,
424
+ },
425
+ {
426
+ key: "S3_REGION",
427
+ label: "Region",
428
+ placeholder: "auto",
429
+ },
430
+ {
431
+ key: "S3_PUBLIC_BASE_URL",
432
+ label: "Public base URL",
433
+ placeholder: "https://cdn.example.com",
434
+ },
435
+ ],
436
+ },
437
+ },
438
+ ],
439
+ isComplete: async () => (await getActiveFileUploadProviderForRequest()) !== null,
440
+ };
377
441
  let registered = false;
378
442
  /** Idempotent. Safe to call from every plugin-mount call. */
379
443
  export function registerDefaultOnboardingSteps() {
380
444
  if (registered)
381
445
  return;
382
446
  registered = true;
447
+ // The framework provides a generic S3/R2 implementation for the custom-key
448
+ // onboarding path. Templates may replace the same provider id with a
449
+ // domain-specific implementation after this default plugin mounts.
450
+ registerFileUploadProvider(s3FileUploadProvider);
383
451
  registerOnboardingStep(llmStep);
452
+ registerOnboardingStep(fileStorageStep);
384
453
  registerOnboardingStep(databaseStep);
385
454
  registerOnboardingStep(authStep);
386
455
  registerOnboardingStep(emailStep);
@@ -91,6 +91,8 @@ export interface OnboardingCapability {
91
91
  label: string;
92
92
  /** Whether this capability blocks the app's normal setup. */
93
93
  required: boolean;
94
+ /** Show this optional capability as a recommended BYOK setup. */
95
+ suggested?: boolean;
94
96
  /** Whether Builder's managed connection covers this capability. */
95
97
  builderIncluded: boolean;
96
98
  /** Compact description of the key or connection the BYOK path needs. */
@@ -77,7 +77,7 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
77
77
  }, z.core.$strip>>, {
78
78
  id?: undefined;
79
79
  deleted?: undefined;
80
- provider?: undefined;
80
+ message?: undefined;
81
81
  providers: {
82
82
  id: string;
83
83
  label: string;
@@ -88,45 +88,45 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
88
88
  updatedAt: number;
89
89
  }[];
90
90
  count: number;
91
+ provider?: undefined;
91
92
  found?: undefined;
92
93
  registered?: undefined;
93
94
  label?: undefined;
94
- message?: undefined;
95
95
  } | {
96
+ count?: undefined;
96
97
  id?: undefined;
97
98
  deleted?: undefined;
98
- count?: undefined;
99
+ message?: undefined;
99
100
  providers?: undefined;
100
101
  found: boolean;
101
102
  provider: import("../custom-registry.js").CustomProviderConfig;
102
103
  registered?: undefined;
103
104
  label?: undefined;
104
- message?: undefined;
105
105
  } | {
106
- deleted?: undefined;
107
106
  count?: undefined;
108
- provider?: undefined;
107
+ deleted?: undefined;
108
+ message?: undefined;
109
109
  providers?: undefined;
110
+ provider?: undefined;
110
111
  found: boolean;
111
112
  id: string;
112
113
  registered?: undefined;
113
114
  label?: undefined;
114
- message?: undefined;
115
115
  } | {
116
116
  count?: undefined;
117
- provider?: undefined;
117
+ message?: undefined;
118
118
  providers?: undefined;
119
+ provider?: undefined;
119
120
  found?: undefined;
120
121
  deleted: boolean;
121
122
  id: string;
122
123
  registered?: undefined;
123
124
  label?: undefined;
124
- message?: undefined;
125
125
  } | {
126
- deleted?: undefined;
127
126
  count?: undefined;
128
- provider?: undefined;
127
+ deleted?: undefined;
129
128
  providers?: undefined;
129
+ provider?: undefined;
130
130
  found?: undefined;
131
131
  registered: boolean;
132
132
  id: string;
@@ -311,8 +311,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
311
311
  notes?: string | undefined;
312
312
  scope?: "org" | "user" | undefined;
313
313
  }, {
314
- message?: undefined;
315
314
  id?: undefined;
315
+ provider?: undefined;
316
316
  deleted?: undefined;
317
317
  providers: {
318
318
  id: string;
@@ -324,12 +324,11 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
324
324
  updatedAt: number;
325
325
  }[];
326
326
  count: number;
327
- provider?: undefined;
328
327
  found?: undefined;
329
328
  registered?: undefined;
330
329
  label?: undefined;
331
- } | {
332
330
  message?: undefined;
331
+ } | {
333
332
  count?: undefined;
334
333
  id?: undefined;
335
334
  deleted?: undefined;
@@ -338,31 +337,32 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
338
337
  provider: import("../custom-registry.js").CustomProviderConfig;
339
338
  registered?: undefined;
340
339
  label?: undefined;
341
- } | {
342
340
  message?: undefined;
341
+ } | {
343
342
  count?: undefined;
343
+ provider?: undefined;
344
344
  deleted?: undefined;
345
345
  providers?: undefined;
346
- provider?: undefined;
347
346
  found: boolean;
348
347
  id: string;
349
348
  registered?: undefined;
350
349
  label?: undefined;
351
- } | {
352
350
  message?: undefined;
351
+ } | {
353
352
  count?: undefined;
354
- providers?: undefined;
355
353
  provider?: undefined;
354
+ providers?: undefined;
356
355
  found?: undefined;
357
356
  deleted: boolean;
358
357
  id: string;
359
358
  registered?: undefined;
360
359
  label?: undefined;
360
+ message?: undefined;
361
361
  } | {
362
362
  count?: undefined;
363
+ provider?: undefined;
363
364
  deleted?: undefined;
364
365
  providers?: undefined;
365
- provider?: undefined;
366
366
  found?: undefined;
367
367
  registered: boolean;
368
368
  id: string;
@@ -34,16 +34,16 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- status?: undefined;
38
37
  ok?: undefined;
38
+ status?: undefined;
39
39
  } | {
40
40
  ok: boolean;
41
41
  status: string;
42
42
  error?: undefined;
43
43
  } | {
44
+ ok?: undefined;
44
45
  error: string;
45
46
  removed?: undefined;
46
- ok?: undefined;
47
47
  } | {
48
48
  ok: boolean;
49
49
  removed: boolean;
@@ -54,9 +54,9 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
54
54
  * or the current stored value without changing anything.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
+ ok?: undefined;
57
58
  error: string;
58
59
  note?: undefined;
59
- ok?: undefined;
60
60
  } | {
61
61
  ok: boolean;
62
62
  note?: undefined;
@@ -1,4 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { getActiveFileUploadProviderForRequest } from "../../file-upload/registry.js";
2
3
  import { areBuiltinMcpCapabilitiesSupported, buildMergedConfig, setBuiltinMcpCapabilityEnabled, } from "../../mcp-client/index.js";
3
4
  import { getBuilderBrowserConnectUrlForOwner, resolveBuilderBranchProjectId, } from "../builder-browser.js";
4
5
  import { getRequestUserEmail } from "../request-context.js";
@@ -73,6 +74,25 @@ export function createBuilderBrowserTool(deps) {
73
74
  return { ok: true, enabledIds: enabledIds ?? [] };
74
75
  };
75
76
  const entries = {
77
+ "connect-file-storage": {
78
+ tool: {
79
+ description: "Render the inline file-storage setup card when an image or file attachment could not be durably uploaded. The card lets the user connect Builder for managed object storage or open the same custom-key setup used by onboarding. Call it immediately when the attachment context says storage is missing; do not ask the user to upload the file again.",
80
+ parameters: {
81
+ type: "object",
82
+ properties: {},
83
+ },
84
+ },
85
+ run: async () => {
86
+ const activeProvider = await getActiveFileUploadProviderForRequest();
87
+ const ownerEmail = deps.getOwner?.() ?? getRequestUserEmail();
88
+ return JSON.stringify({
89
+ kind: "connect-file-storage-card",
90
+ configured: !!activeProvider,
91
+ provider: activeProvider?.name ?? null,
92
+ connectUrl: getBuilderBrowserConnectUrlForOwner(deps.getOrigin(), ownerEmail),
93
+ });
94
+ },
95
+ },
76
96
  "connect-builder": {
77
97
  tool: {
78
98
  description: `Render a Builder.io card inline in the chat. Call this as the first step (no code exploration or planning needed) when the user asks to modify the APP'S OWN SOURCE CODE: add a feature, change the UI chrome, edit a React component, add a route, add an integration, fix a bug in the app itself, or anything else that requires source-file edits while in hosted/production mode. ${extensionRequestGuidance}Do NOT call this for content the app is meant to produce — creating a video, generating a design, drafting an email, building a slide deck, making a dashboard, etc. — those run through the app's own domain actions, not Builder. Do NOT mention 'click Send to Builder' in your response unless this card is already in the conversation. The tool result includes \`builderEnabled\`; treat \`true\` as "Builder Cloud Agents can take the code-change handoff" and \`false\` as "this still needs a code change, but no Builder Cloud Agent can run here." If Builder is connected and Builder Cloud Agents are available, the card shows a 'Send to Builder' button that hands the work off to Builder's cloud agent and returns a branch URL. If \`builderEnabled\` is false, the card still renders but shows the code-change fallback: "This requires a code change. Edit locally or use Builder.io to edit this code in the cloud and continue customizing the app any way you like." Never tell the user to enable Builder Cloud Agents in Builder org settings or beta settings, and do not claim the Builder card has everything, is pre-loaded for handoff, or can run the cloud agent when \`builderEnabled\` is false. When you call this for a code-change request, pass the user's request verbatim as the \`prompt\` arg so the card can forward it to Builder unchanged when cloud agents are available.`,
@@ -951,9 +951,18 @@ export function createAgentChatPlugin(options) {
951
951
  const corpusToolNames = loadCorpusToolsInitially
952
952
  ? corpusToolNamesTaughtByPrompt(corpusPromptRegistry)
953
953
  : [];
954
- const effectiveInitialToolNames = corpusToolNames.length > 0
955
- ? [...new Set([...templateInitialToolNames, ...corpusToolNames])]
956
- : templateInitialToolNames;
954
+ const effectiveInitialToolNames = [
955
+ ...new Set([
956
+ ...templateInitialToolNames,
957
+ ...corpusToolNames,
958
+ // Attachment setup is a recovery action, but it must be available on
959
+ // the first request so a missing provider renders the CTA immediately
960
+ // instead of spending another turn in tool-search.
961
+ ...(browserTools["connect-file-storage"]
962
+ ? ["connect-file-storage"]
963
+ : []),
964
+ ]),
965
+ ];
957
966
  const resolveExtraContext = async (event, owner) => {
958
967
  if (!options?.extraContext)
959
968
  return "";
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
+ error?: undefined;
30
31
  ok: boolean;
31
32
  key: string;
32
33
  baseUrlKey?: string;
33
34
  scope: AgentEngineApiKeyScope;
34
- error?: undefined;
35
35
  }>>;
36
36
  export {};
@@ -55,6 +55,7 @@ import { normalizeWorkspaceAppAudience, workspaceAppAudienceFromEnv, workspaceAp
55
55
  import { isValidWorkspaceAppIdFormat } from "../shared/workspace-app-id.js";
56
56
  import { injectAnalyticsIntoHtml } from "./analytics.js";
57
57
  import { getConfiguredAppBasePath } from "./app-base-path.js";
58
+ import { getAppProductionUrl } from "./app-url.js";
58
59
  import { readAnalyticsAnonymousId, signupAttributionFromCookieHeader, } from "./attribution.js";
59
60
  import { getAuthLoginMode } from "./auth-login-mode.js";
60
61
  import { createBetterAuthSessionForEmail, ensureGoogleAuthIdentity, getBetterAuth, getBetterAuthSync, isDeployPreview, } from "./better-auth-instance.js";
@@ -64,10 +65,7 @@ import { getAllowedCorsOrigin, readCorsAllowedOrigins, } from "./cors-origins.js
64
65
  import { readDesktopSso, writeDesktopSso, clearDesktopSso, } from "./desktop-sso.js";
65
66
  import { resolveGoogleSignInCredentials } from "./google-oauth-credentials.js";
66
67
  import { isElectron as isElectronRequest, getAppBasePath, getAppUrl, getOrigin, encodeOAuthState, decodeOAuthState, createOAuthSession, oauthCallbackResponse, oauthDesktopExchangePage, oauthErrorPage, resolveOAuthRedirectUri, isAllowedOAuthRedirectUri, } from "./google-oauth.js";
67
- // Pure env-read feature switch from a leaf module (no dependency back on
68
- // auth.ts), so the guard and the SSO route handler share one validator and
69
- // can never disagree about whether federated SSO is enabled.
70
- import { isIdentitySsoEnabled } from "./identity-sso-store.js";
68
+ import { isCanonicalAgentNativeAppRequest, isDesktopSsoCanaryUserAgent, isIdentitySsoEnabled, } from "./identity-sso-store.js";
71
69
  import { ensureCanonicalUserForLegacySession } from "./legacy-auth-migration.js";
72
70
  import { safeOAuthReturnUrl } from "./oauth-return-url.js";
73
71
  import { getOnboardingHtml, getResetPasswordHtml, } from "./onboarding-html.js";
@@ -312,6 +310,23 @@ export function isDevEnvironment() {
312
310
  export function safeReturnPath(raw) {
313
311
  return normalizeAppPath(raw) ?? "/";
314
312
  }
313
+ // Better Auth's relative callback validator is stricter than normalizeAppPath:
314
+ // query values such as UTM labels may contain characters that are safe here but
315
+ // invalid as a Better Auth relative callback. Promote those paths to the
316
+ // canonical app origin so the callback remains same-origin and valid there.
317
+ const BETTER_AUTH_RELATIVE_CALLBACK_PATH_RE = /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/i;
318
+ function betterAuthCallbackURL(raw, forceAbsolute = false, event) {
319
+ const safePath = safeReturnPath(raw);
320
+ if (!forceAbsolute && BETTER_AUTH_RELATIVE_CALLBACK_PATH_RE.test(safePath)) {
321
+ return safePath;
322
+ }
323
+ try {
324
+ return new URL(safePath, getAppProductionUrl(event)).toString();
325
+ }
326
+ catch {
327
+ return "/";
328
+ }
329
+ }
315
330
  /**
316
331
  * Return the configured login HTML for this request, or `null` when no auth
317
332
  * guard is installed. Used by the `/_agent-native/open` deep-link route to
@@ -1693,13 +1708,16 @@ function createAuthGuardFn() {
1693
1708
  // definition, NOT yet signed in to THIS app) must bypass the blanket
1694
1709
  // 401-for-/_agent-native/*: they resolve / mint the browser session
1695
1710
  // themselves and verify a signature-bound, single-use, CSRF-stated
1696
- // hub token — not a cookie. This bypass is GATED on the opt-in env var
1697
- // so an unset `AGENT_NATIVE_IDENTITY_HUB_URL` is a true no-op (the
1698
- // guard's behaviour is byte-for-byte unchanged when SSO is off). The
1699
- // handler itself 404s when disabled as defence in depth.
1700
- if (isIdentitySsoEnabled() &&
1701
- (p === "/_agent-native/identity/login" ||
1702
- p === "/_agent-native/identity/callback")) {
1711
+ // hub token — not a cookie. The handler fails closed with 404 unless
1712
+ // direct web SSO is configured or this is the packaged SSO Canary on a
1713
+ // canonical app origin. Keeping the bypass exact lets that request-scoped
1714
+ // decision happen without exposing any other identity subpath.
1715
+ const isIdentitySsoEntryPath = p === "/_agent-native/identity/login" ||
1716
+ p === "/_agent-native/identity/callback";
1717
+ const isDesktopCanaryIdentityRequest = isDesktopSsoCanaryUserAgent(getHeader(event, "user-agent")) &&
1718
+ isCanonicalAgentNativeAppRequest(getHeader(event, "host"), getHeader(event, "x-forwarded-proto"));
1719
+ if (isIdentitySsoEntryPath &&
1720
+ (isIdentitySsoEnabled() || isDesktopCanaryIdentityRequest)) {
1703
1721
  return;
1704
1722
  }
1705
1723
  // Internal processor endpoint for the A2A async-mode fanout. Mirrors the
@@ -2971,6 +2989,7 @@ async function mountBetterAuthRoutes(app, options) {
2971
2989
  // need for a separate "Connect Google" page.
2972
2990
  const betterAuthConfig = {
2973
2991
  ...(options.betterAuth ?? {}),
2992
+ ...(options.maxAge !== undefined ? { sessionMaxAge: options.maxAge } : {}),
2974
2993
  ...(options.googleScopes ? { googleScopes: options.googleScopes } : {}),
2975
2994
  };
2976
2995
  const auth = await getBetterAuth(betterAuthConfig);
@@ -3046,10 +3065,13 @@ async function mountBetterAuthRoutes(app, options) {
3046
3065
  }
3047
3066
  }
3048
3067
  // The signup wrapper sanitizes callbackURL before calling Better Auth,
3049
- // but the resend endpoint is exposed directly so users can request a
3050
- // fresh link while unauthenticated. Keep that path equally strict:
3051
- // only same-origin relative return paths survive into the email.
3052
- if (isSendVerificationEmail || isMagicLinkRequest) {
3068
+ // but the direct email and magic-link endpoints are also reachable from
3069
+ // the browser. Keep every callback path valid for Better Auth's own
3070
+ // stricter relative URL validator before it is embedded in an email.
3071
+ if (isSendVerificationEmail ||
3072
+ isMagicLinkRequest ||
3073
+ reqPath.includes("/sign-up/email") ||
3074
+ reqPath.includes("/sign-in/email")) {
3053
3075
  try {
3054
3076
  const body = (await authRequest
3055
3077
  .clone()
@@ -3064,7 +3086,7 @@ async function mountBetterAuthRoutes(app, options) {
3064
3086
  for (const key of callbackKeys) {
3065
3087
  if (typeof body[key] !== "string")
3066
3088
  continue;
3067
- const callbackURL = safeReturnPath(body[key]);
3089
+ const callbackURL = betterAuthCallbackURL(body[key], false, event);
3068
3090
  if (callbackURL !== body[key]) {
3069
3091
  sanitizedBody[key] = callbackURL;
3070
3092
  changed = true;
@@ -3273,7 +3295,7 @@ async function mountBetterAuthRoutes(app, options) {
3273
3295
  const body = await readBody(event);
3274
3296
  const rawEmail = typeof body?.email === "string" ? body.email : "";
3275
3297
  const email = normalizeAuthEmail(rawEmail);
3276
- let callbackURL = typeof body?.callbackURL === "string"
3298
+ let callbackPath = typeof body?.callbackURL === "string"
3277
3299
  ? safeReturnPath(body.callbackURL)
3278
3300
  : "/";
3279
3301
  let desktopFlow;
@@ -3286,15 +3308,17 @@ async function mountBetterAuthRoutes(app, options) {
3286
3308
  return { error: GOOGLE_AUTH_REQUIRED_MESSAGE };
3287
3309
  }
3288
3310
  try {
3289
- if (isDesktopMagicLinkCallbackPath(callbackURL)) {
3311
+ if (isDesktopMagicLinkCallbackPath(callbackPath)) {
3290
3312
  desktopFlow = await issueDesktopMagicLinkFlow();
3291
- callbackURL = withDesktopMagicLinkFlow(callbackURL, desktopFlow);
3313
+ callbackPath = withDesktopMagicLinkFlow(callbackPath, desktopFlow);
3292
3314
  }
3315
+ const callbackURL = betterAuthCallbackURL(callbackPath, false, event);
3316
+ const newUserCallbackPath = `${getAppBasePath()}/_agent-native/auth/magic-link/new-user?return=${encodeURIComponent(callbackPath)}`;
3293
3317
  await auth.api.signInMagicLink({
3294
3318
  body: {
3295
3319
  email,
3296
3320
  callbackURL,
3297
- newUserCallbackURL: `${getAppBasePath()}/_agent-native/auth/magic-link/new-user?return=${encodeURIComponent(callbackURL)}`,
3321
+ newUserCallbackURL: betterAuthCallbackURL(newUserCallbackPath, callbackURL !== callbackPath, event),
3298
3322
  },
3299
3323
  headers: event.headers,
3300
3324
  });
@@ -3323,7 +3347,7 @@ async function mountBetterAuthRoutes(app, options) {
3323
3347
  const email = normalizeAuthEmail(rawEmail);
3324
3348
  const password = body?.password;
3325
3349
  const callbackURL = typeof body?.callbackURL === "string"
3326
- ? safeReturnPath(body.callbackURL)
3350
+ ? betterAuthCallbackURL(body.callbackURL, false, event)
3327
3351
  : "/";
3328
3352
  if (!email) {
3329
3353
  setResponseStatus(event, 400);
@@ -118,6 +118,8 @@ export interface BetterAuthInstance {
118
118
  export interface BetterAuthConfig {
119
119
  /** Base path for Better Auth routes. Default: "/_agent-native/auth/ba" */
120
120
  basePath?: string;
121
+ /** Session max age in seconds. Defaults to the framework's 30-day lifetime. */
122
+ sessionMaxAge?: number;
121
123
  /** Additional social providers beyond what env vars auto-detect */
122
124
  socialProviders?: BetterAuthOptions["socialProviders"];
123
125
  /** Additional Better Auth plugins */
@@ -1048,8 +1048,8 @@ async function createBetterAuthInstance(config) {
1048
1048
  },
1049
1049
  },
1050
1050
  session: {
1051
- expiresIn: 60 * 60 * 24 * 30, // 30 days
1052
- updateAge: 60 * 60 * 24, // refresh daily
1051
+ expiresIn: config?.sessionMaxAge ?? 60 * 60 * 24 * 30,
1052
+ updateAge: Math.min(60 * 60 * 24, config?.sessionMaxAge ?? 60 * 60 * 24 * 30), // refresh daily, or sooner for short custom sessions
1053
1053
  cookieCache: {
1054
1054
  enabled: true,
1055
1055
  maxAge: 5 * 60, // 5 min cache
@@ -293,6 +293,7 @@ export declare function readLegacyCoreRouteInitSettings(readSetting?: CoreRouteS
293
293
  * their cold-start budget on legacy cleanup or best-effort table warmups.
294
294
  */
295
295
  export declare function shouldRunCoreRouteBootDatabaseWork(env?: NodeJS.ProcessEnv): boolean;
296
+ export declare function ensureS3FileUploadProvider(): void;
296
297
  export declare function createCoreRoutesPlugin(options?: CoreRoutesPluginOptions): NitroPluginDef;
297
298
  /**
298
299
  * Default core routes plugin — mount with no configuration needed.
@@ -11,7 +11,8 @@ import { mountDbAdminRoutes } from "../db-admin/routes.js";
11
11
  import { getDbExec, isProductionServerlessFunctionRuntime, } from "../db/client.js";
12
12
  import { getDatabaseRuntimeFingerprint, getRuntimeDebugFingerprint, runDatabaseSchemaHealthCheck, } from "../db/runtime-diagnostics.js";
13
13
  import { ssrfSafeFetch } from "../extensions/url-safety.js";
14
- import { uploadFile, getActiveFileUploadProviderForRequest, listFileUploadProviders, } from "../file-upload/index.js";
14
+ import { uploadFile, getActiveFileUploadProviderForRequest, listFileUploadProviders, registerFileUploadProvider, } from "../file-upload/index.js";
15
+ import { s3FileUploadProvider } from "../file-upload/s3.js";
15
16
  import { handleMcpConnect } from "../mcp/connect-route.js";
16
17
  import { handleMcpOAuth, handleMcpOAuthAuthorizationServerMetadata, handleMcpOAuthProtectedResourceMetadata, } from "../mcp/oauth-route.js";
17
18
  import { MCP_ROUTE_PREFIXES } from "../mcp/route-paths.js";
@@ -51,7 +52,6 @@ import { createGatewayAccessCheckHandler } from "./gateway-access-check.js";
51
52
  import { getAppBasePath, getOrigin } from "./google-oauth.js";
52
53
  import { createGoogleRealtimeSessionHandler } from "./google-realtime-session.js";
53
54
  import { readBody, DEFAULT_UPLOAD_MAX_FILE_BYTES, isAllowedUploadMimeType, } from "./h3-helpers.js";
54
- import { isIdentitySsoEnabled } from "./identity-sso-store.js";
55
55
  import { handleIdentitySso } from "./identity-sso.js";
56
56
  import { createOpenRouteHandler } from "./open-route.js";
57
57
  import { createPollEventsHandler } from "./poll-events.js";
@@ -889,6 +889,12 @@ function wireRouteErrorCapture(nitroApp) {
889
889
  }
890
890
  });
891
891
  }
892
+ export function ensureS3FileUploadProvider() {
893
+ if (listFileUploadProviders().some((provider) => provider.id === s3FileUploadProvider.id)) {
894
+ return;
895
+ }
896
+ registerFileUploadProvider(s3FileUploadProvider);
897
+ }
892
898
  export function createCoreRoutesPlugin(options = {}) {
893
899
  return async (nitroApp) => {
894
900
  markDefaultPluginProvided(nitroApp, "core-routes");
@@ -905,6 +911,12 @@ export function createCoreRoutesPlugin(options = {}) {
905
911
  });
906
912
  try {
907
913
  const P = FRAMEWORK_ROUTE_PREFIX;
914
+ // Keep the framework-owned S3-compatible provider available even when an
915
+ // app does not mount the optional onboarding plugin. The settings CTA and
916
+ // the upload route share this registry. An app may register its own
917
+ // provider under the conventional `s3` id, so preserve that explicit
918
+ // registration instead of replacing it during core bootstrap.
919
+ ensureS3FileUploadProvider();
908
920
  // This response is a side-effect-free static contract used by the SSR
909
921
  // shell. Mount it before optional default-plugin/bootstrap work so a
910
922
  // browser's automatic rules fetch cannot inherit the cold-start wait.
@@ -3077,22 +3089,20 @@ export function createCoreRoutesPlugin(options = {}) {
3077
3089
  }));
3078
3090
  }
3079
3091
  }
3080
- // Cross-app SSO ("Sign in with Agent-Native") — CLIENT side. Mounted
3081
- // ONLY when `AGENT_NATIVE_IDENTITY_HUB_URL` is set, so an unset env var
3082
- // means the route is never even registered: zero new surface, existing
3083
- // auth byte-for-byte unchanged. `/login` 302s to the identity hub;
3092
+ // Cross-app SSO ("Sign in with Agent-Native") — CLIENT side. `/login`
3093
+ // 302s to the identity hub;
3084
3094
  // `/callback` verifies the hub-issued A2A-signed identity JWT and JIT-
3085
3095
  // links the verified email into this app's local Better Auth store. The
3086
- // handler 404s if disabled (defence in depth). The auth guard bypasses
3087
- // these two exact paths under the same env gate.
3088
- if (isIdentitySsoEnabled()) {
3089
- getH3App(nitroApp).use(`${P}/identity`, defineEventHandler(async (event) => {
3090
- // Framework strips the mount prefix; what remains is the subpath
3091
- // after `/identity` (e.g. `/login`, `/callback`).
3092
- const subpath = event.url?.pathname || "";
3093
- return handleIdentitySso(event, subpath);
3094
- }));
3095
- }
3096
+ // handler fails closed unless direct web SSO is configured or the
3097
+ // packaged Desktop SSO Canary requests a canonical Agent Native app.
3098
+ // Mounting the handler unconditionally lets that request-scoped decision
3099
+ // work.
3100
+ getH3App(nitroApp).use(`${P}/identity`, defineEventHandler(async (event) => {
3101
+ // Framework strips the mount prefix; what remains is the subpath
3102
+ // after `/identity` (e.g. `/login`, `/callback`).
3103
+ const subpath = event.url?.pathname || "";
3104
+ return handleIdentitySso(event, subpath);
3105
+ }));
3096
3106
  if (!options.disableOpenRoute) {
3097
3107
  // Stable deep-link route. External agents (MCP/A2A) surface
3098
3108
  // `/_agent-native/open?app=…&view=…&<recordId>=…` links; this resolves
@@ -35,6 +35,9 @@ export declare function getIdentityHubUrl(): string | undefined;
35
35
  * env-unset-no-op invariant is asserted against.
36
36
  */
37
37
  export declare function isIdentitySsoEnabled(): boolean;
38
+ export declare function isDesktopSsoCanaryUserAgent(userAgent: string | undefined): boolean;
39
+ export declare function isCanonicalAgentNativeAppOrigin(origin: string | undefined): boolean;
40
+ export declare function isCanonicalAgentNativeAppRequest(host: string | undefined, forwardedProtocol: string | undefined): boolean;
38
41
  /**
39
42
  * The conditional "Sign in with Agent-Native" entry injected into the login
40
43
  * page — ONLY when the feature is enabled. Returns an empty string when