@agent-native/core 0.114.12 → 0.114.15
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 +21 -0
- package/corpus/core/docs/content/deployment.mdx +1 -1
- package/corpus/core/docs/content/frames.mdx +1 -1
- package/corpus/core/docs/content/integrations.mdx +27 -27
- package/corpus/core/docs/content/pr-visual-recap.mdx +17 -13
- package/corpus/core/docs/content/workspace-management.mdx +1 -1
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/engine/builder-engine.ts +4 -0
- package/corpus/core/src/application-state/index.ts +3 -0
- package/corpus/core/src/application-state/script-helpers.ts +12 -1
- package/corpus/core/src/application-state/store.ts +216 -15
- package/corpus/core/src/client/AgentPanel.tsx +10 -4
- package/corpus/core/src/client/ConnectBuilderCard.tsx +5 -1
- package/corpus/core/src/client/chat/markdown-renderer.tsx +3 -5
- package/corpus/core/src/client/error-format.ts +2 -1
- package/corpus/core/src/client/index.ts +1 -0
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +2 -18
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +43 -32
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +4 -2
- package/corpus/core/src/client/settings/BackgroundAgentSection.tsx +5 -1
- package/corpus/core/src/client/settings/SettingsPanel.tsx +4 -4
- package/corpus/core/src/client/settings/useBuilderStatus.ts +3 -0
- package/corpus/core/src/db/client.ts +44 -1
- package/corpus/core/src/localization/default-messages.ts +1 -7
- package/corpus/core/src/server/builder-browser.ts +4 -0
- package/corpus/core/src/server/builder-design-systems.ts +6 -1
- package/corpus/core/src/server/fusion-app.ts +5 -1
- package/corpus/core/src/shared/builder-link-tracking.ts +41 -0
- package/corpus/core/src/shared/index.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +10 -1
- package/corpus/templates/analytics/actions/save-dashboard-report-subscription.ts +10 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +5 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +20 -32
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +62 -0
- package/corpus/templates/analytics/changelog/2026-07-21-chart-series-controls-stay-open-while-moving-from-the-legend.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-21-dashboard-email-captures-complete-large-dashboards-in-chunks.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +4 -4
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +1 -8
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +39 -7
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +341 -251
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +114 -0
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +84 -6
- package/corpus/templates/analytics/server/plugins/db.ts +13 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +10 -4
- package/corpus/templates/clips/changelog/2026-07-21-choose-which-whisper-model-to-use-in-settings.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-fixed-organization-recording-visibility-default.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-live-dictation-text-now-appears-above-the-desktop-recording-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-meeting-notes-stop-when-calls-end.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +66 -75
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +2 -0
- package/corpus/templates/clips/desktop/src/hooks/useWhisperSettings.ts +172 -0
- package/corpus/templates/clips/desktop/src/lib/meeting-call-app.ts +41 -0
- package/corpus/templates/clips/desktop/src/lib/silence-events.ts +1 -0
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +14 -3
- package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +25 -0
- package/corpus/templates/clips/desktop/src/shared/config.ts +1 -0
- package/corpus/templates/clips/desktop/src/styles.css +100 -7
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +3 -4
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +32 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +11 -4
- package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +268 -20
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_model.rs +285 -164
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +18 -7
- package/corpus/templates/clips/learnings.defaults.md +1 -1
- package/corpus/templates/clips/server/plugins/db.ts +11 -0
- package/corpus/templates/clips/shared/builder-credits.ts +1 -1
- package/corpus/templates/design/AGENTS.md +7 -3
- package/corpus/templates/design/actions/begin-node-rewrite-request.ts +78 -0
- package/corpus/templates/design/actions/cancel-node-rewrite-request.ts +17 -7
- package/corpus/templates/design/actions/propose-node-rewrite.ts +26 -18
- package/corpus/templates/design/actions/resolve-node-rewrite.ts +67 -19
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +9 -1
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +5 -1
- package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +1 -4
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +2 -6
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +9 -1
- package/corpus/templates/design/shared/node-rewrite.ts +32 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +6 -3
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +11 -18
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +9 -5
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +9 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +18 -0
- package/corpus/templates/slides/changelog/2026-07-21-decks-list-now-refreshes-when-you-switch-organizations.md +6 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldCreateBar.tsx +13 -19
- package/corpus/templates/tasks/app/components/custom-fields/FieldListRow.tsx +27 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsList.tsx +26 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsListSkeleton.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/FieldsPage.tsx +4 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldEditorSidebar.tsx +12 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldTitleSection.tsx +6 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/CurrencyConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/NumberConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/PercentConfigControl.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/SelectConfigControl.tsx +17 -7
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/select-colors.ts +37 -9
- package/corpus/templates/tasks/app/components/custom-fields/field-types.ts +23 -0
- package/corpus/templates/tasks/app/components/inbox/InboxList.tsx +24 -16
- package/corpus/templates/tasks/app/components/inbox/InboxListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/inbox/InboxListRow.tsx +7 -5
- package/corpus/templates/tasks/app/components/layout/Header.tsx +10 -10
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +11 -7
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +17 -10
- package/corpus/templates/tasks/app/components/shared/AddListItemInput.tsx +14 -8
- package/corpus/templates/tasks/app/components/shared/AlertDialog.tsx +6 -2
- package/corpus/templates/tasks/app/components/shared/BulkDeleteDialog.tsx +13 -6
- package/corpus/templates/tasks/app/components/shared/ChipSelect.tsx +12 -5
- package/corpus/templates/tasks/app/components/shared/DeleteItemDialog.tsx +6 -6
- package/corpus/templates/tasks/app/components/shared/ListViewHeader.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/SidePanel.tsx +5 -2
- package/corpus/templates/tasks/app/components/shared/list/ListRowDragHandle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionBar.tsx +46 -20
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionHeaderToggle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionToolbar.tsx +10 -6
- package/corpus/templates/tasks/app/components/tasks/TaskList.tsx +24 -13
- package/corpus/templates/tasks/app/components/tasks/TaskListHeaderRow.tsx +4 -1
- package/corpus/templates/tasks/app/components/tasks/TaskListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +15 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskFieldsSidebar.tsx +11 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskTitleSection.tsx +8 -3
- package/corpus/templates/tasks/app/components/tasks/fields/controls/RichTextValueControl.tsx +12 -6
- package/corpus/templates/tasks/app/components/tasks/fields/controls/SingleSelectValueControl.tsx +6 -1
- package/corpus/templates/tasks/app/i18n/en-US.ts +209 -0
- package/corpus/templates/tasks/app/i18n/index.ts +34 -0
- package/corpus/templates/tasks/app/root.tsx +34 -2
- package/corpus/templates/tasks/app/routes/extensions.$id.tsx +2 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -1
- package/corpus/templates/tasks/app/routes/fields.tsx +2 -1
- package/corpus/templates/tasks/app/routes/inbox.tsx +2 -1
- package/corpus/templates/tasks/app/routes/tasks.tsx +2 -1
- package/corpus/templates/tasks/app/routes/team.tsx +6 -3
- package/corpus/templates/tasks/changelog/2026-07-20-tasks-is-now-available-in-10-additional-languages.md +6 -0
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +4 -0
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/script-helpers.d.ts +3 -1
- package/dist/application-state/script-helpers.d.ts.map +1 -1
- package/dist/application-state/script-helpers.js +7 -1
- package/dist/application-state/script-helpers.js.map +1 -1
- package/dist/application-state/store.d.ts +7 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +143 -17
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +10 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +5 -1
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
- package/dist/client/chat/markdown-renderer.js +3 -2
- package/dist/client/chat/markdown-renderer.js.map +1 -1
- package/dist/client/error-format.d.ts +1 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +1 -1
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +3 -4
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +21 -7
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +2 -2
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/settings/BackgroundAgentSection.d.ts.map +1 -1
- package/dist/client/settings/BackgroundAgentSection.js +5 -1
- package/dist/client/settings/BackgroundAgentSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +2 -0
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts +7 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +39 -1
- package/dist/db/client.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +0 -6
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +1 -7
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +4 -0
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +6 -1
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/fusion-app.d.ts.map +1 -1
- package/dist/server/fusion-app.js +2 -1
- package/dist/server/fusion-app.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/builder-link-tracking.d.ts +14 -0
- package/dist/shared/builder-link-tracking.d.ts.map +1 -0
- package/dist/shared/builder-link-tracking.js +26 -0
- package/dist/shared/builder-link-tracking.js.map +1 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/docs/content/deployment.mdx +1 -1
- package/docs/content/frames.mdx +1 -1
- package/docs/content/integrations.mdx +27 -27
- package/docs/content/pr-visual-recap.mdx +17 -13
- package/docs/content/workspace-management.mdx +1 -1
- package/package.json +3 -2
- package/src/agent/engine/builder-engine.ts +4 -0
- package/src/application-state/index.ts +3 -0
- package/src/application-state/script-helpers.ts +12 -1
- package/src/application-state/store.ts +216 -15
- package/src/client/AgentPanel.tsx +10 -4
- package/src/client/ConnectBuilderCard.tsx +5 -1
- package/src/client/chat/markdown-renderer.tsx +3 -5
- package/src/client/error-format.ts +2 -1
- package/src/client/index.ts +1 -0
- package/src/client/integrations/IntegrationsPanel.tsx +2 -18
- package/src/client/resources/McpIntegrationDialog.tsx +43 -32
- package/src/client/resources/mcp-integration-catalog.ts +4 -2
- package/src/client/settings/BackgroundAgentSection.tsx +5 -1
- package/src/client/settings/SettingsPanel.tsx +4 -4
- package/src/client/settings/useBuilderStatus.ts +3 -0
- package/src/db/client.ts +44 -1
- package/src/localization/default-messages.ts +1 -7
- package/src/server/builder-browser.ts +4 -0
- package/src/server/builder-design-systems.ts +6 -1
- package/src/server/fusion-app.ts +5 -1
- package/src/shared/builder-link-tracking.ts +41 -0
- package/src/shared/index.ts +1 -0
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* regex stays narrow; the gateway may emit URLs containing `(`
|
|
12
12
|
* (e.g. `?ref=Acme%20(staging)`) and we don't want to reject them.
|
|
13
13
|
*/
|
|
14
|
-
export const BUILDER_SPACE_SETTINGS_URL =
|
|
14
|
+
export const BUILDER_SPACE_SETTINGS_URL =
|
|
15
|
+
"https://builder.io/account/space?utm_source=agent-native&utm_medium=product&utm_campaign=onboarding&utm_content=space_settings";
|
|
15
16
|
|
|
16
17
|
// Pseudo-href used to mark an in-app "Start new chat" CTA inside the markdown
|
|
17
18
|
// error message. The chat renderer intercepts this href and renders a button
|
package/src/client/index.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
} from "@tabler/icons-react";
|
|
15
15
|
import React, { useState, useCallback, useEffect } from "react";
|
|
16
16
|
|
|
17
|
-
import { AgentAskPopover } from "../AgentAskPopover.js";
|
|
18
17
|
import { agentNativePath } from "../api-path.js";
|
|
19
18
|
import {
|
|
20
19
|
Tooltip,
|
|
@@ -135,7 +134,8 @@ const PLATFORMS: PlatformInfo[] = [
|
|
|
135
134
|
"Builder.io discovers each agent's skills via A2A",
|
|
136
135
|
"Chat with one agent that can trigger actions across all your apps",
|
|
137
136
|
],
|
|
138
|
-
docsUrl:
|
|
137
|
+
docsUrl:
|
|
138
|
+
"https://www.builder.io?utm_source=agent-native&utm_medium=product&utm_campaign=integrations&utm_content=integrations_panel",
|
|
139
139
|
},
|
|
140
140
|
];
|
|
141
141
|
|
|
@@ -512,14 +512,6 @@ export function IntegrationsPanel() {
|
|
|
512
512
|
<div className="text-[10px] font-medium text-muted-foreground mb-1.5">
|
|
513
513
|
{t("integrations.addChatIntegration")}
|
|
514
514
|
</div>
|
|
515
|
-
<AgentAskPopover
|
|
516
|
-
label={t("integrations.addSomething")}
|
|
517
|
-
title={t("integrations.addSomethingTitle")}
|
|
518
|
-
placeholder={t("integrations.addSomethingPlaceholder")}
|
|
519
|
-
prompt=""
|
|
520
|
-
context="The user wants to add a chat or workspace integration that is not in the current directory. Research the provider's official OAuth or MCP setup, explain any app registration or allowlist requirements, and add a reusable integration preset when it is supported. Never ask the user to paste credentials into a prompt."
|
|
521
|
-
className="mb-2 h-7 w-full justify-center border-dashed px-2 text-[10px]"
|
|
522
|
-
/>
|
|
523
515
|
<AddIntegrationPicker
|
|
524
516
|
connectedIds={connectedIds}
|
|
525
517
|
onSelect={(p) => {
|
|
@@ -554,14 +546,6 @@ export function IntegrationsPanel() {
|
|
|
554
546
|
</TooltipTrigger>
|
|
555
547
|
<TooltipContent>{t("integrations.addIntegration")}</TooltipContent>
|
|
556
548
|
</Tooltip>
|
|
557
|
-
<AgentAskPopover
|
|
558
|
-
label={t("integrations.addSomething")}
|
|
559
|
-
title={t("integrations.addSomethingTitle")}
|
|
560
|
-
placeholder={t("integrations.addSomethingPlaceholder")}
|
|
561
|
-
prompt=""
|
|
562
|
-
context="The user wants to add a chat or workspace integration that is not in the current directory. Research the provider's official OAuth or MCP setup, explain any app registration or allowlist requirements, and add a reusable integration preset when it is supported. Never ask the user to paste credentials into a prompt."
|
|
563
|
-
className="h-7 px-2 text-[10px]"
|
|
564
|
-
/>
|
|
565
549
|
</div>
|
|
566
550
|
</div>
|
|
567
551
|
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
} from "@tabler/icons-react";
|
|
8
8
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
9
9
|
|
|
10
|
-
import { AgentAskPopover } from "../AgentAskPopover.js";
|
|
11
10
|
import { agentNativePath } from "../api-path.js";
|
|
12
11
|
import { openAgentSettings } from "../CommandMenu.js";
|
|
13
12
|
import {
|
|
@@ -62,6 +61,40 @@ interface TestResult {
|
|
|
62
61
|
message: string;
|
|
63
62
|
}
|
|
64
63
|
|
|
64
|
+
function IntegrationLogo({ name, logoUrl }: { name: string; logoUrl: string }) {
|
|
65
|
+
const [loaded, setLoaded] = useState(false);
|
|
66
|
+
const [loadFailed, setLoadFailed] = useState(false);
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
setLoaded(false);
|
|
70
|
+
setLoadFailed(false);
|
|
71
|
+
}, [logoUrl]);
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div className="relative flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-md border border-border bg-background text-[11px] font-semibold text-muted-foreground">
|
|
75
|
+
<span aria-hidden="true" hidden={loaded}>
|
|
76
|
+
{name.slice(0, 1)}
|
|
77
|
+
</span>
|
|
78
|
+
<img
|
|
79
|
+
src={logoUrl}
|
|
80
|
+
alt=""
|
|
81
|
+
loading="lazy"
|
|
82
|
+
decoding="async"
|
|
83
|
+
className="absolute inset-1 h-6 w-6 object-contain"
|
|
84
|
+
hidden={loadFailed}
|
|
85
|
+
onLoad={() => {
|
|
86
|
+
setLoadFailed(false);
|
|
87
|
+
setLoaded(true);
|
|
88
|
+
}}
|
|
89
|
+
onError={() => {
|
|
90
|
+
setLoadFailed(true);
|
|
91
|
+
setLoaded(false);
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
65
98
|
function parseHeaderLines(text: string): Record<string, string> | undefined {
|
|
66
99
|
const out: Record<string, string> = {};
|
|
67
100
|
for (const line of text.split(/\r?\n/)) {
|
|
@@ -412,7 +445,9 @@ export function McpIntegrationDialog({
|
|
|
412
445
|
<DialogHeader className="shrink-0 px-7 pb-5 pe-14 pt-6">
|
|
413
446
|
<DialogTitle>{t("mcpIntegrations.title")}</DialogTitle>
|
|
414
447
|
<DialogDescription>
|
|
415
|
-
{t("mcpIntegrations.description"
|
|
448
|
+
{t("mcpIntegrations.description", {
|
|
449
|
+
count: defaultIntegrations.length,
|
|
450
|
+
})}
|
|
416
451
|
</DialogDescription>
|
|
417
452
|
</DialogHeader>
|
|
418
453
|
<div className="flex shrink-0 flex-col gap-3 px-7 pb-5 sm:flex-row">
|
|
@@ -435,14 +470,6 @@ export function McpIntegrationDialog({
|
|
|
435
470
|
>
|
|
436
471
|
{t("mcpIntegrations.addYourOwn")}
|
|
437
472
|
</button>
|
|
438
|
-
<AgentAskPopover
|
|
439
|
-
label={t("mcpIntegrations.addSomething")}
|
|
440
|
-
title={t("mcpIntegrations.addSomethingTitle")}
|
|
441
|
-
placeholder={t("mcpIntegrations.addSomethingPlaceholder")}
|
|
442
|
-
prompt=""
|
|
443
|
-
context="The user wants to add an MCP or provider integration that is not in the current directory. Research the provider's official remote MCP endpoint and OAuth, client-registration, or allowlist requirements. Prefer Streamable HTTP endpoints over legacy SSE, reuse an existing provider OAuth connector when appropriate, and never ask the user to paste credentials into a prompt. If this should become a reusable preset, update the integration catalog, official docs link, bundled logo, localization, and tests."
|
|
444
|
-
className="h-9 whitespace-nowrap border-dashed px-3 text-[12px] font-medium"
|
|
445
|
-
/>
|
|
446
473
|
</div>
|
|
447
474
|
<div className="min-h-0 flex-1 overflow-y-auto px-7 pb-7">
|
|
448
475
|
{error && (
|
|
@@ -467,27 +494,16 @@ export function McpIntegrationDialog({
|
|
|
467
494
|
className="flex min-h-[128px] flex-col rounded-md border border-border bg-card p-4 transition-colors hover:border-border/80 hover:bg-accent/20"
|
|
468
495
|
>
|
|
469
496
|
<div className="flex items-center gap-3">
|
|
470
|
-
<
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
<img
|
|
475
|
-
src={integration.logoUrl}
|
|
476
|
-
alt=""
|
|
477
|
-
loading="lazy"
|
|
478
|
-
decoding="async"
|
|
479
|
-
className="absolute inset-1 h-6 w-6 object-contain"
|
|
480
|
-
onError={(event) => {
|
|
481
|
-
event.currentTarget.hidden = true;
|
|
482
|
-
}}
|
|
483
|
-
/>
|
|
484
|
-
</div>
|
|
497
|
+
<IntegrationLogo
|
|
498
|
+
name={integration.name}
|
|
499
|
+
logoUrl={integration.logoUrl}
|
|
500
|
+
/>
|
|
485
501
|
<div className="min-w-0">
|
|
486
502
|
<h3 className="truncate text-[13px] font-semibold text-foreground">
|
|
487
503
|
{integration.name}
|
|
488
504
|
</h3>
|
|
489
505
|
{integration.availability !== "ready" && (
|
|
490
|
-
<span className="mt-0.5 inline-flex rounded-full border border-
|
|
506
|
+
<span className="mt-0.5 inline-flex rounded-full border border-border/70 bg-muted/40 px-1.5 py-0.5 text-[9px] font-medium text-muted-foreground">
|
|
491
507
|
{integration.availability === "beta"
|
|
492
508
|
? t("mcpIntegrations.status.beta")
|
|
493
509
|
: integration.availability ===
|
|
@@ -508,11 +524,6 @@ export function McpIntegrationDialog({
|
|
|
508
524
|
<p className="mt-1 line-clamp-2 flex-1 text-[12px] leading-relaxed text-muted-foreground">
|
|
509
525
|
{t(integration.descriptionKey)}
|
|
510
526
|
</p>
|
|
511
|
-
{integration.setupNoteKey && (
|
|
512
|
-
<p className="mt-2 line-clamp-3 text-[10px] leading-relaxed text-amber-700 dark:text-amber-300">
|
|
513
|
-
{t(integration.setupNoteKey)}
|
|
514
|
-
</p>
|
|
515
|
-
)}
|
|
516
527
|
<div className="mt-3 flex items-center gap-2">
|
|
517
528
|
{connected ? (
|
|
518
529
|
<button
|
|
@@ -637,7 +648,7 @@ export function McpIntegrationDialog({
|
|
|
637
648
|
<div className="space-y-3">
|
|
638
649
|
{renderScopeSelector()}
|
|
639
650
|
{selected?.setupNoteKey && (
|
|
640
|
-
<div className="rounded-md border border-
|
|
651
|
+
<div className="rounded-md border border-border bg-muted/40 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground">
|
|
641
652
|
{t(selected.setupNoteKey)}
|
|
642
653
|
</div>
|
|
643
654
|
)}
|
|
@@ -189,7 +189,8 @@ export const DEFAULT_MCP_INTEGRATIONS: DefaultMcpIntegration[] = [
|
|
|
189
189
|
availability: "ready",
|
|
190
190
|
verification: "preflight-only",
|
|
191
191
|
logoUrl: mcpIntegrationLogo("supabase"),
|
|
192
|
-
docsUrl:
|
|
192
|
+
docsUrl:
|
|
193
|
+
"https://www.builder.io/c/docs/fusion-connect-to-supabase?utm_source=agent-native&utm_medium=product&utm_campaign=integrations&utm_content=fusion_connect_supabase",
|
|
193
194
|
keywords: ["database", "auth", "postgres", "storage"],
|
|
194
195
|
},
|
|
195
196
|
{
|
|
@@ -206,7 +207,8 @@ export const DEFAULT_MCP_INTEGRATIONS: DefaultMcpIntegration[] = [
|
|
|
206
207
|
availability: "ready",
|
|
207
208
|
verification: "preflight-only",
|
|
208
209
|
logoUrl: mcpIntegrationLogo("neon"),
|
|
209
|
-
docsUrl:
|
|
210
|
+
docsUrl:
|
|
211
|
+
"https://www.builder.io/c/docs/fusion-connect-to-neon?utm_source=agent-native&utm_medium=product&utm_campaign=integrations&utm_content=fusion_connect_neon",
|
|
210
212
|
keywords: ["database", "postgres", "serverless", "backend"],
|
|
211
213
|
},
|
|
212
214
|
{
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "@tabler/icons-react";
|
|
7
7
|
import { useState } from "react";
|
|
8
8
|
|
|
9
|
+
import { withBuilderUtmTrackingParams } from "../../shared/builder-link-tracking.js";
|
|
9
10
|
import { trackEvent } from "../analytics.js";
|
|
10
11
|
import { agentNativePath } from "../api-path.js";
|
|
11
12
|
import { SettingsSection } from "./SettingsSection.js";
|
|
@@ -170,7 +171,10 @@ export function BackgroundAgentSection() {
|
|
|
170
171
|
Branch created
|
|
171
172
|
</div>
|
|
172
173
|
<a
|
|
173
|
-
href={result.url
|
|
174
|
+
href={withBuilderUtmTrackingParams(result.url, {
|
|
175
|
+
campaign: "product",
|
|
176
|
+
content: "background_agent_branch",
|
|
177
|
+
})}
|
|
174
178
|
target="_blank"
|
|
175
179
|
rel="noopener noreferrer"
|
|
176
180
|
className="flex items-center gap-1 text-[10px] text-foreground hover:underline"
|
|
@@ -2857,7 +2857,7 @@ function SettingsPanelContent({
|
|
|
2857
2857
|
/>
|
|
2858
2858
|
<ManualSetupCard
|
|
2859
2859
|
hint="Deploy manually to Netlify, Vercel, Cloudflare, or any Nitro-supported target."
|
|
2860
|
-
docsUrl="https://www.builder.io/c/docs/agent-native-deployment"
|
|
2860
|
+
docsUrl="https://www.builder.io/c/docs/agent-native-deployment?utm_source=agent-native&utm_medium=product&utm_campaign=onboarding&utm_content=deployment_settings"
|
|
2861
2861
|
dim={connected}
|
|
2862
2862
|
/>
|
|
2863
2863
|
</div>
|
|
@@ -2888,7 +2888,7 @@ function SettingsPanelContent({
|
|
|
2888
2888
|
/>
|
|
2889
2889
|
<ManualSetupCard
|
|
2890
2890
|
hint="Set DATABASE_URL in your .env to connect Neon, Supabase, Turso, any Postgres/SQLite database, or local PGlite with pglite:./data/pglite."
|
|
2891
|
-
docsUrl="https://www.builder.io/c/docs/agent-native-database"
|
|
2891
|
+
docsUrl="https://www.builder.io/c/docs/agent-native-database?utm_source=agent-native&utm_medium=product&utm_campaign=onboarding&utm_content=database_settings"
|
|
2892
2892
|
dim={connected}
|
|
2893
2893
|
/>
|
|
2894
2894
|
</div>
|
|
@@ -2919,7 +2919,7 @@ function SettingsPanelContent({
|
|
|
2919
2919
|
/>
|
|
2920
2920
|
<ManualSetupCard
|
|
2921
2921
|
hint="Without a provider, files are stored as base64 in your database. Fine for dev, not recommended for production."
|
|
2922
|
-
docsUrl="https://www.builder.io/c/docs/agent-native-file-uploads"
|
|
2922
|
+
docsUrl="https://www.builder.io/c/docs/agent-native-file-uploads?utm_source=agent-native&utm_medium=product&utm_campaign=onboarding&utm_content=file_upload_settings"
|
|
2923
2923
|
dim={connected}
|
|
2924
2924
|
/>
|
|
2925
2925
|
</div>
|
|
@@ -2950,7 +2950,7 @@ function SettingsPanelContent({
|
|
|
2950
2950
|
/>
|
|
2951
2951
|
<ManualSetupCard
|
|
2952
2952
|
hint="Configure Better Auth with BETTER_AUTH_SECRET and optional Google/GitHub OAuth providers."
|
|
2953
|
-
docsUrl="https://www.builder.io/c/docs/agent-native-authentication"
|
|
2953
|
+
docsUrl="https://www.builder.io/c/docs/agent-native-authentication?utm_source=agent-native&utm_medium=product&utm_campaign=onboarding&utm_content=authentication_settings"
|
|
2954
2954
|
dim={connected}
|
|
2955
2955
|
/>
|
|
2956
2956
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
2
2
|
|
|
3
|
+
import { applyBuilderUtmTrackingParams } from "../../shared/builder-link-tracking.js";
|
|
3
4
|
import { trackEvent } from "../analytics.js";
|
|
4
5
|
import { agentNativePath } from "../api-path.js";
|
|
5
6
|
import { getCallbackOrigin } from "../frame.js";
|
|
@@ -343,6 +344,8 @@ export function withBuilderConnectTrackingParams(
|
|
|
343
344
|
parsed.searchParams.set("redirect_url", parsedRedirect.toString());
|
|
344
345
|
}
|
|
345
346
|
|
|
347
|
+
applyBuilderUtmTrackingParams(parsed.searchParams, { content: source });
|
|
348
|
+
|
|
346
349
|
return parsed.toString();
|
|
347
350
|
} catch {
|
|
348
351
|
return url;
|
package/src/db/client.ts
CHANGED
|
@@ -29,6 +29,9 @@ export interface DbExec {
|
|
|
29
29
|
sql: string | { sql: string; args?: unknown[] },
|
|
30
30
|
): Promise<{ rows: any[]; rowsAffected: number }>;
|
|
31
31
|
transaction?<T>(fn: (tx: DbExec) => Promise<T>): Promise<T>;
|
|
32
|
+
atomicBatch?(
|
|
33
|
+
statements: readonly (string | { sql: string; args?: unknown[] })[],
|
|
34
|
+
): Promise<Array<{ rows: any[]; rowsAffected: number }>>;
|
|
32
35
|
/**
|
|
33
36
|
* Release the underlying connection/pool held by this exec.
|
|
34
37
|
* Only non-singleton execs created via `createDbExec()` (e.g. the migration
|
|
@@ -1100,7 +1103,17 @@ async function createDbExecInternal(
|
|
|
1100
1103
|
};
|
|
1101
1104
|
return {
|
|
1102
1105
|
execute,
|
|
1103
|
-
|
|
1106
|
+
async atomicBatch(statements) {
|
|
1107
|
+
const prepared = statements.map((statement) => {
|
|
1108
|
+
if (typeof statement === "string") return d1.prepare(statement);
|
|
1109
|
+
return d1.prepare(statement.sql).bind(...(statement.args ?? []));
|
|
1110
|
+
});
|
|
1111
|
+
const results = await d1.batch(prepared);
|
|
1112
|
+
return results.map((result: any) => ({
|
|
1113
|
+
rows: result.results || [],
|
|
1114
|
+
rowsAffected: result.meta?.changes ?? 0,
|
|
1115
|
+
}));
|
|
1116
|
+
},
|
|
1104
1117
|
};
|
|
1105
1118
|
}
|
|
1106
1119
|
|
|
@@ -1558,6 +1571,10 @@ export function getDbExec(): DbExec {
|
|
|
1558
1571
|
// After init, swap to a sanitizing wrapper around the real client
|
|
1559
1572
|
const wrapper: DbExec = {
|
|
1560
1573
|
execute: (s) => _exec!.execute(sanitize(s)),
|
|
1574
|
+
atomicBatch: _exec!.atomicBatch
|
|
1575
|
+
? (statements) =>
|
|
1576
|
+
_exec!.atomicBatch!(statements.map((s) => sanitize(s)))
|
|
1577
|
+
: undefined,
|
|
1561
1578
|
transaction: _exec!.transaction
|
|
1562
1579
|
? (fn) =>
|
|
1563
1580
|
_exec!.transaction!((tx) =>
|
|
@@ -1582,6 +1599,10 @@ export function getDbExec(): DbExec {
|
|
|
1582
1599
|
}
|
|
1583
1600
|
const wrapper: DbExec = {
|
|
1584
1601
|
execute: (s) => _exec!.execute(sanitize(s)),
|
|
1602
|
+
atomicBatch: _exec!.atomicBatch
|
|
1603
|
+
? (statements) =>
|
|
1604
|
+
_exec!.atomicBatch!(statements.map((s) => sanitize(s)))
|
|
1605
|
+
: undefined,
|
|
1585
1606
|
transaction: _exec!.transaction
|
|
1586
1607
|
? (innerFn) =>
|
|
1587
1608
|
_exec!.transaction!((tx) =>
|
|
@@ -1601,8 +1622,30 @@ export function getDbExec(): DbExec {
|
|
|
1601
1622
|
}),
|
|
1602
1623
|
);
|
|
1603
1624
|
}
|
|
1625
|
+
if (_exec!.atomicBatch) {
|
|
1626
|
+
throw new Error(
|
|
1627
|
+
"This database supports atomic batches, not interactive transactions.",
|
|
1628
|
+
);
|
|
1629
|
+
}
|
|
1604
1630
|
return explicitTransaction(wrapper.execute)(fn);
|
|
1605
1631
|
},
|
|
1632
|
+
async atomicBatch(statements) {
|
|
1633
|
+
if (!_initPromise) _initPromise = initClient();
|
|
1634
|
+
try {
|
|
1635
|
+
await _initPromise;
|
|
1636
|
+
} catch (err) {
|
|
1637
|
+
_initPromise = undefined;
|
|
1638
|
+
_exec = undefined;
|
|
1639
|
+
throw err;
|
|
1640
|
+
}
|
|
1641
|
+
if (!_exec!.atomicBatch) {
|
|
1642
|
+
throw new Error("This database does not support atomic batches.");
|
|
1643
|
+
}
|
|
1644
|
+
const batch = (items: typeof statements) =>
|
|
1645
|
+
_exec!.atomicBatch!(items.map((item) => sanitize(item)));
|
|
1646
|
+
Object.assign(proxy, { atomicBatch: batch });
|
|
1647
|
+
return batch(statements);
|
|
1648
|
+
},
|
|
1606
1649
|
};
|
|
1607
1650
|
return proxy;
|
|
1608
1651
|
}
|
|
@@ -725,9 +725,6 @@ const messages = {
|
|
|
725
725
|
chatIntegrations: "Chat Integrations",
|
|
726
726
|
chatIntegrationsDescription: "Talk to this agent from other platforms",
|
|
727
727
|
addIntegration: "Add integration",
|
|
728
|
-
addSomething: "Add something not listed",
|
|
729
|
-
addSomethingTitle: "Add another integration",
|
|
730
|
-
addSomethingPlaceholder: "Which integration should we add?",
|
|
731
728
|
dispatchEntrypoint:
|
|
732
729
|
"For a central Slack or Telegram entrypoint that can route work across multiple apps, use the",
|
|
733
730
|
sharedMessaging:
|
|
@@ -737,12 +734,9 @@ const messages = {
|
|
|
737
734
|
menuLabel: "Integrations",
|
|
738
735
|
menuDescription: "Connect MCP tools to the agent",
|
|
739
736
|
title: "Connect integrations",
|
|
740
|
-
description: "
|
|
737
|
+
description: "Browse {{count}} MCP integrations or add a custom server.",
|
|
741
738
|
searchPlaceholder: "Search integrations",
|
|
742
739
|
addYourOwn: "Add your own",
|
|
743
|
-
addSomething: "Add something not listed",
|
|
744
|
-
addSomethingTitle: "Add another integration",
|
|
745
|
-
addSomethingPlaceholder: "Which MCP or provider should we add?",
|
|
746
740
|
noMatches: "No integrations match that search.",
|
|
747
741
|
connected: "Connected",
|
|
748
742
|
configure: "Configure",
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import type { H3Event } from "h3";
|
|
9
9
|
import { getHeader } from "h3";
|
|
10
10
|
|
|
11
|
+
import { applyBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|
|
11
12
|
import {
|
|
12
13
|
getAuthSecret,
|
|
13
14
|
resolveSignupTrackingIdentity,
|
|
@@ -920,6 +921,9 @@ export function buildBuilderCliAuthUrl(
|
|
|
920
921
|
);
|
|
921
922
|
url.searchParams.set("framework", "agent-native");
|
|
922
923
|
applyBuilderConnectTrackingParams(url.searchParams, tracking);
|
|
924
|
+
applyBuilderUtmTrackingParams(url.searchParams, {
|
|
925
|
+
content: cleanTrackingParam(tracking.agentNativeConnectSource) ?? null,
|
|
926
|
+
});
|
|
923
927
|
return url.toString();
|
|
924
928
|
}
|
|
925
929
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|
|
1
2
|
import { FeatureNotConfiguredError } from "./credential-provider.js";
|
|
2
3
|
import {
|
|
3
4
|
getBuilderProxyOrigin,
|
|
@@ -356,11 +357,15 @@ function nonEmptyFiles(
|
|
|
356
357
|
|
|
357
358
|
export function builderDesignSystemUrl(designSystemId?: string | null): string {
|
|
358
359
|
const host = trimTrailingSlash(getBuilderAppHost());
|
|
359
|
-
|
|
360
|
+
const url = designSystemId
|
|
360
361
|
? `${host}/app/design-system-intelligence/${encodeURIComponent(
|
|
361
362
|
designSystemId,
|
|
362
363
|
)}`
|
|
363
364
|
: `${host}/app/design-system-intelligence`;
|
|
365
|
+
return withBuilderUtmTrackingParams(url, {
|
|
366
|
+
campaign: "product",
|
|
367
|
+
content: "design_system_intelligence",
|
|
368
|
+
});
|
|
364
369
|
}
|
|
365
370
|
|
|
366
371
|
export function localBuilderDesignSystemId(
|
package/src/server/fusion-app.ts
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* respond with newline-delimited JSON over chunked HTTP.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|
|
27
28
|
import { getBuilderApiHost, getBuilderAppHost } from "./builder-browser.js";
|
|
28
29
|
|
|
29
30
|
export interface FusionBranchRef {
|
|
@@ -86,7 +87,10 @@ function fusionUrl(
|
|
|
86
87
|
/** The Builder visual-editor URL for a fusion branch. */
|
|
87
88
|
export function getFusionBranchEditorUrl(ref: FusionBranchRef): string {
|
|
88
89
|
const host = getBuilderAppHost().replace(/\/+$/, "");
|
|
89
|
-
return
|
|
90
|
+
return withBuilderUtmTrackingParams(
|
|
91
|
+
`${host}/app/projects/${encodeURIComponent(ref.projectId)}/${encodeURIComponent(ref.branchName)}`,
|
|
92
|
+
{ campaign: "product", content: "fusion_editor" },
|
|
93
|
+
);
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
/** Public URL for a reserved fusion hosting slug. */
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const BUILDER_UTM_SOURCE = "agent-native";
|
|
2
|
+
export const BUILDER_UTM_MEDIUM = "product";
|
|
3
|
+
export const BUILDER_UTM_CAMPAIGN = "onboarding";
|
|
4
|
+
|
|
5
|
+
export function applyBuilderUtmTrackingParams(
|
|
6
|
+
params: URLSearchParams,
|
|
7
|
+
options: {
|
|
8
|
+
medium?: string;
|
|
9
|
+
campaign?: string;
|
|
10
|
+
content?: string | null;
|
|
11
|
+
} = {},
|
|
12
|
+
): void {
|
|
13
|
+
params.set("utm_source", BUILDER_UTM_SOURCE);
|
|
14
|
+
params.set("utm_medium", options.medium ?? BUILDER_UTM_MEDIUM);
|
|
15
|
+
params.set("utm_campaign", options.campaign ?? BUILDER_UTM_CAMPAIGN);
|
|
16
|
+
if (options.content) params.set("utm_content", options.content);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function withBuilderUtmTrackingParams(
|
|
20
|
+
url: string,
|
|
21
|
+
options: {
|
|
22
|
+
medium?: string;
|
|
23
|
+
campaign?: string;
|
|
24
|
+
content?: string | null;
|
|
25
|
+
} = {},
|
|
26
|
+
): string {
|
|
27
|
+
let parsed: URL;
|
|
28
|
+
try {
|
|
29
|
+
parsed = new URL(url);
|
|
30
|
+
} catch {
|
|
31
|
+
return url;
|
|
32
|
+
}
|
|
33
|
+
if (
|
|
34
|
+
parsed.hostname !== "builder.io" &&
|
|
35
|
+
parsed.hostname !== "www.builder.io"
|
|
36
|
+
) {
|
|
37
|
+
return url;
|
|
38
|
+
}
|
|
39
|
+
applyBuilderUtmTrackingParams(parsed.searchParams, options);
|
|
40
|
+
return parsed.toString();
|
|
41
|
+
}
|
package/src/shared/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export {
|
|
|
7
7
|
export { agentEnv, type EnvVar } from "./agent-env.js";
|
|
8
8
|
export { extractOAuthStateAppId } from "./oauth-state.js";
|
|
9
9
|
export { truncate } from "./truncate.js";
|
|
10
|
+
export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
|
|
10
11
|
export {
|
|
11
12
|
llmConnectionTrackingProperties,
|
|
12
13
|
normalizeLlmConnection,
|