@agent-native/core 0.149.5 → 0.151.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +83 -45
- package/corpus/templates/analytics/changelog/2026-08-11-analytics-dashboards-keep-the-selected-tab-when-reopened.md +6 -0
- package/corpus/templates/assets/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/brain/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/calendar/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/clips/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/clips/changelog/2026-08-11-clips-recovers-from-transient-updates-and-avoids-macos-priva.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +32 -176
- package/corpus/templates/clips/desktop/src/lib/updater.ts +52 -37
- package/corpus/templates/clips/desktop/src/styles.css +1 -166
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -0
- package/corpus/templates/clips/desktop/src-tauri/Info.plist +4 -0
- package/corpus/templates/clips/desktop/src-tauri/src/eventkit.rs +28 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +48 -1
- package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +5 -0
- package/corpus/templates/clips/server/plugins/auth.ts +3 -0
- package/corpus/templates/content/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/content/actions/_document-discovery-query.ts +127 -0
- package/corpus/templates/content/actions/list-documents.ts +189 -198
- package/corpus/templates/content/actions/search-documents.ts +95 -24
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +2 -1
- package/corpus/templates/content/app/hooks/use-documents.ts +84 -6
- package/corpus/templates/content/shared/api.ts +10 -0
- package/corpus/templates/design/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +5 -1
- package/corpus/templates/design/changelog/2026-08-11-design-agent-prompts-copy-successfully-in-the-desktop-app.md +6 -0
- package/corpus/templates/dispatch/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/dispatch/app/global.css +2 -2
- package/corpus/templates/dispatch/changelog/2026-08-10-desktop-workspace-sign-in.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-no-longer-shows-the-generic-chat-starter-among-defa.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-integrations-and-scheduled-work-open-as-first-class-electron-pages.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-sidebar-text-is-slightly-easier-to-read-in-light-and-dark-mo.md +6 -0
- package/corpus/templates/dispatch/server/lib/identity-sso.ts +57 -31
- package/corpus/templates/dispatch/server/plugins/feature-flags.ts +5 -0
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +82 -33
- package/corpus/templates/dispatch/server/plugins/org-apps-directory.ts +7 -15
- package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +9 -1
- package/corpus/templates/dispatch/shared/feature-flags.ts +15 -0
- package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/forms/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +8 -7
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/forms/app/hooks/use-forms.ts +8 -1
- package/corpus/templates/forms/changelog/2026-08-11-fixed-public-forms-so-conditional-questions-stay-hidden-unti.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +2 -1
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +37 -2
- package/corpus/templates/forms/shared/page-url.ts +54 -0
- package/corpus/templates/forms/shared/types.ts +4 -4
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/mail/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/plan/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/slides/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +5 -0
- package/corpus/templates/slides/actions/add-slide.ts +0 -27
- package/corpus/templates/slides/actions/import-file.ts +28 -9
- package/corpus/templates/slides/actions/view-screen.ts +4 -4
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +8 -1
- package/corpus/templates/slides/app/components/editor/AiEditingMarker.tsx +25 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +43 -48
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +9 -6
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -9
- package/corpus/templates/slides/app/components/editor/ImageDropPromptPopover.tsx +2 -0
- package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +0 -26
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +904 -217
- package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +11 -0
- package/corpus/templates/slides/app/components/editor/inline-edit-session.ts +16 -0
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +22 -6
- package/corpus/templates/slides/app/components/editor/style-clipboard.ts +61 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +26 -2
- package/corpus/templates/slides/app/components/ui/context-menu.tsx +1 -0
- package/corpus/templates/slides/app/context/DeckContext.tsx +75 -25
- package/corpus/templates/slides/app/global.css +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +6 -1
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
- package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +12 -12
- package/corpus/templates/slides/app/lib/slide-agent-context.ts +52 -0
- package/corpus/templates/slides/app/lib/slide-image-replacement.ts +61 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +55 -116
- package/corpus/templates/slides/app/pages/Index.tsx +28 -3
- package/corpus/templates/slides/changelog/2026-08-11-agent-chat-now-follows-the-current-slide-and-selection.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-deck-titles-now-use-slide-content-instead-of-placeholder-filenames.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-history-now-opens-from-the-deck-overflow-menu.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-images-can-be-dropped-directly-onto-slides-and-resized-or-re.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-new-decks-now-transition-directly-to-a-full-page-editor-load.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-selected-slide-layers-can-be-nudged-precisely-with-arrow-key.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-can-copy-and-paste-element-styles-with-cmd-option-c-v.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-shows-one-compact-ai-marker-and-keeps-your-current-sl.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-text-edits-preserve-slide-layout-when-no-changes-are-made.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-the-style-toolbar-now-uses-the-full-available-width.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-undo-and-redo-now-move-one-visible-slide-state-at-a-time.md +6 -0
- package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -2
- package/corpus/templates/slides/shared/deck-title.ts +56 -0
- package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/agent/run-store.js +6 -1
- package/dist/agent/thread-data-builder.js +19 -44
- package/dist/agent/types.d.ts +13 -0
- package/dist/catalog.json +1 -0
- package/dist/cli/create.js +1 -1
- package/dist/client/AssistantChat.js +58 -10
- package/dist/client/FileStorageSetupCard.d.ts +6 -0
- package/dist/client/FileStorageSetupCard.js +18 -0
- package/dist/client/NewWorkspaceAppFlow.js +10 -0
- package/dist/client/agent-chat-adapter.js +87 -11
- package/dist/client/agent-chat.d.ts +1 -1
- package/dist/client/agent-chat.js +8 -3
- package/dist/client/chat/attachment-adapters.js +10 -0
- package/dist/client/chat/message-components.d.ts +4 -1
- package/dist/client/chat/message-components.js +37 -13
- package/dist/client/chat/tool-call-display.js +14 -0
- package/dist/client/chat-first/apps-rail.d.ts +1 -1
- package/dist/client/chat-first/apps-rail.js +6 -6
- package/dist/client/chat-first/copy.js +1 -0
- package/dist/client/chat-first/types.d.ts +1 -0
- package/dist/client/extensions/EmbeddedExtension.js +1 -1
- package/dist/client/extensions/ExtensionViewer.js +1 -1
- package/dist/client/extensions/InlineExtensionFrame.js +1 -1
- package/dist/client/onboarding/FirstRunOnboarding.js +17 -2
- package/dist/client/settings/FileStorageSettingsForm.d.ts +2 -0
- package/dist/client/settings/FileStorageSettingsForm.js +113 -0
- package/dist/client/settings/SettingsPanel.js +2 -1
- package/dist/client/sse-event-processor.js +21 -0
- package/dist/extensions/actions.js +2 -2
- package/dist/extensions/html-shell.js +3 -1
- package/dist/file-upload/pre-upload-attachments.d.ts +15 -10
- package/dist/file-upload/pre-upload-attachments.js +68 -24
- package/dist/file-upload/registry.d.ts +4 -5
- package/dist/file-upload/registry.js +7 -14
- package/dist/file-upload/s3.d.ts +9 -0
- package/dist/file-upload/s3.js +168 -0
- package/dist/file-upload/types.d.ts +3 -3
- package/dist/file-upload/types.js +2 -2
- package/dist/onboarding/app-profile.js +23 -1
- package/dist/onboarding/default-steps.js +69 -0
- package/dist/onboarding/types.d.ts +2 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat/browser-team-tools.js +20 -0
- package/dist/server/agent-chat-plugin.js +12 -3
- package/dist/server/auth.js +45 -21
- package/dist/server/better-auth-instance.d.ts +2 -0
- package/dist/server/better-auth-instance.js +2 -2
- package/dist/server/core-routes-plugin.d.ts +1 -0
- package/dist/server/core-routes-plugin.js +26 -16
- package/dist/server/identity-sso-store.d.ts +3 -0
- package/dist/server/identity-sso-store.js +45 -0
- package/dist/server/identity-sso.d.ts +20 -10
- package/dist/server/identity-sso.js +79 -31
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
- package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
- package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
- package/docs/content/authentication.mdx +27 -0
- package/docs/content/cross-app-sso.mdx +38 -8
- package/docs/content/extensions.mdx +15 -15
- package/docs/content/file-uploads.mdx +10 -12
- package/docs/content/generative-ui.mdx +6 -1
- package/package.json +2 -2
- package/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +24 -1
- package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +28 -0
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -2
- package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +1 -1
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +3 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
callAction,
|
|
2
3
|
useActionQuery,
|
|
3
4
|
useActionMutation,
|
|
4
5
|
} from "@agent-native/core/client/hooks";
|
|
@@ -7,6 +8,7 @@ import type {
|
|
|
7
8
|
ContentDatabaseItem,
|
|
8
9
|
Document,
|
|
9
10
|
DocumentCreateRequest,
|
|
11
|
+
DocumentListResponse,
|
|
10
12
|
DocumentPropertiesResponse,
|
|
11
13
|
DocumentUpdateRequest,
|
|
12
14
|
DocumentUpdateResponse,
|
|
@@ -15,7 +17,7 @@ import type {
|
|
|
15
17
|
DocumentTreeNode,
|
|
16
18
|
} from "@shared/api";
|
|
17
19
|
import type { QueryClient } from "@tanstack/react-query";
|
|
18
|
-
import { useQueryClient } from "@tanstack/react-query";
|
|
20
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
19
21
|
import { toast } from "sonner";
|
|
20
22
|
|
|
21
23
|
import type { DocumentUpdateConflictResponse } from "../../actions/update-document";
|
|
@@ -63,6 +65,74 @@ export const LIST_DOCUMENTS_QUERY_KEY = [
|
|
|
63
65
|
undefined,
|
|
64
66
|
] as const;
|
|
65
67
|
|
|
68
|
+
const DOCUMENT_LIST_PAGE_SIZE = 200;
|
|
69
|
+
|
|
70
|
+
export async function fetchCompleteDocumentList(
|
|
71
|
+
fetchPage: (offset: number, limit: number) => Promise<DocumentListResponse>,
|
|
72
|
+
) {
|
|
73
|
+
const documents: Document[] = [];
|
|
74
|
+
const documentIds = new Set<string>();
|
|
75
|
+
let offset = 0;
|
|
76
|
+
let expectedTotal: number | null = null;
|
|
77
|
+
|
|
78
|
+
while (true) {
|
|
79
|
+
const page = await fetchPage(offset, DOCUMENT_LIST_PAGE_SIZE);
|
|
80
|
+
const { pagination } = page;
|
|
81
|
+
if (!pagination) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
"list-documents returned no pagination boundary; refusing to treat the result as complete.",
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (
|
|
87
|
+
pagination.offset !== offset ||
|
|
88
|
+
pagination.limit !== DOCUMENT_LIST_PAGE_SIZE ||
|
|
89
|
+
pagination.returnedItems !== page.documents.length
|
|
90
|
+
) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"list-documents returned inconsistent pagination metadata; retry the complete read.",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (expectedTotal === null) expectedTotal = pagination.totalItems;
|
|
96
|
+
if (pagination.totalItems !== expectedTotal) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
"Documents changed during paginated discovery; retry the complete read.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
for (const document of page.documents) {
|
|
102
|
+
if (documentIds.has(document.id)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`list-documents repeated document "${document.id}" across pages; refusing an ambiguous result.`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
documentIds.add(document.id);
|
|
108
|
+
documents.push(document);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const expectedNextOffset = offset + page.documents.length;
|
|
112
|
+
if (!pagination.hasMore) {
|
|
113
|
+
if (
|
|
114
|
+
pagination.nextOffset !== null ||
|
|
115
|
+
expectedNextOffset !== expectedTotal ||
|
|
116
|
+
documents.length !== expectedTotal
|
|
117
|
+
) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
"list-documents claimed exhaustion before every declared document was returned.",
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return documents;
|
|
123
|
+
}
|
|
124
|
+
if (
|
|
125
|
+
pagination.nextOffset !== expectedNextOffset ||
|
|
126
|
+
pagination.nextOffset <= offset
|
|
127
|
+
) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
"list-documents returned a non-advancing continuation; refusing a clipped result.",
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
offset = pagination.nextOffset;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
66
136
|
export function documentPropertiesQueryKey(
|
|
67
137
|
documentId: string,
|
|
68
138
|
databaseId: string,
|
|
@@ -317,11 +387,19 @@ export function seedDatabaseItemDocumentCaches(
|
|
|
317
387
|
}
|
|
318
388
|
|
|
319
389
|
export function useDocuments() {
|
|
320
|
-
return
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
390
|
+
return useQuery({
|
|
391
|
+
queryKey: LIST_DOCUMENTS_QUERY_KEY,
|
|
392
|
+
queryFn: async ({ signal }) => ({
|
|
393
|
+
documents: await fetchCompleteDocumentList((offset, limit) =>
|
|
394
|
+
callAction<DocumentListResponse>(
|
|
395
|
+
"list-documents",
|
|
396
|
+
{ offset, limit },
|
|
397
|
+
{ method: "GET", signal },
|
|
398
|
+
),
|
|
399
|
+
),
|
|
400
|
+
}),
|
|
401
|
+
select: (data) => data.documents,
|
|
402
|
+
retry: false,
|
|
325
403
|
});
|
|
326
404
|
}
|
|
327
405
|
|
|
@@ -128,6 +128,16 @@ export interface DocumentMoveRequest {
|
|
|
128
128
|
|
|
129
129
|
export interface DocumentListResponse {
|
|
130
130
|
documents: Document[];
|
|
131
|
+
pagination: DocumentDiscoveryPagination;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface DocumentDiscoveryPagination {
|
|
135
|
+
offset: number;
|
|
136
|
+
limit: number;
|
|
137
|
+
totalItems: number;
|
|
138
|
+
returnedItems: number;
|
|
139
|
+
hasMore: boolean;
|
|
140
|
+
nextOffset: number | null;
|
|
131
141
|
}
|
|
132
142
|
|
|
133
143
|
export interface DocumentTreeNode extends Document {
|
|
@@ -49,6 +49,34 @@ sendToAgentChat({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Keep user text separate from injected context
|
|
53
|
+
|
|
54
|
+
Treat the visible `message` as the user's request or the shortest clear
|
|
55
|
+
description of an app-initiated operation. Put context the user did not type —
|
|
56
|
+
IDs, URLs, filenames, current selection or screen state, serialized records,
|
|
57
|
+
upload instructions, and bounded source excerpts — in the `context` field.
|
|
58
|
+
`context` is model input carried through the agent turn; it is stripped from
|
|
59
|
+
the rendered user message, so do not concatenate it into `message` with labels,
|
|
60
|
+
blank-line sections, or `<context>` tags yourself.
|
|
61
|
+
|
|
62
|
+
Use the related surface for each kind of supporting input:
|
|
63
|
+
|
|
64
|
+
| Surface | Use for |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `message` | User-authored intent or a concise app action description |
|
|
67
|
+
| `context` | Derived metadata and bounded text needed to carry out that intent |
|
|
68
|
+
| `setAgentChatContextItem` | Context staged for a later user-submitted prompt; keep it keyed so updates replace stale context |
|
|
69
|
+
| `images`, `referenceImagePaths`, attachments | Binary or visual inputs; describe only the handling instructions in `context` |
|
|
70
|
+
|
|
71
|
+
If an app builds a prompt from a form, selection, upload, or editor state, keep
|
|
72
|
+
the visible message short and pass the assembled details as `context`. Preserve
|
|
73
|
+
the user's actual freeform text in `message` when it is the request; do not
|
|
74
|
+
restate it as metadata in `context` unless the agent needs a structured copy.
|
|
75
|
+
|
|
76
|
+
This boundary applies to auto-submitted turns and prefills. A hidden context
|
|
77
|
+
field is not a license to send unbounded records or secrets: cap excerpts,
|
|
78
|
+
prefer stable IDs and URLs, and use an action or resource lookup for full data.
|
|
79
|
+
|
|
52
80
|
**From the UI, in the background:**
|
|
53
81
|
|
|
54
82
|
```ts
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -555,9 +555,13 @@ export default function DesignSystemSetup() {
|
|
|
555
555
|
}. Present a summary for review.`,
|
|
556
556
|
);
|
|
557
557
|
|
|
558
|
+
const message =
|
|
559
|
+
parts[0] ?? "Set up a design system from the selected sources.";
|
|
560
|
+
const context = parts.slice(1).join("\n");
|
|
558
561
|
openAgentSidebar();
|
|
559
562
|
sendToDesignAgentChat({
|
|
560
|
-
message
|
|
563
|
+
message,
|
|
564
|
+
context,
|
|
561
565
|
submit: true,
|
|
562
566
|
newTab: true,
|
|
563
567
|
});
|
|
@@ -49,6 +49,34 @@ sendToAgentChat({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Keep user text separate from injected context
|
|
53
|
+
|
|
54
|
+
Treat the visible `message` as the user's request or the shortest clear
|
|
55
|
+
description of an app-initiated operation. Put context the user did not type —
|
|
56
|
+
IDs, URLs, filenames, current selection or screen state, serialized records,
|
|
57
|
+
upload instructions, and bounded source excerpts — in the `context` field.
|
|
58
|
+
`context` is model input carried through the agent turn; it is stripped from
|
|
59
|
+
the rendered user message, so do not concatenate it into `message` with labels,
|
|
60
|
+
blank-line sections, or `<context>` tags yourself.
|
|
61
|
+
|
|
62
|
+
Use the related surface for each kind of supporting input:
|
|
63
|
+
|
|
64
|
+
| Surface | Use for |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `message` | User-authored intent or a concise app action description |
|
|
67
|
+
| `context` | Derived metadata and bounded text needed to carry out that intent |
|
|
68
|
+
| `setAgentChatContextItem` | Context staged for a later user-submitted prompt; keep it keyed so updates replace stale context |
|
|
69
|
+
| `images`, `referenceImagePaths`, attachments | Binary or visual inputs; describe only the handling instructions in `context` |
|
|
70
|
+
|
|
71
|
+
If an app builds a prompt from a form, selection, upload, or editor state, keep
|
|
72
|
+
the visible message short and pass the assembled details as `context`. Preserve
|
|
73
|
+
the user's actual freeform text in `message` when it is the request; do not
|
|
74
|
+
restate it as metadata in `context` unless the agent needs a structured copy.
|
|
75
|
+
|
|
76
|
+
This boundary applies to auto-submitted turns and prefills. A hidden context
|
|
77
|
+
field is not a license to send unbounded records or secrets: cap excerpts,
|
|
78
|
+
prefer stable IDs and URLs, and use an action or resource lookup for full data.
|
|
79
|
+
|
|
52
80
|
**From the UI, in the background:**
|
|
53
81
|
|
|
54
82
|
```ts
|
|
@@ -168,6 +168,11 @@ the useful information remains dense and scannable.
|
|
|
168
168
|
- Do not build custom dropdowns, menus, popovers, modals, or confirmations with manual absolute positioning and click-outside effects.
|
|
169
169
|
- Never use browser dialogs (`window.alert`, `window.confirm`, `window.prompt`). Use `AlertDialog`, `Dialog`, or app-specific confirmation UI.
|
|
170
170
|
- Use Tabler icons for all first-party UI icons. Do not add Lucide, Heroicons, inline SVG icon sets, or emoji icons.
|
|
171
|
+
- Never guess a Tabler icon name. Names like `IconPartyPopper` or `IconConfettiCannon` feel
|
|
172
|
+
plausible but don't exist and crash Vite with a "Named export not found" error. Before importing
|
|
173
|
+
an icon you haven't used elsewhere in this app, confirm it exists by grepping
|
|
174
|
+
`node_modules/@tabler/icons-react/dist/tabler-icons-react.d.ts` (or the package's icon list)
|
|
175
|
+
for the exact name, and pick the closest real match if your first guess isn't there.
|
|
171
176
|
- Keep inline help/info glyphs next to labels at `size-3` (12px) or smaller than the adjacent text. Preserve a larger hit area on the trigger, not the glyph. Use `guard:allow-large-help-icon` only for deliberate heading documentation or menu action exceptions.
|
|
172
177
|
- Use `useActionQuery` and `useActionMutation` from `@agent-native/core/client` for action-backed UI. Standard CRUD should go through actions, not custom `/api/` routes.
|
|
173
178
|
- Keep UI optimistic where possible: update cache and navigation immediately, then reconcile or roll back on mutation result.
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
--ring: 0 0% 40%;
|
|
30
30
|
--radius: 0.5rem;
|
|
31
31
|
--sidebar-background: 0 0% 97%;
|
|
32
|
-
--sidebar-foreground: 0 0%
|
|
32
|
+
--sidebar-foreground: 0 0% 43%;
|
|
33
33
|
--sidebar-primary: 0 0% 15%;
|
|
34
34
|
--sidebar-primary-foreground: 0 0% 100%;
|
|
35
35
|
--sidebar-accent: 0 0% 95%;
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
--ring: 0 0% 60%;
|
|
61
61
|
--radius: 0.5rem;
|
|
62
62
|
--sidebar-background: 0 0% 10%;
|
|
63
|
-
--sidebar-foreground: 0 0%
|
|
63
|
+
--sidebar-foreground: 0 0% 62%;
|
|
64
64
|
--sidebar-primary: 0 0% 75%;
|
|
65
65
|
--sidebar-primary-foreground: 0 0% 10%;
|
|
66
66
|
--sidebar-accent: 0 0% 16%;
|
|
@@ -43,26 +43,30 @@ export const IDENTITY_TOKEN_TTL = "2m";
|
|
|
43
43
|
/** JWT `scope` claim marking this as an identity (login) token, not A2A/MCP. */
|
|
44
44
|
export const IDENTITY_SCOPE = "identity";
|
|
45
45
|
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
46
|
+
/** Exact first-party clients trusted to receive identity tokens. */
|
|
47
|
+
export const CANONICAL_IDENTITY_SSO_APP_ORIGINS = {
|
|
48
|
+
analytics: "https://analytics.agent-native.com",
|
|
49
|
+
assets: "https://assets.agent-native.com",
|
|
50
|
+
brain: "https://brain.agent-native.com",
|
|
51
|
+
calendar: "https://calendar.agent-native.com",
|
|
52
|
+
chat: "https://chat.agent-native.com",
|
|
53
|
+
clips: "https://clips.agent-native.com",
|
|
54
|
+
content: "https://content.agent-native.com",
|
|
55
|
+
crm: "https://crm.agent-native.com",
|
|
56
|
+
design: "https://design.agent-native.com",
|
|
57
|
+
dispatch: "https://dispatch.agent-native.com",
|
|
58
|
+
forms: "https://forms.agent-native.com",
|
|
59
|
+
macros: "https://macros.agent-native.com",
|
|
60
|
+
mail: "https://mail.agent-native.com",
|
|
61
|
+
plan: "https://plan.agent-native.com",
|
|
62
|
+
slides: "https://slides.agent-native.com",
|
|
63
|
+
tasks: "https://tasks.agent-native.com",
|
|
64
|
+
} as const;
|
|
65
|
+
|
|
66
|
+
export const DEFAULT_ALLOWED_ORIGINS: readonly string[] = Object.values(
|
|
67
|
+
CANONICAL_IDENTITY_SSO_APP_ORIGINS,
|
|
68
|
+
);
|
|
69
|
+
const IDENTITY_SSO_CALLBACK_PATH = "/_agent-native/identity/callback";
|
|
66
70
|
|
|
67
71
|
/** Loopback hosts allowed for local development of the client side. */
|
|
68
72
|
const LOCALHOST_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
|
|
@@ -102,14 +106,11 @@ export function getConfiguredHostSuffixes(
|
|
|
102
106
|
* `http:` is also allowed (TLS is not available on localhost).
|
|
103
107
|
* 3. It has no embedded credentials (`user:pass@host`) — those are an
|
|
104
108
|
* open-redirect obfuscation vector.
|
|
105
|
-
* 4. Its
|
|
106
|
-
*
|
|
107
|
-
* configured via env). The suffix is matched against the FULL parsed
|
|
108
|
-
* hostname with a leading dot, so `agent-native.com.evil.com` is
|
|
109
|
-
* rejected (ends in `.evil.com`) and substring spoofs cannot pass.
|
|
109
|
+
* 4. Its origin is an exact registered first-party app, a loopback host,
|
|
110
|
+
* or an operator-configured extra host suffix.
|
|
110
111
|
*
|
|
111
|
-
* Everything else is rejected.
|
|
112
|
-
*
|
|
112
|
+
* Everything else is rejected. The authorize endpoint adds a second check
|
|
113
|
+
* that binds the app id to the exact origin and callback path.
|
|
113
114
|
*/
|
|
114
115
|
export function isAllowedRedirectUri(
|
|
115
116
|
rawRedirectUri: unknown,
|
|
@@ -145,10 +146,9 @@ export function isAllowedRedirectUri(
|
|
|
145
146
|
|
|
146
147
|
if (isLoopback) return true;
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
];
|
|
149
|
+
if (DEFAULT_ALLOWED_ORIGINS.includes(url.origin)) return true;
|
|
150
|
+
|
|
151
|
+
const suffixes = options.allowedHostSuffixes ?? getConfiguredHostSuffixes();
|
|
152
152
|
|
|
153
153
|
// Suffix match against the full hostname, leading-dot anchored so a
|
|
154
154
|
// sibling/parent host can never satisfy a child's suffix:
|
|
@@ -158,6 +158,32 @@ export function isAllowedRedirectUri(
|
|
|
158
158
|
return suffixes.some((suffix) => hostname.endsWith(suffix));
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
const APP_ID = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
162
|
+
|
|
163
|
+
export function isAllowedIdentityRedirect(
|
|
164
|
+
appId: unknown,
|
|
165
|
+
rawRedirectUri: unknown,
|
|
166
|
+
options: { allowedHostSuffixes?: readonly string[] } = {},
|
|
167
|
+
): boolean {
|
|
168
|
+
if (typeof appId !== "string" || !APP_ID.test(appId)) return false;
|
|
169
|
+
if (!isAllowedRedirectUri(rawRedirectUri, options)) return false;
|
|
170
|
+
|
|
171
|
+
const url = new URL(rawRedirectUri as string);
|
|
172
|
+
if (url.pathname !== IDENTITY_SSO_CALLBACK_PATH || url.search || url.hash) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (DEFAULT_ALLOWED_ORIGINS.includes(url.origin)) {
|
|
177
|
+
return (
|
|
178
|
+
CANONICAL_IDENTITY_SSO_APP_ORIGINS[
|
|
179
|
+
appId as keyof typeof CANONICAL_IDENTITY_SSO_APP_ORIGINS
|
|
180
|
+
] === url.origin
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
|
|
161
187
|
export interface IdentityClaims {
|
|
162
188
|
/** Stable user identifier — the Dispatch account email. */
|
|
163
189
|
sub: string;
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* unauthenticated visitor here with:
|
|
9
9
|
* ?app=<id>&redirect_uri=<https url>&state=<opaque>
|
|
10
10
|
*
|
|
11
|
-
* 2. We
|
|
12
|
-
* (`
|
|
11
|
+
* 2. We bind `app` and `redirect_uri` against the strict allowlist
|
|
12
|
+
* (`isAllowedIdentityRedirect`). An invalid/forbidden pair is rejected
|
|
13
13
|
* with 400 BEFORE any session work — an attacker-controlled
|
|
14
14
|
* `redirect_uri` must never receive a token. This is the single most
|
|
15
15
|
* important control on this endpoint.
|
|
@@ -49,42 +49,40 @@
|
|
|
49
49
|
* This is documented as the chosen trade-off.
|
|
50
50
|
*
|
|
51
51
|
* Auth-guard reachability:
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* `publicPath` via a second `createAuthPlugin({ publicPaths })` call.
|
|
56
|
-
* When two `createAuthPlugin` calls run in the same server boot on the
|
|
57
|
-
* same Nitro app, the framework APPENDS publicPaths to the live guard
|
|
58
|
-
* config (it does not clobber Dispatch's googleOnly/marketing/onboarding
|
|
59
|
-
* — verified in packages/core/src/server/auth.ts). The path is matched
|
|
60
|
-
* exactly (or as a `/`-segment prefix), so ONLY the authorize endpoint
|
|
61
|
-
* becomes public; any future `/_agent-native/identity/*` route stays
|
|
62
|
-
* protected. The handler then resolves the session ITSELF (exactly the
|
|
63
|
-
* `/_agent-native/open` pattern) — public-path only means "guard does not
|
|
64
|
-
* pre-empt", not "no auth": logged-out users are still bounced to login,
|
|
65
|
-
* and a token is only minted for a real session.
|
|
52
|
+
* Dispatch's primary auth plugin receives the exact public paths from
|
|
53
|
+
* `setupDispatch`. These handlers still resolve the session themselves;
|
|
54
|
+
* public-path only means the guard does not pre-empt the logged-out bounce.
|
|
66
55
|
*/
|
|
67
56
|
|
|
68
57
|
import { signA2AToken } from "@agent-native/core/a2a";
|
|
69
|
-
import { getOrgDomain } from "@agent-native/core/org";
|
|
70
58
|
import {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
} from "@agent-native/core/
|
|
59
|
+
getFeatureFlagRules,
|
|
60
|
+
isFeatureFlagEnabled,
|
|
61
|
+
normalizeFeatureFlagRules,
|
|
62
|
+
} from "@agent-native/core/feature-flags";
|
|
63
|
+
import { getOrgDomain } from "@agent-native/core/org";
|
|
64
|
+
import { getH3App, getSession } from "@agent-native/core/server";
|
|
75
65
|
import { signInJourney } from "@agent-native/core/shared";
|
|
76
|
-
import { defineEventHandler, getMethod } from "h3";
|
|
66
|
+
import { defineEventHandler, getHeader, getMethod } from "h3";
|
|
77
67
|
import type { H3Event } from "h3";
|
|
78
68
|
|
|
69
|
+
import { DESKTOP_WORKSPACE_SSO_FLAG } from "../../shared/feature-flags.js";
|
|
79
70
|
import {
|
|
80
71
|
IDENTITY_TOKEN_TTL,
|
|
81
72
|
buildIdentityClaims,
|
|
82
73
|
buildRedirectLocation,
|
|
83
|
-
|
|
74
|
+
isAllowedIdentityRedirect,
|
|
84
75
|
} from "../lib/identity-sso.js";
|
|
85
76
|
|
|
86
|
-
|
|
77
|
+
const AVAILABILITY_PATH = "/_agent-native/identity/availability";
|
|
87
78
|
const AUTHORIZE_PATH = "/_agent-native/identity/authorize";
|
|
79
|
+
const DESKTOP_SSO_CANARY_USER_AGENT = /AgentNativeDesktopSsoCanary\//i;
|
|
80
|
+
|
|
81
|
+
export function isDesktopWorkspaceSsoRequest(
|
|
82
|
+
userAgent: string | undefined,
|
|
83
|
+
): boolean {
|
|
84
|
+
return DESKTOP_SSO_CANARY_USER_AGENT.test(userAgent ?? "");
|
|
85
|
+
}
|
|
88
86
|
|
|
89
87
|
function getRequestUrl(event: H3Event): string {
|
|
90
88
|
return (event as any).node?.req?.url ?? (event as any).path ?? "/";
|
|
@@ -93,7 +91,10 @@ function getRequestUrl(event: H3Event): string {
|
|
|
93
91
|
function jsonResponse(body: unknown, status: number): Response {
|
|
94
92
|
return new Response(JSON.stringify(body), {
|
|
95
93
|
status,
|
|
96
|
-
headers: {
|
|
94
|
+
headers: {
|
|
95
|
+
"Cache-Control": "private, no-store",
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
},
|
|
97
98
|
});
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -118,6 +119,45 @@ async function resolveOrgDomain(
|
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
export async function canAttemptWorkspaceSso(): Promise<boolean> {
|
|
123
|
+
const stored = await getFeatureFlagRules(
|
|
124
|
+
DESKTOP_WORKSPACE_SSO_FLAG.key,
|
|
125
|
+
{},
|
|
126
|
+
).catch(() => null);
|
|
127
|
+
if (!stored) return false;
|
|
128
|
+
const rules = normalizeFeatureFlagRules(stored);
|
|
129
|
+
if (rules.mode === "off") return false;
|
|
130
|
+
if (rules.mode === "on") return true;
|
|
131
|
+
return (
|
|
132
|
+
rules.emails.length > 0 || rules.orgIds.length > 0 || rules.percentage > 0
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function isWorkspaceSsoEnabledForSession(
|
|
137
|
+
session: Awaited<ReturnType<typeof getSession>>,
|
|
138
|
+
): Promise<boolean> {
|
|
139
|
+
if (!session?.email) return false;
|
|
140
|
+
return isFeatureFlagEnabled(DESKTOP_WORKSPACE_SSO_FLAG, {
|
|
141
|
+
userEmail: session.email,
|
|
142
|
+
userKey: session.email,
|
|
143
|
+
orgId: session.orgId,
|
|
144
|
+
}).catch(() => false);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const availabilityHandler = defineEventHandler(
|
|
148
|
+
async (event: H3Event): Promise<Response> => {
|
|
149
|
+
const method = getMethod(event);
|
|
150
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
151
|
+
return jsonResponse({ error: "Method not allowed" }, 405);
|
|
152
|
+
}
|
|
153
|
+
const session = await getSession(event).catch(() => null);
|
|
154
|
+
const available = session?.email
|
|
155
|
+
? await isWorkspaceSsoEnabledForSession(session)
|
|
156
|
+
: await canAttemptWorkspaceSso();
|
|
157
|
+
return jsonResponse({ available }, 200);
|
|
158
|
+
},
|
|
159
|
+
);
|
|
160
|
+
|
|
121
161
|
const authorizeHandler = defineEventHandler(
|
|
122
162
|
async (event: H3Event): Promise<Response> => {
|
|
123
163
|
const method = getMethod(event);
|
|
@@ -134,11 +174,15 @@ const authorizeHandler = defineEventHandler(
|
|
|
134
174
|
}
|
|
135
175
|
|
|
136
176
|
const redirectUri = search.get("redirect_uri");
|
|
177
|
+
const appId = search.get("app");
|
|
137
178
|
const state = search.get("state");
|
|
179
|
+
const isDesktopRequest = isDesktopWorkspaceSsoRequest(
|
|
180
|
+
getHeader(event, "user-agent"),
|
|
181
|
+
);
|
|
138
182
|
|
|
139
183
|
// ---- Control 1: redirect_uri allowlist (BEFORE any session work) ----
|
|
140
184
|
// An attacker-supplied redirect_uri must never reach the mint path.
|
|
141
|
-
if (!
|
|
185
|
+
if (!isAllowedIdentityRedirect(appId, redirectUri)) {
|
|
142
186
|
return jsonResponse(
|
|
143
187
|
{
|
|
144
188
|
error: "invalid_redirect_uri",
|
|
@@ -150,9 +194,13 @@ const authorizeHandler = defineEventHandler(
|
|
|
150
194
|
400,
|
|
151
195
|
);
|
|
152
196
|
}
|
|
153
|
-
// Narrowed to string by
|
|
197
|
+
// Narrowed to string by isAllowedIdentityRedirect.
|
|
154
198
|
const safeRedirectUri = redirectUri as string;
|
|
155
199
|
|
|
200
|
+
if (isDesktopRequest && !(await canAttemptWorkspaceSso())) {
|
|
201
|
+
return jsonResponse({ error: "not_found" }, 404);
|
|
202
|
+
}
|
|
203
|
+
|
|
156
204
|
// ---- Resolve the EXISTING Dispatch session --------------------------
|
|
157
205
|
const session = await getSession(event).catch(() => null);
|
|
158
206
|
|
|
@@ -182,6 +230,10 @@ const authorizeHandler = defineEventHandler(
|
|
|
182
230
|
return redirect(signInHref);
|
|
183
231
|
}
|
|
184
232
|
|
|
233
|
+
if (isDesktopRequest && !(await isWorkspaceSsoEnabledForSession(session))) {
|
|
234
|
+
return jsonResponse({ error: "not_found" }, 404);
|
|
235
|
+
}
|
|
236
|
+
|
|
185
237
|
// ---- Mint the short-lived identity token ----------------------------
|
|
186
238
|
if (!process.env.A2A_SECRET) {
|
|
187
239
|
// Without a shared secret, no first-party app could verify the token.
|
|
@@ -238,13 +290,10 @@ const authorizeHandler = defineEventHandler(
|
|
|
238
290
|
);
|
|
239
291
|
|
|
240
292
|
/**
|
|
241
|
-
* Dispatch identity-SSO plugin.
|
|
242
|
-
*
|
|
243
|
-
* logged-out bounce. The `createAuthPlugin({ publicPaths })` call is
|
|
244
|
-
* additive — it appends to the live guard config without disturbing the
|
|
245
|
-
* primary Dispatch auth plugin's googleOnly/marketing/onboarding config.
|
|
293
|
+
* Dispatch identity-SSO plugin. The primary Dispatch auth plugin owns the
|
|
294
|
+
* exact public-path registration; this plugin owns only these handlers.
|
|
246
295
|
*/
|
|
247
296
|
export default async (nitroApp: any) => {
|
|
297
|
+
getH3App(nitroApp).use(AVAILABILITY_PATH, availabilityHandler);
|
|
248
298
|
getH3App(nitroApp).use(AUTHORIZE_PATH, authorizeHandler);
|
|
249
|
-
return createAuthPlugin({ publicPaths: [AUTHORIZE_PATH] })(nitroApp);
|
|
250
299
|
};
|