@agent-native/core 0.80.0 → 0.80.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +16 -1
- package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +14 -1
- package/corpus/core/docs/content/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/template-design.mdx +14 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/handlers.ts +1 -1
- package/corpus/core/src/brand-kit/index.ts +1 -1
- package/corpus/core/src/cli/skills.ts +18 -0
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
- package/corpus/core/src/client/extensions/portable-extension.ts +1 -1
- package/corpus/core/src/code-agents/transcript-normalizer.ts +1 -1
- package/corpus/core/src/extensions/path.ts +1 -4
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +1 -1
- package/corpus/core/src/mcp/build-server.ts +2 -2
- package/corpus/core/src/mcp/embed-app.ts +35 -1
- package/corpus/core/src/org/handlers.ts +5 -5
- package/corpus/core/src/org/plugin.ts +2 -2
- package/corpus/core/src/scripts/call-agent.ts +1 -1
- package/corpus/core/src/scripts/db/safety.ts +1 -1
- package/corpus/core/src/server/auth.ts +3 -0
- package/corpus/core/src/server/builder-design-systems.ts +308 -0
- package/corpus/core/src/server/core-routes-plugin.ts +29 -3
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/core/src/styles/agent-native.css +14 -7
- package/corpus/core/src/usage/store.ts +2 -2
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +298 -15
- package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -4
- package/corpus/templates/analytics/actions/mutate-dashboard.ts +18 -2
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +12 -2
- package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +66 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +37 -0
- package/corpus/templates/analytics/app/i18n-data.ts +404 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +333 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +121 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +49 -26
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +137 -36
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-agents-can-now-place-new-charts-into-requested-das.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-queries-now-report-failed-source-query-errors-inst.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-charts-can-now-be-dropped-between-full-dashboard-rows-to-cre.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-dashboard-email-reports-include-the-full-dashboard-image-wit.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-main-surface-border-reaches-the-top.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-session-replay-now-records-playable-sessions-in-production-a.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-set-up-session-replay-storage-from-settings-connect-builder-.md +6 -0
- package/corpus/templates/analytics/scripts/cleanup-empty-session-recordings.ts +102 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +49 -26
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +81 -20
- package/corpus/templates/analytics/server/lib/replay-storage.ts +79 -0
- package/corpus/templates/analytics/server/lib/s3-upload-provider.ts +255 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +29 -8
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
- package/corpus/templates/analytics/server/plugins/onboarding.ts +97 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +24 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +105 -5
- package/corpus/templates/content/actions/set-image-alt-text.ts +1 -1
- package/corpus/templates/content/shared/document-export.ts +1 -1
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -18
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
- package/corpus/templates/design/actions/add-localhost-screens.ts +32 -5
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +259 -0
- package/corpus/templates/design/actions/update-file.ts +9 -2
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +33 -75
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +72 -9
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +41 -39
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1029 -249
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +450 -101
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +978 -154
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -9
- package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +133 -66
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +1234 -344
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +144 -94
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +301 -72
- package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +876 -286
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +601 -0
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +242 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +30 -7
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +212 -155
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +423 -0
- package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +487 -107
- package/corpus/templates/design/app/components/design/inspector/index.ts +27 -0
- package/corpus/templates/design/app/global.css +29 -3
- package/corpus/templates/design/app/i18n/zh-TW.ts +13 -0
- package/corpus/templates/design/app/i18n-data.ts +239 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +1023 -353
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +57 -221
- package/corpus/templates/design/changelog/2026-06-29-canvas-selection-no-longer-flashes-broken-prototype-html-whe.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-command-menu-selections-are-clearer-in-dark-mode.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-element-selection-now-stays-on-the-intended-layer-after-sele.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-full-view-controls-now-sit-above-frames-inst.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-tools-can-draw-shapes-create-screens-and-kee.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-now-creates-anchor-based-bezier-vectors-with-ha.md +6 -0
- package/corpus/templates/design/server/handlers/import-figma-system.ts +38 -85
- package/corpus/templates/design/server/lib/design-snapshot.ts +9 -1
- package/corpus/templates/design/shared/code-layer.ts +209 -9
- package/corpus/templates/design/shared/html-content.ts +21 -0
- package/corpus/templates/design/shared/pen-path.ts +207 -0
- package/corpus/templates/mail/app/lib/utils.ts +2 -2
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -10
- package/corpus/templates/slides/AGENTS.md +3 -2
- package/corpus/templates/slides/actions/import-file.ts +26 -17
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +259 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +35 -167
- package/corpus/templates/slides/app/components/design-system/fig-import-response.ts +9 -13
- package/corpus/templates/slides/app/context/DeckContext.tsx +1 -1
- package/corpus/templates/slides/app/i18n/ar-SA.ts +9 -37
- package/corpus/templates/slides/app/i18n/de-DE.ts +10 -25
- package/corpus/templates/slides/app/i18n/en-US.ts +9 -26
- package/corpus/templates/slides/app/i18n/es-ES.ts +10 -28
- package/corpus/templates/slides/app/i18n/fr-FR.ts +10 -28
- package/corpus/templates/slides/app/i18n/hi-IN.ts +9 -26
- package/corpus/templates/slides/app/i18n/ja-JP.ts +10 -22
- package/corpus/templates/slides/app/i18n/ko-KR.ts +9 -23
- package/corpus/templates/slides/app/i18n/pt-BR.ts +10 -28
- package/corpus/templates/slides/app/i18n/zh-CN.ts +9 -22
- package/corpus/templates/slides/app/i18n/zh-TW.ts +9 -22
- package/corpus/templates/slides/server/handlers/import-figma-system.ts +44 -12
- package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
- package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +1 -1
- package/dist/application-state/handlers.js +1 -1
- package/dist/application-state/handlers.js.map +1 -1
- package/dist/brand-kit/index.d.ts +1 -1
- package/dist/brand-kit/index.js +1 -1
- package/dist/brand-kit/index.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +18 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +1 -1
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/extensions/path.d.ts +1 -1
- package/dist/extensions/path.d.ts.map +1 -1
- package/dist/extensions/path.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/integrations/a2a-continuation-processor.js +1 -1
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/mcp/build-server.d.ts +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +1 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +35 -1
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +8 -8
- package/dist/org/handlers.js +5 -5
- package/dist/org/handlers.js.map +1 -1
- package/dist/org/plugin.js +2 -2
- package/dist/org/plugin.js.map +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/call-agent.js +1 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/db/safety.js +1 -1
- package/dist/scripts/db/safety.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +3 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +28 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -0
- package/dist/server/builder-design-systems.js +217 -0
- package/dist/server/builder-design-systems.js.map +1 -0
- package/dist/server/core-routes-plugin.d.ts +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +20 -3
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/styles/agent-native.css +14 -7
- package/dist/usage/store.js +2 -2
- package/dist/usage/store.js.map +1 -1
- package/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
- package/docs/content/locales/ar-SA/template-design.mdx +14 -1
- package/docs/content/locales/de-DE/skills-guide.mdx +5 -0
- package/docs/content/locales/de-DE/template-design.mdx +15 -1
- package/docs/content/locales/es-ES/skills-guide.mdx +5 -0
- package/docs/content/locales/es-ES/template-design.mdx +15 -1
- package/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
- package/docs/content/locales/fr-FR/template-design.mdx +15 -1
- package/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
- package/docs/content/locales/hi-IN/template-design.mdx +15 -1
- package/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
- package/docs/content/locales/ja-JP/template-design.mdx +16 -1
- package/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
- package/docs/content/locales/ko-KR/template-design.mdx +14 -1
- package/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
- package/docs/content/locales/pt-BR/template-design.mdx +14 -1
- package/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
- package/docs/content/locales/zh-CN/template-design.mdx +14 -1
- package/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
- package/docs/content/locales/zh-TW/template-design.mdx +14 -1
- package/docs/content/skills-guide.mdx +5 -0
- package/docs/content/template-design.mdx +14 -1
- package/package.json +1 -1
- package/corpus/templates/design/actions/import-figma-file.ts +0 -166
- package/corpus/templates/slides/server/lib/fig-design-system.ts +0 -110
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.80.
|
|
3
|
+
"version": "0.80.2",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The shared, template-agnostic Brand Kit surface. A Brand Kit unifies what
|
|
5
5
|
* `design` and `slides` previously copy-pasted as a "design system": design
|
|
6
|
-
* tokens + brand assets + custom instructions, extractable from
|
|
6
|
+
* tokens + brand assets + custom instructions, extractable from code,
|
|
7
7
|
* GitHub, a URL, or documents, and used to generate on-brand content.
|
|
8
8
|
*
|
|
9
9
|
* This module is pure (no `defineAction`, no DB, no template imports). Templates
|
|
@@ -404,6 +404,10 @@ iframe-backed screens on the infinite canvas.
|
|
|
404
404
|
iframe frame and URL metadata; change the copy's path/query for a new state.
|
|
405
405
|
- Flow visualization is multiple URL states: \`/checkout?step=shipping\`,
|
|
406
406
|
\`/checkout?step=payment\`, \`/checkout?step=done\`, etc.
|
|
407
|
+
- When the user gives a named flow or numbered screen list, preserve that order
|
|
408
|
+
and create one screen per URL/path. Shorthand like
|
|
409
|
+
\`localhost:1234/onboarding/1\` means
|
|
410
|
+
\`http://localhost:1234/onboarding/1\`.
|
|
407
411
|
|
|
408
412
|
## Required Local Bridge
|
|
409
413
|
|
|
@@ -439,6 +443,20 @@ pnpm action add-localhost-screens '{
|
|
|
439
443
|
}'
|
|
440
444
|
\`\`\`
|
|
441
445
|
|
|
446
|
+
For a numbered flow the user describes in chat, keep the labels and order:
|
|
447
|
+
|
|
448
|
+
\`\`\`bash
|
|
449
|
+
pnpm action add-localhost-screens '{
|
|
450
|
+
"designId": "<design-id>",
|
|
451
|
+
"connectionId": "<connection-id>",
|
|
452
|
+
"routes": [
|
|
453
|
+
{ "url": "localhost:1234/onboarding/1", "title": "Screen 1" },
|
|
454
|
+
{ "url": "localhost:1234/onboarding/2", "title": "Screen 2" },
|
|
455
|
+
{ "url": "localhost:1234/onboarding/3", "title": "Screen 3" }
|
|
456
|
+
]
|
|
457
|
+
}'
|
|
458
|
+
\`\`\`
|
|
459
|
+
|
|
442
460
|
If no \`routes\` or \`paths\` are supplied, \`add-localhost-screens\` uses every
|
|
443
461
|
route from the latest localhost manifest.
|
|
444
462
|
|
|
@@ -1318,7 +1318,7 @@ function AgentPanelInner({
|
|
|
1318
1318
|
data-agent-page-new-chat=""
|
|
1319
1319
|
aria-label={t("agentPanel.newChat")}
|
|
1320
1320
|
onClick={() => {
|
|
1321
|
-
|
|
1321
|
+
addTab();
|
|
1322
1322
|
}}
|
|
1323
1323
|
className="pointer-events-auto inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background/95 px-2.5 text-xs font-medium text-foreground shadow-sm backdrop-blur transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1324
1324
|
>
|
|
@@ -47,7 +47,7 @@ export interface AgentNativeExtensionStorageOptions {
|
|
|
47
47
|
export interface AgentNativeExtensionStorageContext {
|
|
48
48
|
extensionId: string;
|
|
49
49
|
slotId?: string;
|
|
50
|
-
scope?: Exclude<AgentNativeExtensionStorageScope, "all"
|
|
50
|
+
scope?: Exclude<AgentNativeExtensionStorageScope, "all">;
|
|
51
51
|
userId?: string;
|
|
52
52
|
organizationId?: string;
|
|
53
53
|
[key: string]: unknown;
|
|
@@ -576,7 +576,7 @@ function joinAssistantChunks(previous: string, next: string): string {
|
|
|
576
576
|
if (!next) return previous;
|
|
577
577
|
if (/\s$/.test(previous) || /^\s/.test(next)) return `${previous}${next}`;
|
|
578
578
|
if (/^[.,!?;:)\]}'"`]/.test(next)) return `${previous}${next}`;
|
|
579
|
-
if (/[(
|
|
579
|
+
if (/[([{'"`]$/.test(previous)) return `${previous}${next}`;
|
|
580
580
|
return `${previous} ${next}`;
|
|
581
581
|
}
|
|
582
582
|
|
|
@@ -19,10 +19,7 @@ export function extensionNameToSlug(
|
|
|
19
19
|
return sliced || "extension";
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export function extensionPath(
|
|
23
|
-
id: string,
|
|
24
|
-
name?: string | null | undefined,
|
|
25
|
-
): string {
|
|
22
|
+
export function extensionPath(id: string, name?: string | null): string {
|
|
26
23
|
const encodedId = encodeURIComponent(id);
|
|
27
24
|
if (name === undefined) return `/extensions/${encodedId}`;
|
|
28
25
|
return `/extensions/${encodedId}/${extensionNameToSlug(name)}`;
|
|
@@ -528,7 +528,7 @@ function expandRelativeUrls(text: string, agentUrl: string): string {
|
|
|
528
528
|
if (!text || !agentUrl) return text;
|
|
529
529
|
const base = publicAgentBaseUrl(agentUrl);
|
|
530
530
|
return text.replace(
|
|
531
|
-
/(^|[\s(
|
|
531
|
+
/(^|[\s([<"'`])(\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,
|
|
532
532
|
(_match, lead, path) => `${lead}${base}${path}`,
|
|
533
533
|
);
|
|
534
534
|
}
|
|
@@ -750,7 +750,7 @@ function safeUiSegment(value: string | undefined, fallback: string): string {
|
|
|
750
750
|
|
|
751
751
|
// ChatGPT and Claude cache MCP App resource HTML by `ui://` URI. Bump this
|
|
752
752
|
// when the shared shell changes in a way that must invalidate host caches.
|
|
753
|
-
const MCP_APP_RESOURCE_SHELL_VERSION = "shell-
|
|
753
|
+
const MCP_APP_RESOURCE_SHELL_VERSION = "shell-v54";
|
|
754
754
|
|
|
755
755
|
function legacyDefaultMcpAppUri(config: MCPConfig, actionName: string): string {
|
|
756
756
|
const app = safeUiSegment(config.appId ?? config.name, "agent-native");
|
|
@@ -1889,7 +1889,7 @@ async function isConnectTokenAllowed(
|
|
|
1889
1889
|
*/
|
|
1890
1890
|
export async function verifyAuth(
|
|
1891
1891
|
authHeader: string | undefined,
|
|
1892
|
-
ownerEmailHeader?: string
|
|
1892
|
+
ownerEmailHeader?: string,
|
|
1893
1893
|
options: { allowDevOpen?: boolean; resourceUrl?: string | string[] } = {},
|
|
1894
1894
|
): Promise<{
|
|
1895
1895
|
authed: boolean;
|
|
@@ -124,6 +124,7 @@ export function embedApp(
|
|
|
124
124
|
let app = null;
|
|
125
125
|
let appConnectPromise = null;
|
|
126
126
|
let openAiBridge = null;
|
|
127
|
+
let lastOpenAiSyncSignature = null;
|
|
127
128
|
let wrapperRequestId = 0;
|
|
128
129
|
const wrapperRequests = new Map();
|
|
129
130
|
let toolInput = {};
|
|
@@ -1533,11 +1534,19 @@ export function embedApp(
|
|
|
1533
1534
|
setMessage("Ready to open.");
|
|
1534
1535
|
return;
|
|
1535
1536
|
}
|
|
1536
|
-
setMessage("Loading app");
|
|
1537
1537
|
try {
|
|
1538
1538
|
const selfNavigate = shouldSelfNavigateToApp();
|
|
1539
1539
|
if (startedFor === launchUrl) return;
|
|
1540
1540
|
startedFor = launchUrl;
|
|
1541
|
+
// Only show the loading message when no frame is mounted yet. ChatGPT
|
|
1542
|
+
// fires openai:set_globals (and thus re-launch) constantly; calling
|
|
1543
|
+
// setMessage() unconditionally here wiped the just-mounted iframe out of
|
|
1544
|
+
// the stage on every redundant launch, so the app rendered and was
|
|
1545
|
+
// instantly blanked back to "Loading app" forever. renderFrame()/
|
|
1546
|
+
// transplant replace the stage themselves when they actually (re)mount.
|
|
1547
|
+
if (!appFrame) {
|
|
1548
|
+
setMessage("Loading app");
|
|
1549
|
+
}
|
|
1541
1550
|
const embedUrl = withChatBridgeParam(launchUrl);
|
|
1542
1551
|
if (selfNavigate && isEmbedStartUrl(embedUrl)) {
|
|
1543
1552
|
if (shouldTransplantAppDocument()) {
|
|
@@ -1662,6 +1671,31 @@ export function embedApp(
|
|
|
1662
1671
|
toolResultData = objectValue(data);
|
|
1663
1672
|
openUrl = openLinkFrom(params, data);
|
|
1664
1673
|
openStartUrl = embedStartUrlFrom(params, data);
|
|
1674
|
+
// ChatGPT/Codex fire openai:set_globals extremely often, and the listener
|
|
1675
|
+
// that calls this re-syncs on each one. Because this function calls
|
|
1676
|
+
// notifyHostHeight()/sendHostContext() (which the host reflects back as a
|
|
1677
|
+
// fresh set_globals), an unguarded sync becomes an infinite feedback storm
|
|
1678
|
+
// that starves the host until it shows its sad-face placeholder. Only do
|
|
1679
|
+
// the host round-trips + (re)launch when something we care about changed.
|
|
1680
|
+
// Deliberately EXCLUDE bridge.maxHeight: the host mutates it on every
|
|
1681
|
+
// set_globals as it echoes our height back, which would defeat the guard.
|
|
1682
|
+
let signature;
|
|
1683
|
+
try {
|
|
1684
|
+
signature = JSON.stringify([
|
|
1685
|
+
toolInput,
|
|
1686
|
+
openUrl,
|
|
1687
|
+
openStartUrl,
|
|
1688
|
+
bridge.displayMode,
|
|
1689
|
+
bridge.theme,
|
|
1690
|
+
bridge.locale
|
|
1691
|
+
]);
|
|
1692
|
+
} catch {
|
|
1693
|
+
signature = null;
|
|
1694
|
+
}
|
|
1695
|
+
if (signature !== null && signature === lastOpenAiSyncSignature) {
|
|
1696
|
+
return true;
|
|
1697
|
+
}
|
|
1698
|
+
lastOpenAiSyncSignature = signature;
|
|
1665
1699
|
updateTitle(data);
|
|
1666
1700
|
updateOpenButton();
|
|
1667
1701
|
updateDisplayButton();
|
|
@@ -17,8 +17,8 @@ function extractInvitationId(event: H3Event): string | undefined {
|
|
|
17
17
|
if (fromRouter) return fromRouter;
|
|
18
18
|
const path = getRequestURL(event).pathname;
|
|
19
19
|
const match =
|
|
20
|
-
path.match(/^\/([
|
|
21
|
-
path.match(/\/org\/invitations\/([
|
|
20
|
+
path.match(/^\/([^/]+)\/accept\/?$/) ??
|
|
21
|
+
path.match(/\/org\/invitations\/([^/]+)\/accept\/?$/);
|
|
22
22
|
return match?.[1] ? decodeURIComponent(match[1]) : undefined;
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -28,9 +28,9 @@ function extractMemberEmail(event: H3Event): string | undefined {
|
|
|
28
28
|
if (fromRouter) return fromRouter;
|
|
29
29
|
const path = getRequestURL(event).pathname;
|
|
30
30
|
const match =
|
|
31
|
-
path.match(/^\/([
|
|
32
|
-
path.match(/^\/([
|
|
33
|
-
path.match(/\/org\/members\/([
|
|
31
|
+
path.match(/^\/([^/]+)\/role\/?$/) ??
|
|
32
|
+
path.match(/^\/([^/]+)\/?$/) ??
|
|
33
|
+
path.match(/\/org\/members\/([^/]+)(?:\/role)?\/?$/);
|
|
34
34
|
return match?.[1] ? decodeURIComponent(match[1]) : undefined;
|
|
35
35
|
}
|
|
36
36
|
const nanoid = (): string =>
|
|
@@ -100,7 +100,7 @@ export function createOrgPlugin(): NitroPluginDef {
|
|
|
100
100
|
return listMembersHandler(event);
|
|
101
101
|
}
|
|
102
102
|
// Tail is /:email/role
|
|
103
|
-
if (/^\/[
|
|
103
|
+
if (/^\/[^/]+\/role\/?$/.test(tail)) {
|
|
104
104
|
if (method !== "PUT") {
|
|
105
105
|
setResponseStatus(event, 405);
|
|
106
106
|
return { error: "Method not allowed" };
|
|
@@ -129,7 +129,7 @@ export function createOrgPlugin(): NitroPluginDef {
|
|
|
129
129
|
return { error: "Method not allowed" };
|
|
130
130
|
}
|
|
131
131
|
// Tail is /:id/accept
|
|
132
|
-
if (/^\/[
|
|
132
|
+
if (/^\/[^/]+\/accept\/?$/.test(tail)) {
|
|
133
133
|
if (method !== "POST") {
|
|
134
134
|
setResponseStatus(event, 405);
|
|
135
135
|
return { error: "Method not allowed" };
|
|
@@ -434,7 +434,7 @@ export function expandRelativeUrls(text: string, agentUrl: string): string {
|
|
|
434
434
|
// Path must start at boundary (start, whitespace, or punctuation that isn't
|
|
435
435
|
// ':' — to avoid mangling `https://example.com/foo` or markdown link bodies).
|
|
436
436
|
return text.replace(
|
|
437
|
-
/(^|[\s(
|
|
437
|
+
/(^|[\s([<"'`])(\/[a-z0-9_-][a-z0-9_/?&=%#.,:-]*)/gi,
|
|
438
438
|
(_match, lead, path) => `${lead}${base}${path}`,
|
|
439
439
|
);
|
|
440
440
|
}
|
|
@@ -1855,6 +1855,9 @@ function createAuthGuardFn(): (
|
|
|
1855
1855
|
// the gate below 401s anonymous /_agent-native/* requests before any DB
|
|
1856
1856
|
// query, so the database would never get warmed.
|
|
1857
1857
|
if (p === "/_agent-native/health") return;
|
|
1858
|
+
if (getMethod(event) === "GET" && p.startsWith("/_agent-native/avatar/")) {
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1858
1861
|
if (isPublicPath(normalizedUrl, publicPaths)) return;
|
|
1859
1862
|
if (shouldBypassAuthForBuilderConnect(event, p)) return;
|
|
1860
1863
|
if (isPublicWorkspacePageRequest(event, p, config)) {
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { FeatureNotConfiguredError } from "./credential-provider.js";
|
|
2
|
+
import {
|
|
3
|
+
getBuilderProxyOrigin,
|
|
4
|
+
resolveBuilderCredentials,
|
|
5
|
+
} from "./credential-provider.js";
|
|
6
|
+
|
|
7
|
+
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
8
|
+
|
|
9
|
+
export interface BuilderDesignSystemIndexFile {
|
|
10
|
+
name: string;
|
|
11
|
+
data: Uint8Array;
|
|
12
|
+
mimeType?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BuilderDesignSystemIndexOptions {
|
|
16
|
+
projectName?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
githubRepoUrl?: string;
|
|
19
|
+
connectedProjectId?: string;
|
|
20
|
+
files?: BuilderDesignSystemIndexFile[];
|
|
21
|
+
selection?: Record<string, string[]>;
|
|
22
|
+
devToolsVersion?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface BuilderDesignSystemIndexResult {
|
|
26
|
+
ok: true;
|
|
27
|
+
source: "builder";
|
|
28
|
+
projectId: string;
|
|
29
|
+
jobId: string;
|
|
30
|
+
designSystemId: string;
|
|
31
|
+
suggestedTitle: string | null;
|
|
32
|
+
builderUrl: string;
|
|
33
|
+
status: "in-progress";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface BuilderDesignSystemCredentials {
|
|
37
|
+
privateKey: string;
|
|
38
|
+
publicKey: string;
|
|
39
|
+
userId: string | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface UploadStartResponse {
|
|
43
|
+
uploads?: Array<{ idx: number; uploadUrl: string; uploadToken: string }>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface GenerateResponse {
|
|
47
|
+
projectId?: string;
|
|
48
|
+
jobId?: string;
|
|
49
|
+
designSystemId?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function trimTrailingSlash(value: string): string {
|
|
53
|
+
return value.replace(/\/+$/, "");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getBuilderDesignSystemsBaseUrl(): string {
|
|
57
|
+
return (
|
|
58
|
+
process.env.BUILDER_DESIGN_SYSTEMS_BASE_URL ||
|
|
59
|
+
`${trimTrailingSlash(getBuilderProxyOrigin())}/design-systems/v1`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getBuilderAppHost(): string {
|
|
64
|
+
return (
|
|
65
|
+
process.env.BUILDER_APP_HOST ||
|
|
66
|
+
process.env.BUILDER_PUBLIC_APP_HOST ||
|
|
67
|
+
"https://builder.io"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function makeBuilderDesignSystemUrl(
|
|
72
|
+
path: string,
|
|
73
|
+
credentials: BuilderDesignSystemCredentials,
|
|
74
|
+
): URL {
|
|
75
|
+
const base = `${trimTrailingSlash(getBuilderDesignSystemsBaseUrl())}/`;
|
|
76
|
+
const url = new URL(path.replace(/^\/+/, ""), base);
|
|
77
|
+
url.searchParams.set("apiKey", credentials.publicKey);
|
|
78
|
+
if (credentials.userId) url.searchParams.set("userId", credentials.userId);
|
|
79
|
+
return url;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function makeBuilderHeaders(
|
|
83
|
+
credentials: BuilderDesignSystemCredentials,
|
|
84
|
+
): Record<string, string> {
|
|
85
|
+
return {
|
|
86
|
+
Authorization: `Bearer ${credentials.privateKey}`,
|
|
87
|
+
"x-builder-api-key": credentials.publicKey,
|
|
88
|
+
...(credentials.userId ? { "x-builder-user-id": credentials.userId } : {}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function resolveBuilderDesignSystemCredentials(): Promise<BuilderDesignSystemCredentials> {
|
|
93
|
+
const credentials = await resolveBuilderCredentials();
|
|
94
|
+
if (!credentials.privateKey || !credentials.publicKey) {
|
|
95
|
+
throw new FeatureNotConfiguredError({
|
|
96
|
+
requiredCredential: "BUILDER_PRIVATE_KEY",
|
|
97
|
+
message:
|
|
98
|
+
"Connect Builder.io before indexing a design system from Figma or code.",
|
|
99
|
+
builderConnectUrl: "/_agent-native/builder/connect",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
privateKey: credentials.privateKey,
|
|
104
|
+
publicKey: credentials.publicKey,
|
|
105
|
+
userId: credentials.userId ?? null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function mimeTypeForFile(file: BuilderDesignSystemIndexFile): string {
|
|
110
|
+
if (file.mimeType?.trim()) return file.mimeType.trim();
|
|
111
|
+
const lower = file.name.toLowerCase();
|
|
112
|
+
if (lower.endsWith(".fig")) return "application/octet-stream";
|
|
113
|
+
if (lower.endsWith(".pdf")) return "application/pdf";
|
|
114
|
+
if (lower.endsWith(".md") || lower.endsWith(".markdown"))
|
|
115
|
+
return "text/markdown";
|
|
116
|
+
if (lower.endsWith(".json")) return "application/json";
|
|
117
|
+
if (lower.endsWith(".css")) return "text/css";
|
|
118
|
+
return "text/plain";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function makeBody(bytes: Uint8Array, mimeType: string): BodyInit {
|
|
122
|
+
return typeof Blob !== "undefined"
|
|
123
|
+
? new Blob([bytes as unknown as BlobPart], { type: mimeType })
|
|
124
|
+
: (bytes as unknown as BodyInit);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function fetchWithTimeout(
|
|
128
|
+
url: string | URL,
|
|
129
|
+
init: RequestInit,
|
|
130
|
+
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
131
|
+
): Promise<Response> {
|
|
132
|
+
const controller = new AbortController();
|
|
133
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
134
|
+
try {
|
|
135
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
136
|
+
} finally {
|
|
137
|
+
clearTimeout(timer);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function parseErrorBody(response: Response): Promise<string> {
|
|
142
|
+
const text = await response.text().catch(() => "");
|
|
143
|
+
if (!text) return response.statusText || `HTTP ${response.status}`;
|
|
144
|
+
try {
|
|
145
|
+
const json = JSON.parse(text) as { error?: unknown };
|
|
146
|
+
if (typeof json.error === "string") return json.error;
|
|
147
|
+
if (json.error && typeof json.error === "object") {
|
|
148
|
+
return JSON.stringify(json.error).slice(0, 500);
|
|
149
|
+
}
|
|
150
|
+
} catch {}
|
|
151
|
+
return text.replace(/\s+/g, " ").trim().slice(0, 500);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function assertOk(response: Response, label: string): Promise<void> {
|
|
155
|
+
if (response.ok) return;
|
|
156
|
+
throw new Error(
|
|
157
|
+
`${label} (${response.status}): ${await parseErrorBody(response)}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function uploadToResumableUrl(
|
|
162
|
+
slot: { uploadUrl: string },
|
|
163
|
+
file: BuilderDesignSystemIndexFile,
|
|
164
|
+
): Promise<void> {
|
|
165
|
+
const mimeType = mimeTypeForFile(file);
|
|
166
|
+
const bytes = file.data;
|
|
167
|
+
const start = await fetchWithTimeout(slot.uploadUrl, {
|
|
168
|
+
method: "POST",
|
|
169
|
+
headers: {
|
|
170
|
+
"x-goog-resumable": "start",
|
|
171
|
+
"x-goog-content-length-range": `0,${bytes.byteLength}`,
|
|
172
|
+
"Content-Type": mimeType,
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
await assertOk(start, "Builder design-system upload session failed");
|
|
176
|
+
const sessionUrl = start.headers.get("Location");
|
|
177
|
+
if (!sessionUrl) {
|
|
178
|
+
throw new Error("Builder design-system upload session returned no URL.");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const response = await fetchWithTimeout(sessionUrl, {
|
|
182
|
+
method: "PUT",
|
|
183
|
+
headers: {
|
|
184
|
+
"Content-Range": `bytes 0-${bytes.byteLength - 1}/${bytes.byteLength}`,
|
|
185
|
+
"Content-Type": mimeType,
|
|
186
|
+
},
|
|
187
|
+
body: makeBody(bytes, mimeType),
|
|
188
|
+
});
|
|
189
|
+
await assertOk(response, "Builder design-system file upload failed");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function nonEmptyFiles(
|
|
193
|
+
files: BuilderDesignSystemIndexFile[] | undefined,
|
|
194
|
+
): BuilderDesignSystemIndexFile[] {
|
|
195
|
+
return (files ?? []).filter((file) => file.data.byteLength > 0);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function builderDesignSystemUrl(designSystemId?: string | null): string {
|
|
199
|
+
const host = trimTrailingSlash(getBuilderAppHost());
|
|
200
|
+
return designSystemId
|
|
201
|
+
? `${host}/app/design-system-intelligence/${encodeURIComponent(
|
|
202
|
+
designSystemId,
|
|
203
|
+
)}`
|
|
204
|
+
: `${host}/app/design-system-intelligence`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export async function startBuilderDesignSystemIndex(
|
|
208
|
+
options: BuilderDesignSystemIndexOptions,
|
|
209
|
+
): Promise<BuilderDesignSystemIndexResult> {
|
|
210
|
+
const files = nonEmptyFiles(options.files);
|
|
211
|
+
const description = options.description?.trim();
|
|
212
|
+
if (description) {
|
|
213
|
+
files.unshift({
|
|
214
|
+
name: "additional-context.txt",
|
|
215
|
+
data: new TextEncoder().encode(description),
|
|
216
|
+
mimeType: "text/plain",
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (
|
|
220
|
+
files.length === 0 &&
|
|
221
|
+
!options.githubRepoUrl &&
|
|
222
|
+
!options.connectedProjectId
|
|
223
|
+
) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
"Provide at least one .fig/code/text file or a GitHub repository URL to index with Builder.",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const credentials = await resolveBuilderDesignSystemCredentials();
|
|
230
|
+
let uploadTokens: string[] = [];
|
|
231
|
+
if (files.length > 0) {
|
|
232
|
+
const uploadStart = await fetchWithTimeout(
|
|
233
|
+
makeBuilderDesignSystemUrl("upload/start", credentials),
|
|
234
|
+
{
|
|
235
|
+
method: "POST",
|
|
236
|
+
headers: {
|
|
237
|
+
...makeBuilderHeaders(credentials),
|
|
238
|
+
"Content-Type": "application/json",
|
|
239
|
+
},
|
|
240
|
+
body: JSON.stringify({
|
|
241
|
+
attachments: files.map((file) => ({
|
|
242
|
+
name: file.name,
|
|
243
|
+
mimetype: mimeTypeForFile(file),
|
|
244
|
+
declaredSize: file.data.byteLength,
|
|
245
|
+
})),
|
|
246
|
+
}),
|
|
247
|
+
},
|
|
248
|
+
);
|
|
249
|
+
await assertOk(uploadStart, "Builder design-system upload start failed");
|
|
250
|
+
const uploadJson = (await uploadStart.json()) as UploadStartResponse;
|
|
251
|
+
const slots = [...(uploadJson.uploads ?? [])].sort((a, b) => a.idx - b.idx);
|
|
252
|
+
if (slots.length !== files.length) {
|
|
253
|
+
throw new Error("Builder did not return upload slots for all files.");
|
|
254
|
+
}
|
|
255
|
+
for (let i = 0; i < slots.length; i++) {
|
|
256
|
+
if (slots[i].idx !== i) {
|
|
257
|
+
throw new Error(`Builder upload slot mismatch: expected ${i}.`);
|
|
258
|
+
}
|
|
259
|
+
await uploadToResumableUrl(slots[i], files[i]);
|
|
260
|
+
}
|
|
261
|
+
uploadTokens = slots.map((slot) => slot.uploadToken);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const generate = await fetchWithTimeout(
|
|
265
|
+
makeBuilderDesignSystemUrl("generate", credentials),
|
|
266
|
+
{
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: {
|
|
269
|
+
...makeBuilderHeaders(credentials),
|
|
270
|
+
"Content-Type": "application/json",
|
|
271
|
+
},
|
|
272
|
+
body: JSON.stringify({
|
|
273
|
+
uploads: uploadTokens,
|
|
274
|
+
...(options.projectName?.trim()
|
|
275
|
+
? { projectName: options.projectName.trim() }
|
|
276
|
+
: {}),
|
|
277
|
+
...(options.githubRepoUrl?.trim()
|
|
278
|
+
? { githubRepoUrl: options.githubRepoUrl.trim() }
|
|
279
|
+
: {}),
|
|
280
|
+
...(options.connectedProjectId?.trim()
|
|
281
|
+
? { connectedProjectId: options.connectedProjectId.trim() }
|
|
282
|
+
: {}),
|
|
283
|
+
...(options.selection ? { selection: options.selection } : {}),
|
|
284
|
+
...(options.devToolsVersion?.trim()
|
|
285
|
+
? { devToolsVersion: options.devToolsVersion.trim() }
|
|
286
|
+
: {}),
|
|
287
|
+
}),
|
|
288
|
+
},
|
|
289
|
+
);
|
|
290
|
+
await assertOk(generate, "Builder design-system indexing failed");
|
|
291
|
+
const generated = (await generate.json()) as GenerateResponse;
|
|
292
|
+
if (!generated.projectId || !generated.jobId || !generated.designSystemId) {
|
|
293
|
+
throw new Error(
|
|
294
|
+
"Builder design-system indexing returned an incomplete response.",
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
ok: true,
|
|
300
|
+
source: "builder",
|
|
301
|
+
projectId: generated.projectId,
|
|
302
|
+
jobId: generated.jobId,
|
|
303
|
+
designSystemId: generated.designSystemId,
|
|
304
|
+
suggestedTitle: options.projectName?.trim() || null,
|
|
305
|
+
builderUrl: builderDesignSystemUrl(generated.designSystemId),
|
|
306
|
+
status: "in-progress",
|
|
307
|
+
};
|
|
308
|
+
}
|
|
@@ -383,6 +383,31 @@ function parseBuilderCallbackBoolean(
|
|
|
383
383
|
// inlines them in the DOM. Mirrors SAFE_DATA_IMAGE in sanitize-html.ts.
|
|
384
384
|
export const AVATAR_RASTER_MIME = /^data:image\/(png|jpe?g|gif|webp);/i;
|
|
385
385
|
|
|
386
|
+
export function resolveAvatarEmailParam(
|
|
387
|
+
pathname: string,
|
|
388
|
+
appBasePath = "",
|
|
389
|
+
): string {
|
|
390
|
+
const base = appBasePath.replace(/\/+$/, "");
|
|
391
|
+
const avatarPaths = Array.from(
|
|
392
|
+
new Set([`${base}/_agent-native/avatar/`, "/_agent-native/avatar/"]),
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
for (const avatarPath of avatarPaths) {
|
|
396
|
+
const avatarIndex = pathname.indexOf(avatarPath);
|
|
397
|
+
if (avatarIndex >= 0) {
|
|
398
|
+
return pathname
|
|
399
|
+
.slice(avatarIndex + avatarPath.length)
|
|
400
|
+
.replace(/^\/+/, "")
|
|
401
|
+
.split("/")[0];
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const firstSegment = pathname.replace(/^\/+/, "").split("/")[0] ?? "";
|
|
406
|
+
if (!firstSegment || firstSegment === "_agent-native") return "";
|
|
407
|
+
if (base && firstSegment === base.replace(/^\/+/, "")) return "";
|
|
408
|
+
return firstSegment;
|
|
409
|
+
}
|
|
410
|
+
|
|
386
411
|
async function detectUsageEngineName(
|
|
387
412
|
event: H3Event,
|
|
388
413
|
userEmail: string | undefined,
|
|
@@ -3010,9 +3035,10 @@ export function createCoreRoutesPlugin(
|
|
|
3010
3035
|
`${P}/avatar`,
|
|
3011
3036
|
defineEventHandler(async (event: H3Event) => {
|
|
3012
3037
|
const method = getMethod(event);
|
|
3013
|
-
const emailParam = (
|
|
3014
|
-
.
|
|
3015
|
-
|
|
3038
|
+
const emailParam = resolveAvatarEmailParam(
|
|
3039
|
+
event.url?.pathname || "",
|
|
3040
|
+
getConfiguredAppBasePath(),
|
|
3041
|
+
);
|
|
3016
3042
|
|
|
3017
3043
|
if (method === "GET") {
|
|
3018
3044
|
if (!emailParam) {
|
|
@@ -386,6 +386,14 @@ export {
|
|
|
386
386
|
deleteBuilderCredentials,
|
|
387
387
|
resolveSecret,
|
|
388
388
|
} from "./credential-provider.js";
|
|
389
|
+
export {
|
|
390
|
+
builderDesignSystemUrl,
|
|
391
|
+
getBuilderDesignSystemsBaseUrl,
|
|
392
|
+
startBuilderDesignSystemIndex,
|
|
393
|
+
type BuilderDesignSystemIndexFile,
|
|
394
|
+
type BuilderDesignSystemIndexOptions,
|
|
395
|
+
type BuilderDesignSystemIndexResult,
|
|
396
|
+
} from "./builder-design-systems.js";
|
|
389
397
|
export {
|
|
390
398
|
getBuilderBranchProjectId,
|
|
391
399
|
isBuilderBranchingEnabled,
|