@agent-native/core 0.157.0 → 0.157.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 +1 -1
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +19 -4
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +7 -2
- package/corpus/templates/assets/app/global.css +4 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +1 -2
- package/corpus/templates/brain/app/routes/sources.tsx +1 -2
- package/corpus/templates/calendar/app/hooks/use-bookings.ts +12 -2
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +64 -2
- package/corpus/templates/calendar/server/handlers/bookings.ts +224 -93
- package/corpus/templates/calendar/server/plugins/auth.ts +0 -2
- package/corpus/templates/clips/actions/create-folder.ts +7 -1
- package/corpus/templates/clips/actions/create-meeting.ts +6 -2
- package/corpus/templates/clips/actions/create-recording.ts +5 -3
- package/corpus/templates/clips/actions/finalize-recording.ts +97 -65
- package/corpus/templates/clips/actions/import-loom-recording.ts +5 -3
- package/corpus/templates/clips/actions/request-recording-access.ts +305 -0
- package/corpus/templates/clips/actions/stitch-recordings.ts +5 -3
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +38 -63
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +75 -75
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +3 -21
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +13 -30
- package/corpus/templates/clips/app/i18n/en-US.ts +10 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -5
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +9 -16
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +135 -18
- package/corpus/templates/clips/changelog/2026-08-14-long-resumable-uploads-now-abort-cleanly-and-show-errors.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-14-standardized-share-popovers.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +11 -3
- package/corpus/templates/clips/chrome-extension/src/github-preview-content.ts +37 -8
- package/corpus/templates/clips/chrome-extension/src/github-preview.ts +3 -3
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -25
- package/corpus/templates/clips/desktop/src/app.tsx +24 -0
- package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +42 -13
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +11 -18
- package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +1 -0
- package/corpus/templates/clips/desktop/src/shared/config.ts +1 -0
- package/corpus/templates/clips/desktop/src/styles.css +24 -9
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +8 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +154 -176
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +115 -31
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +7 -0
- package/corpus/templates/clips/server/db/index.ts +1 -0
- package/corpus/templates/clips/server/db/schema.ts +1 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +6 -1
- package/corpus/templates/clips/server/lib/emails.ts +23 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +55 -0
- package/corpus/templates/clips/server/lib/recordings.ts +2 -1
- package/corpus/templates/clips/server/lib/resumable-upload-cleanup.ts +49 -0
- package/corpus/templates/clips/server/lib/s3-upload-provider.ts +34 -7
- package/corpus/templates/clips/server/lib/upload-interruption.ts +15 -1
- package/corpus/templates/clips/server/lib/upload-lease.ts +94 -9
- package/corpus/templates/clips/server/routes/api/agent-context.json.get.ts +82 -7
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +1 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +71 -12
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +4 -3
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +133 -4
- package/corpus/templates/clips/server/routes/api/uploads/reap.post.ts +8 -1
- package/corpus/templates/clips/shared/recording-link.ts +4 -0
- package/corpus/templates/clips/shared/share-loader-response.ts +2 -1
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +7 -16
- package/corpus/templates/factory/AGENTS.md +5 -1
- package/corpus/templates/factory/README.md +6 -2
- package/corpus/templates/factory/actions/view-screen.ts +15 -0
- package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +58 -189
- package/corpus/templates/factory/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/factory/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +7 -0
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +3 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +3 -1
- package/corpus/templates/factory/app/routes/agents.tsx +9 -0
- package/corpus/templates/mail/server/plugins/auth.ts +0 -2
- package/corpus/templates/plan/app/components/plan/LocalCodebasePicker.tsx +50 -14
- package/corpus/templates/plan/app/pages/PlansPage.tsx +9 -19
- package/corpus/templates/slides/app/components/editor/HistoryPanel.tsx +7 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +71 -22
- package/corpus/templates/slides/app/lib/editor-shortcuts.ts +46 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +13 -0
- package/dist/client/AgentPanel.d.ts +13 -1
- package/dist/client/AgentPanel.js +12 -10
- package/dist/client/AssistantChat.js +25 -5
- package/dist/client/HighlightedCodeBlock.js +12 -2
- package/dist/client/agent-chat/index.d.ts +1 -0
- package/dist/client/agent-chat/index.js +1 -0
- package/dist/client/chat/markdown-renderer.js +16 -3
- package/dist/client/chat-first/apps-rail.js +1 -1
- package/dist/client/components/ui/message-scroller.js +1 -1
- package/dist/client/settings/AccountSettingsCard.js +48 -19
- package/dist/client/sharing/ShareButton.d.ts +1 -2
- package/dist/client/sharing/ShareButton.js +5 -41
- package/dist/client/sharing/ShareDialog.js +5 -4
- package/dist/client/use-chat-threads.js +10 -14
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.js +1 -0
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +15 -15
- package/dist/server/auth-marketing.d.ts +1 -0
- package/dist/server/auth-marketing.js +0 -2
- package/dist/server/auth.d.ts +1 -0
- package/dist/server/auth.js +18 -0
- package/dist/server/onboarding-html.d.ts +1 -0
- package/dist/server/onboarding-html.js +2 -88
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/shared/markdown-block-split.d.ts +16 -0
- package/dist/shared/markdown-block-split.js +81 -5
- package/dist/styles/agent-native.css +13 -0
- package/dist/voice/voice-cleanup-prompt.js +1 -0
- package/docs/content/cloneable-saas.mdx +24 -26
- package/package.json +3 -3
- package/corpus/templates/clips/shared/mic-audio-cleanup.ts +0 -350
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ActionButton, Avatar, TextField, } from "@agent-native/toolkit/design-system";
|
|
3
|
-
import { IconCamera, IconCheck, IconLock } from "@tabler/icons-react";
|
|
2
|
+
import { ActionButton, Avatar, IconButton, TextField, } from "@agent-native/toolkit/design-system";
|
|
3
|
+
import { IconCamera, IconCheck, IconLock, IconPencil, } from "@tabler/icons-react";
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
5
|
import { PASSWORD_MIN_LENGTH } from "../../shared/password-policy.js";
|
|
6
6
|
import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
|
|
7
|
+
import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
|
|
7
8
|
import { useT } from "../i18n.js";
|
|
8
9
|
import { useActionMutation, useActionQuery } from "../use-action.js";
|
|
9
10
|
import { uploadAvatar, useAvatarUrl } from "../use-avatar.js";
|
|
@@ -107,21 +108,23 @@ export function AccountSettingsForm({ compact = false, }) {
|
|
|
107
108
|
const [uploading, setUploading] = useState(false);
|
|
108
109
|
const [photoStatus, setPhotoStatus] = useState("idle");
|
|
109
110
|
const [name, setName] = useState("");
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
const [savedName, setSavedName] = useState("");
|
|
112
|
+
const [isEditingName, setIsEditingName] = useState(false);
|
|
113
|
+
const nameFieldEditedRef = useRef(false);
|
|
114
|
+
const profileName = profileQuery.data?.name || session?.name || "";
|
|
115
|
+
const displayName = name || profileName || email || t("settings.profileSignedOut");
|
|
115
116
|
useEffect(() => {
|
|
116
|
-
|
|
117
|
+
nameFieldEditedRef.current = false;
|
|
118
|
+
setIsEditingName(false);
|
|
119
|
+
setName("");
|
|
120
|
+
setSavedName("");
|
|
117
121
|
}, [email]);
|
|
118
122
|
useEffect(() => {
|
|
119
|
-
if (
|
|
123
|
+
if (nameFieldEditedRef.current)
|
|
120
124
|
return;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}, [profileQuery.data?.name, session?.name]);
|
|
125
|
+
setName(profileName);
|
|
126
|
+
setSavedName(profileName);
|
|
127
|
+
}, [email, profileName]);
|
|
125
128
|
const handleAvatarChange = async (event) => {
|
|
126
129
|
const file = event.target.files?.[0];
|
|
127
130
|
event.target.value = "";
|
|
@@ -142,20 +145,46 @@ export function AccountSettingsForm({ compact = false, }) {
|
|
|
142
145
|
};
|
|
143
146
|
const handleProfileSave = () => {
|
|
144
147
|
const nextName = name.trim();
|
|
145
|
-
if (!nextName || !email)
|
|
148
|
+
if (!nextName || !email || nextName === savedName.trim())
|
|
146
149
|
return;
|
|
147
|
-
updateProfile.mutate({ name: nextName }
|
|
150
|
+
updateProfile.mutate({ name: nextName }, {
|
|
151
|
+
onSuccess: (profile) => {
|
|
152
|
+
setName(profile.name);
|
|
153
|
+
setSavedName(profile.name);
|
|
154
|
+
nameFieldEditedRef.current = false;
|
|
155
|
+
setIsEditingName(false);
|
|
156
|
+
},
|
|
157
|
+
});
|
|
148
158
|
};
|
|
159
|
+
const handleProfileEdit = () => {
|
|
160
|
+
updateProfile.reset();
|
|
161
|
+
nameFieldEditedRef.current = false;
|
|
162
|
+
setName(savedName);
|
|
163
|
+
setIsEditingName(true);
|
|
164
|
+
};
|
|
165
|
+
const handleProfileCancel = () => {
|
|
166
|
+
updateProfile.reset();
|
|
167
|
+
nameFieldEditedRef.current = false;
|
|
168
|
+
setName(savedName);
|
|
169
|
+
setIsEditingName(false);
|
|
170
|
+
};
|
|
171
|
+
const canSaveName = !!email &&
|
|
172
|
+
!updateProfile.isPending &&
|
|
173
|
+
!!name.trim() &&
|
|
174
|
+
name.trim() !== savedName.trim();
|
|
149
175
|
const profileStatus = photoStatus === "saved" ? (_jsx("span", { className: "text-primary", children: t("settings.profilePhotoUpdated") })) : photoStatus === "error" ? (_jsx("span", { className: "text-destructive", children: t("settings.profilePhotoError") })) : email ? (email) : undefined;
|
|
150
176
|
return (_jsxs(SettingsGroup, { id: "account", title: t("settings.profileTitle"), description: t("settings.profileDescription"), className: cn(compact && "[&>div:last-child>div>div]:py-3"), children: [_jsx(SettingsRow, { id: "profile", label: t("settings.profileTitle"), description: profileStatus, control: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Avatar, { name: displayName, src: avatarUrl, fallback: profileInitials(displayName), size: "default", className: "size-10 shrink-0 rounded-full border border-border bg-accent font-semibold text-muted-foreground" }), _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", className: "hidden", onChange: handleAvatarChange }), _jsx(ActionButton, { type: "button", intent: "neutral", emphasis: "outline", size: "compact", disabled: !email || uploading, leadingIcon: _jsx(IconCamera, { className: "size-3.5" }), onPress: () => fileInputRef.current?.click(), children: uploading
|
|
151
177
|
? t("settings.profileUploading")
|
|
152
|
-
: t("settings.profileChangePhoto") })] }) }), _jsx(SettingsRow, { id: "profile-name", label: t("settings.profileNameLabel"), description: updateProfile.isSuccess ? (_jsx("span", { className: "text-primary", children: t("settings.profileSaved") })) : updateProfile.error ? (_jsx("span", { className: "text-destructive", children: t("settings.profileSaveError") })) : (t("settings.profileNameDescription")), control: _jsxs("div", { className: "flex w-full items-center gap-2 sm:w-80", children: [_jsx(TextField, { id: "agent-native-profile-name", value: name, onChange: (value) => {
|
|
153
|
-
|
|
178
|
+
: t("settings.profileChangePhoto") })] }) }), _jsx(SettingsRow, { id: "profile-name", label: t("settings.profileNameLabel"), description: updateProfile.isSuccess ? (_jsx("span", { className: "text-primary", children: t("settings.profileSaved") })) : updateProfile.error ? (_jsx("span", { className: "text-destructive", children: t("settings.profileSaveError") })) : (t("settings.profileNameDescription")), control: isEditingName ? (_jsxs("div", { className: "flex w-full items-center gap-2 sm:w-80", children: [_jsx(TextField, { id: "agent-native-profile-name", value: name, onChange: (value) => {
|
|
179
|
+
nameFieldEditedRef.current = true;
|
|
154
180
|
updateProfile.reset();
|
|
155
181
|
setName(value);
|
|
156
|
-
}, placeholder: t("settings.profileNamePlaceholder"), disabled: !email || updateProfile.isPending, "aria-label": t("settings.profileNameLabel"), className: "min-w-0 flex-1"
|
|
182
|
+
}, placeholder: t("settings.profileNamePlaceholder"), disabled: !email || updateProfile.isPending, autoFocus: true, "aria-label": t("settings.profileNameLabel"), className: "min-w-0 flex-1", onKeyDown: (event) => {
|
|
183
|
+
if (event.key === "Escape")
|
|
184
|
+
handleProfileCancel();
|
|
185
|
+
} }), _jsx(ActionButton, { type: "button", intent: "primary", emphasis: "solid", size: "compact", pending: updateProfile.isPending, disabled: !canSaveName, onPress: handleProfileSave, children: updateProfile.isPending
|
|
157
186
|
? t("settings.profileSaving")
|
|
158
|
-
: t("settings.profileSave") })] }) }), _jsx(SettingsRow, { id: "timezone", label: t("settings.timezoneLabel", { defaultValue: "Timezone" }), description: t("settings.timezoneHint", {
|
|
187
|
+
: t("settings.profileSave") })] })) : (_jsxs("div", { className: "flex w-full items-center justify-end gap-2 sm:w-80", children: [_jsx("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: displayName }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(IconButton, { type: "button", intent: "neutral", emphasis: "ghost", size: "compact", icon: _jsx(IconPencil, { size: 14 }), label: t("settings.profileNameEdit"), title: t("settings.profileNameEdit"), disabled: !email, onPress: handleProfileEdit }) }), _jsx(TooltipContent, { children: t("settings.profileNameEdit") })] })] })) }), _jsx(SettingsRow, { id: "timezone", label: t("settings.timezoneLabel", { defaultValue: "Timezone" }), description: t("settings.timezoneHint", {
|
|
159
188
|
defaultValue: "Used for timestamps and scheduled automations.",
|
|
160
189
|
}), control: _jsx(SchedulingTimezoneField, { compact: true }) }), _jsx(PasswordSettings, {})] }));
|
|
161
190
|
}
|
|
@@ -7,8 +7,7 @@ export interface ShareButtonProps {
|
|
|
7
7
|
/** @deprecated No longer affects rendering — trigger always says
|
|
8
8
|
* "Share". Kept for callsite compatibility. */
|
|
9
9
|
variant?: "compact" | "label";
|
|
10
|
-
/**
|
|
11
|
-
* "label-icon" opts into an icon plus label; "icon" is icon-only. */
|
|
10
|
+
/** @deprecated Share triggers are standardized as text-only buttons. */
|
|
12
11
|
trigger?: "label" | "icon" | "label-icon";
|
|
13
12
|
/** @deprecated No longer affects rendering — kept for callsite compatibility. */
|
|
14
13
|
hideTriggerIcon?: boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ShareCopyRow, ShareTrigger } from "@agent-native/toolkit/sharing";
|
|
2
3
|
import * as Select from "@radix-ui/react-select";
|
|
3
|
-
import { IconLock, IconWorld, IconTrash, IconCheck, IconChevronDown, IconLoader2,
|
|
4
|
+
import { IconLock, IconWorld, IconTrash, IconCheck, IconChevronDown, IconLoader2, IconSearch, IconSearchOff, IconUsersGroup, } from "@tabler/icons-react";
|
|
4
5
|
import { useEffect, useId, useRef, useState, } from "react";
|
|
5
6
|
import { writeClipboardText } from "../clipboard.js";
|
|
6
7
|
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
|
|
@@ -10,7 +11,6 @@ import { useShareButtonController, } from "./useShareButtonController.js";
|
|
|
10
11
|
// Match shadcn's <Button size="sm" variant="outline"> sizing so the trigger
|
|
11
12
|
// sits flush next to other controls while staying transparent at rest.
|
|
12
13
|
const BUTTON_BASE = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0";
|
|
13
|
-
const BUTTON_OUTLINE_SM = cn(BUTTON_BASE, "h-9 px-3 border border-[hsl(var(--sidebar-border,var(--input)))] bg-transparent text-foreground hover:bg-[hsl(var(--sidebar-accent,var(--accent)))] hover:text-[hsl(var(--sidebar-accent-foreground,var(--accent-foreground)))]");
|
|
14
14
|
const BUTTON_PRIMARY_SM = cn(BUTTON_BASE, "h-9 px-4 bg-primary text-primary-foreground hover:bg-primary/90");
|
|
15
15
|
const BUTTON_GHOST_ICON = cn(BUTTON_BASE, "h-7 w-7 p-0 text-muted-foreground hover:bg-accent hover:text-accent-foreground");
|
|
16
16
|
const SHARE_POPOVER_SURFACE = "border border-border bg-popover text-popover-foreground";
|
|
@@ -124,20 +124,8 @@ export function ShareButton(props) {
|
|
|
124
124
|
allowedRoles: props.allowedRoles,
|
|
125
125
|
hideInSearchControl: props.hideInSearchControl,
|
|
126
126
|
});
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
? visibilityMeta(triggerVisibility, t, props.visibilityCopy)
|
|
130
|
-
: null;
|
|
131
|
-
const TriggerIcon = triggerMeta?.Icon ?? IconShare3;
|
|
132
|
-
const iconOnly = props.trigger === "icon";
|
|
133
|
-
const showTriggerIcon = iconOnly || props.trigger === "label-icon";
|
|
134
|
-
const triggerLabel = iconOnly && triggerMeta
|
|
135
|
-
? t("agentChat.share.triggerWithVisibility", {
|
|
136
|
-
defaultValue: "Share ({{visibility}})",
|
|
137
|
-
visibility: triggerMeta.label,
|
|
138
|
-
})
|
|
139
|
-
: t("agentChat.share.share", { defaultValue: "Share" });
|
|
140
|
-
return (_jsxs(Popover, { open: controller.open, onOpenChange: controller.handleOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn(iconOnly ? BUTTON_GHOST_ICON : BUTTON_OUTLINE_SM, props.triggerClassName), "aria-label": triggerLabel, title: triggerLabel, children: [showTriggerIcon && _jsx(TriggerIcon, { size: 16, strokeWidth: 1.75 }), !iconOnly && (_jsx("span", { children: t("agentChat.share.share", { defaultValue: "Share" }) }))] }) }), _jsx(PopoverContent, { align: "end", sideOffset: 6, "data-agent-native-share-overlay": "", className: cn("z-[2000] w-[min(460px,92vw)] rounded-lg p-4 shadow-lg", SHARE_POPOVER_SURFACE, props.popoverClassName), onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: handleSharePopoverInteractOutside, children: _jsx(SharePanel, { ...props, controller: controller }) })] }));
|
|
127
|
+
const triggerLabel = t("agentChat.share.share", { defaultValue: "Share" });
|
|
128
|
+
return (_jsxs(Popover, { open: controller.open, onOpenChange: controller.handleOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(ShareTrigger, { label: triggerLabel, className: props.triggerClassName, "aria-label": triggerLabel, title: triggerLabel }) }), _jsx(PopoverContent, { align: "end", sideOffset: 6, "data-agent-native-share-overlay": "", className: cn("z-[2000] w-[min(460px,92vw)] rounded-lg p-4 shadow-lg", SHARE_POPOVER_SURFACE, props.popoverClassName), onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: handleSharePopoverInteractOutside, children: _jsx(SharePanel, { ...props, controller: controller }) })] }));
|
|
141
129
|
}
|
|
142
130
|
function SharePanel(props) {
|
|
143
131
|
const t = useT();
|
|
@@ -341,31 +329,7 @@ function optionId(baseId, index) {
|
|
|
341
329
|
}
|
|
342
330
|
function CopyLinkField({ value, label, description, }) {
|
|
343
331
|
const t = useT();
|
|
344
|
-
|
|
345
|
-
const resetRef = useRef(undefined);
|
|
346
|
-
useEffect(() => {
|
|
347
|
-
return () => {
|
|
348
|
-
if (resetRef.current)
|
|
349
|
-
clearTimeout(resetRef.current);
|
|
350
|
-
};
|
|
351
|
-
}, []);
|
|
352
|
-
const handleCopy = async () => {
|
|
353
|
-
if (await writeClipboardText(value)) {
|
|
354
|
-
setCopied(true);
|
|
355
|
-
if (resetRef.current)
|
|
356
|
-
clearTimeout(resetRef.current);
|
|
357
|
-
resetRef.current = setTimeout(() => setCopied(false), 1400);
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
setCopied(false);
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
return (_jsxs("div", { className: "mb-4 flex items-center justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-semibold", children: label ??
|
|
364
|
-
t("agentChat.share.shareLink", { defaultValue: "Share link" }) }), description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: description })) : null] }), _jsxs("button", { type: "button", onClick: handleCopy, "aria-label": copied
|
|
365
|
-
? t("agentChat.share.copied", { defaultValue: "Copied" })
|
|
366
|
-
: t("agentChat.share.copy", { defaultValue: "Copy" }), className: "inline-flex h-9 shrink-0 items-center gap-2 whitespace-nowrap rounded-md border border-input bg-card px-3 text-sm font-medium text-foreground hover:bg-accent", children: [copied ? _jsx(IconCheck, { size: 15 }) : _jsx(IconLink, { size: 15 }), copied
|
|
367
|
-
? t("agentChat.share.copied", { defaultValue: "Copied" })
|
|
368
|
-
: t("agentChat.share.copy", { defaultValue: "Copy" })] })] }));
|
|
332
|
+
return (_jsx(ShareCopyRow, { value: value, label: label ?? t("agentChat.share.shareLink", { defaultValue: "Share link" }), description: description, copyLabel: t("agentChat.share.copy", { defaultValue: "Copy" }), copiedLabel: t("agentChat.share.copied", { defaultValue: "Copied" }), onCopy: writeClipboardText, className: "mb-4" }));
|
|
369
333
|
}
|
|
370
334
|
// ---------------------------------------------------------------------------
|
|
371
335
|
// Radix Select wrappers styled like shadcn Select (no native <select> anywhere)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ActionButton, Avatar as DesignSystemAvatar, Dialog as DesignSystemDialog, IconButton, Picker, Status, TextArea,
|
|
2
|
+
import { ActionButton, Avatar as DesignSystemAvatar, Dialog as DesignSystemDialog, IconButton, Picker, Status, TextArea, } from "@agent-native/toolkit/design-system";
|
|
3
|
+
import { ShareCopyRow } from "@agent-native/toolkit/sharing";
|
|
3
4
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@agent-native/toolkit/ui";
|
|
4
5
|
import { IconCheck, IconCode, IconCopy, IconChevronDown, IconLink, IconLock, IconMail, IconTrash, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
|
|
5
6
|
import { useState } from "react";
|
|
@@ -53,7 +54,7 @@ function TabTrigger({ active, onClick, icon, label, }) {
|
|
|
53
54
|
}
|
|
54
55
|
function LinkTab({ controller, extras, }) {
|
|
55
56
|
const Icon = VIS_ICONS[controller.visibility.value];
|
|
56
|
-
return (_jsxs("div", { className: "space-y-3", children: [_jsx(
|
|
57
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsx(ShareCopyRow, { label: controller.labels.shareLink, value: controller.shareUrl, copyLabel: controller.labels.copy, copiedLabel: "Copied", onCopy: (value) => controller.copy("share-link", value), className: "mb-4" }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: controller.labels.generalAccess }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { controller: controller }), _jsx("div", { className: "sr-only text-xs text-muted-foreground", children: controller.visibility.description })] })] })] }), extras] }));
|
|
57
58
|
}
|
|
58
59
|
function InviteTab({ controller, showVisibility, }) {
|
|
59
60
|
const Icon = VIS_ICONS[controller.visibility.value];
|
|
@@ -71,11 +72,11 @@ function PersonRow({ person, canManage, removeLabel, onRemove, }) {
|
|
|
71
72
|
return (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(DesignSystemAvatar, { name: person.label, fallback: person.principalType === "org" ? (_jsx(IconUsersGroup, { size: 14, strokeWidth: 1.75 })) : (person.avatarText), size: "compact", className: "inline-flex h-7 w-7 shrink-0 text-[11px] font-semibold" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: person.label }), _jsx(Status, { tone: "neutral", size: "compact", className: "border-0 bg-transparent px-0 text-xs text-muted-foreground", children: person.roleLabel }), canManage && person.share ? (_jsx(IconButton, { intent: "danger", emphasis: "ghost", size: "compact", icon: _jsx(IconTrash, { size: 14 }), label: removeLabel, "aria-label": removeLabel, onPress: () => onRemove(person.share), className: cn(BUTTON_GHOST_ICON, "[&_svg]:!size-auto") })) : null] }));
|
|
72
73
|
}
|
|
73
74
|
function DefaultEmbedBody({ controller, }) {
|
|
74
|
-
return (_jsxs("div", { className: "space-y-3", children: [_jsx(
|
|
75
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsx(ShareCopyRow, { label: controller.labels.embedUrl, value: controller.embedUrl, copyLabel: controller.labels.copy, copiedLabel: "Copied", onCopy: (value) => controller.copy("embed-url", value) }), _jsx(CopyField, { field: "embed-code", label: controller.labels.embedCode, value: controller.embedCode, controller: controller, multiline: true })] }));
|
|
75
76
|
}
|
|
76
77
|
function CopyField({ field, label, value, controller, multiline, }) {
|
|
77
78
|
const copied = controller.copiedField === field;
|
|
78
|
-
return (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: label }), _jsxs("div", { className: "flex items-stretch gap-2", children: [multiline ? (_jsx(TextArea, { readOnly: true, value: value, onChange: () => undefined, "aria-label": label, className: "flex-1 h-20 text-xs font-mono" })) :
|
|
79
|
+
return (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs font-medium text-muted-foreground", children: label }), _jsxs("div", { className: "flex items-stretch gap-2", children: [multiline ? (_jsx(TextArea, { readOnly: true, value: value, onChange: () => undefined, "aria-label": label, className: "flex-1 h-20 text-xs font-mono" })) : null, _jsx(IconButton, { emphasis: "outline", size: "compact", icon: copied ? _jsx(IconCheck, { size: 14 }) : _jsx(IconCopy, { size: 14 }), label: controller.labels.copy, onPress: () => void controller.copy(field, value), "aria-label": controller.labels.copy, className: cn(BUTTON_OUTLINE_SM, "!w-9 !px-0 [&_svg]:!size-auto") })] })] }));
|
|
79
80
|
}
|
|
80
81
|
function RoleSelect({ controller }) {
|
|
81
82
|
return (_jsx(Picker, { mode: "select", options: controller.invite.roleOptions, value: controller.invite.role, onChange: (value) => {
|
|
@@ -466,17 +466,11 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
466
466
|
// - savedId in newlyCreatedRef (we just created it this session) → keep
|
|
467
467
|
// it; the server hasn't seen it yet because there's no POST anymore,
|
|
468
468
|
// the row gets written when the user sends a message.
|
|
469
|
-
// - savedId is set but
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
//
|
|
473
|
-
//
|
|
474
|
-
// Keep it exactly as the user left it: re-register it as an optimistic
|
|
475
|
-
// empty tab rather than resurrecting an unrelated old conversation. The
|
|
476
|
-
// composer is fully functional with this id (the server writes the row
|
|
477
|
-
// on first message, same as any new tab), so there's no 404 to avoid.
|
|
478
|
-
// This is what makes "the state you left is the state you see on
|
|
479
|
-
// refresh" hold — stale (>12h) tabs are still cleared downstream.
|
|
469
|
+
// - savedId is set but not on the current page → look it up directly. A
|
|
470
|
+
// found thread stays active. An auto-creating surface replaces a confirmed
|
|
471
|
+
// 404 with a fresh local tab rather than reusing an inaccessible server id.
|
|
472
|
+
// A list-only surface keeps the saved id as an optimistic empty tab so a
|
|
473
|
+
// never-posted tab remains selectable after reload.
|
|
480
474
|
// - No savedId → synthesize a fresh local id (no POST; server creates the
|
|
481
475
|
// row on first message). The server may contain chats from another
|
|
482
476
|
// branch, preview, or project that shares the same user/database, so
|
|
@@ -505,7 +499,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
505
499
|
? loadedThreads.find((t) => t.id === restoredId)
|
|
506
500
|
: undefined;
|
|
507
501
|
// One page, so absence from it is not absence from the server — this is what
|
|
508
|
-
// separates an older real thread from
|
|
502
|
+
// separates an older real thread from an unavailable saved id below.
|
|
509
503
|
const restoredThread = lookupRestored && !restoredOnPage
|
|
510
504
|
? await fetchThreadById(apiUrl, restoredId)
|
|
511
505
|
: restoredOnPage;
|
|
@@ -515,11 +509,13 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
|
|
|
515
509
|
setIsLoading(false);
|
|
516
510
|
return;
|
|
517
511
|
}
|
|
512
|
+
const restoredIsUnavailable = restoredThread === null && lookupRestored && !restoredOnPage;
|
|
518
513
|
const restoredBelongsElsewhere = Boolean(restoredThread &&
|
|
519
514
|
!threadCanStayVisibleInScope(restoredThread.scope ?? null, scopeRef.current));
|
|
520
|
-
|
|
515
|
+
const restoredNeedsReplacement = restoredBelongsElsewhere || (restoredIsUnavailable && autoCreate);
|
|
516
|
+
if (restoredNeedsReplacement)
|
|
521
517
|
setActiveThreadId(null);
|
|
522
|
-
const savedId =
|
|
518
|
+
const savedId = restoredNeedsReplacement ? null : restoredId;
|
|
523
519
|
const loadedHasSavedId = Boolean(savedId &&
|
|
524
520
|
(restoredThread || loadedThreads.some((t) => t.id === savedId)));
|
|
525
521
|
const savedIdCameFromRoute = Boolean(savedId) &&
|
|
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
62
62
|
error: string;
|
|
63
63
|
states?: undefined;
|
|
64
64
|
} | {
|
|
65
|
+
error?: undefined;
|
|
65
66
|
states: {
|
|
66
67
|
clientId: number;
|
|
67
68
|
state: string;
|
|
68
69
|
}[];
|
|
69
|
-
error?: undefined;
|
|
70
70
|
}>>;
|
|
71
71
|
/**
|
|
72
72
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
77
77
|
error: string;
|
|
78
78
|
users?: undefined;
|
|
79
79
|
} | {
|
|
80
|
+
error?: undefined;
|
|
80
81
|
users: {
|
|
81
82
|
clientId: number;
|
|
82
83
|
lastSeen: number;
|
|
83
84
|
}[];
|
|
84
|
-
error?: undefined;
|
|
85
85
|
}>>;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
ok?: undefined;
|
|
30
29
|
error: string;
|
|
30
|
+
ok?: undefined;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
error: string;
|
|
17
16
|
ok?: undefined;
|
|
17
|
+
error: string;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -51,6 +51,7 @@ const messages = {
|
|
|
51
51
|
profileUploading: "Uploading...",
|
|
52
52
|
profileChangePhoto: "Change photo",
|
|
53
53
|
profileNameLabel: "Name",
|
|
54
|
+
profileNameEdit: "Edit name",
|
|
54
55
|
profileNamePlaceholder: "Your name",
|
|
55
56
|
profileNameDescription: "This name is used when referring to you across Agent-Native apps.",
|
|
56
57
|
profileSave: "Save changes",
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
* DELETE /_agent-native/notifications/:id — delete
|
|
12
12
|
*/
|
|
13
13
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
14
|
+
error?: undefined;
|
|
14
15
|
count: number;
|
|
15
16
|
updated?: undefined;
|
|
16
|
-
error?: undefined;
|
|
17
17
|
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
|
+
error?: undefined;
|
|
19
20
|
count?: undefined;
|
|
20
21
|
updated: number;
|
|
21
|
-
error?: undefined;
|
|
22
22
|
ok?: undefined;
|
|
23
23
|
} | {
|
|
24
24
|
count?: undefined;
|
|
@@ -26,8 +26,8 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
error: string;
|
|
27
27
|
ok?: undefined;
|
|
28
28
|
} | {
|
|
29
|
+
error?: undefined;
|
|
29
30
|
count?: undefined;
|
|
30
31
|
updated?: undefined;
|
|
31
|
-
error?: undefined;
|
|
32
32
|
ok: boolean;
|
|
33
33
|
}>>;
|
|
@@ -75,11 +75,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
+
deleted?: undefined;
|
|
78
79
|
id?: undefined;
|
|
79
80
|
provider?: undefined;
|
|
80
|
-
deleted?: undefined;
|
|
81
|
-
found?: undefined;
|
|
82
|
-
message?: undefined;
|
|
83
81
|
providers: {
|
|
84
82
|
id: string;
|
|
85
83
|
label: string;
|
|
@@ -90,44 +88,46 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
90
88
|
updatedAt: number;
|
|
91
89
|
}[];
|
|
92
90
|
count: number;
|
|
91
|
+
found?: undefined;
|
|
93
92
|
registered?: undefined;
|
|
94
93
|
label?: undefined;
|
|
94
|
+
message?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
id?: undefined;
|
|
97
96
|
deleted?: undefined;
|
|
98
|
-
|
|
97
|
+
id?: undefined;
|
|
99
98
|
providers?: undefined;
|
|
100
99
|
count?: undefined;
|
|
101
100
|
found: boolean;
|
|
102
101
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
103
102
|
registered?: undefined;
|
|
104
103
|
label?: undefined;
|
|
104
|
+
message?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
provider?: undefined;
|
|
107
106
|
deleted?: undefined;
|
|
108
|
-
|
|
107
|
+
provider?: undefined;
|
|
109
108
|
providers?: undefined;
|
|
110
109
|
count?: undefined;
|
|
111
110
|
found: boolean;
|
|
112
111
|
id: string;
|
|
113
112
|
registered?: undefined;
|
|
114
113
|
label?: undefined;
|
|
114
|
+
message?: undefined;
|
|
115
115
|
} | {
|
|
116
116
|
provider?: undefined;
|
|
117
|
-
found?: undefined;
|
|
118
|
-
message?: undefined;
|
|
119
117
|
providers?: undefined;
|
|
120
118
|
count?: undefined;
|
|
119
|
+
found?: undefined;
|
|
121
120
|
deleted: boolean;
|
|
122
121
|
id: string;
|
|
123
122
|
registered?: undefined;
|
|
124
123
|
label?: undefined;
|
|
124
|
+
message?: undefined;
|
|
125
125
|
} | {
|
|
126
|
-
provider?: undefined;
|
|
127
126
|
deleted?: undefined;
|
|
128
|
-
|
|
127
|
+
provider?: undefined;
|
|
129
128
|
providers?: undefined;
|
|
130
129
|
count?: undefined;
|
|
130
|
+
found?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
@@ -312,7 +312,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
314
|
id?: undefined;
|
|
315
|
-
|
|
315
|
+
message?: undefined;
|
|
316
|
+
deleted?: undefined;
|
|
316
317
|
providers: {
|
|
317
318
|
id: string;
|
|
318
319
|
label: string;
|
|
@@ -324,46 +325,45 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
324
325
|
}[];
|
|
325
326
|
count: number;
|
|
326
327
|
provider?: undefined;
|
|
327
|
-
|
|
328
|
+
found?: undefined;
|
|
328
329
|
registered?: undefined;
|
|
329
330
|
label?: undefined;
|
|
330
|
-
message?: undefined;
|
|
331
331
|
} | {
|
|
332
332
|
id?: undefined;
|
|
333
|
-
|
|
333
|
+
message?: undefined;
|
|
334
334
|
count?: undefined;
|
|
335
|
+
deleted?: undefined;
|
|
336
|
+
providers?: undefined;
|
|
335
337
|
found: boolean;
|
|
336
338
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
337
|
-
deleted?: undefined;
|
|
338
339
|
registered?: undefined;
|
|
339
340
|
label?: undefined;
|
|
340
|
-
message?: undefined;
|
|
341
341
|
} | {
|
|
342
|
-
|
|
342
|
+
message?: undefined;
|
|
343
343
|
count?: undefined;
|
|
344
|
+
deleted?: undefined;
|
|
345
|
+
providers?: undefined;
|
|
344
346
|
provider?: undefined;
|
|
345
347
|
found: boolean;
|
|
346
348
|
id: string;
|
|
347
|
-
deleted?: undefined;
|
|
348
349
|
registered?: undefined;
|
|
349
350
|
label?: undefined;
|
|
350
|
-
message?: undefined;
|
|
351
351
|
} | {
|
|
352
|
-
|
|
353
|
-
providers?: undefined;
|
|
352
|
+
message?: undefined;
|
|
354
353
|
count?: undefined;
|
|
354
|
+
providers?: undefined;
|
|
355
355
|
provider?: undefined;
|
|
356
|
+
found?: undefined;
|
|
356
357
|
deleted: boolean;
|
|
357
358
|
id: string;
|
|
358
359
|
registered?: undefined;
|
|
359
360
|
label?: undefined;
|
|
360
|
-
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
-
found?: undefined;
|
|
363
|
-
providers?: undefined;
|
|
364
362
|
count?: undefined;
|
|
365
|
-
provider?: undefined;
|
|
366
363
|
deleted?: undefined;
|
|
364
|
+
providers?: undefined;
|
|
365
|
+
provider?: undefined;
|
|
366
|
+
found?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
369
369
|
label: string;
|
|
@@ -53,7 +53,6 @@ export const BUILT_IN_AUTH_MARKETING = {
|
|
|
53
53
|
"Review PR recaps with diagrams, file maps, and annotated code",
|
|
54
54
|
"Share links for async comments and product review",
|
|
55
55
|
],
|
|
56
|
-
runLocalCommand: PLAN_LOCAL_FILES_COMMAND,
|
|
57
56
|
signupLocalModeNote: {
|
|
58
57
|
text: "Prefer no account or self-hosting? Switch /visual-plan to local files only:",
|
|
59
58
|
command: PLAN_LOCAL_FILES_COMMAND,
|
|
@@ -103,7 +102,6 @@ export const BUILT_IN_AUTH_MARKETING = {
|
|
|
103
102
|
"Multi-account Gmail in a single unified inbox",
|
|
104
103
|
"Autonomous triage, archiving, and follow-ups",
|
|
105
104
|
],
|
|
106
|
-
runLocalCommand: "npx @agent-native/core@latest create my-mail-app --template mail",
|
|
107
105
|
},
|
|
108
106
|
slides: {
|
|
109
107
|
appName: "Agent-Native Slides",
|
package/dist/server/auth.d.ts
CHANGED
package/dist/server/auth.js
CHANGED
|
@@ -3309,6 +3309,24 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
3309
3309
|
}));
|
|
3310
3310
|
// Passwordless login via Better Auth's rate-limited magic-link plugin.
|
|
3311
3311
|
app.use("/_agent-native/auth/magic-link", defineEventHandler(async (event) => {
|
|
3312
|
+
if (getMethod(event) === "GET") {
|
|
3313
|
+
const query = getQuery(event);
|
|
3314
|
+
if (typeof query.token === "string") {
|
|
3315
|
+
const verificationUrl = new URL(`${getAppBasePath()}/_agent-native/auth/ba/magic-link/verify`, getOrigin(event));
|
|
3316
|
+
for (const key of [
|
|
3317
|
+
"token",
|
|
3318
|
+
"callbackURL",
|
|
3319
|
+
"newUserCallbackURL",
|
|
3320
|
+
"errorCallbackURL",
|
|
3321
|
+
]) {
|
|
3322
|
+
const value = query[key];
|
|
3323
|
+
if (typeof value === "string") {
|
|
3324
|
+
verificationUrl.searchParams.set(key, value);
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
return redirectWithStagedCookies(event, verificationUrl.toString());
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3312
3330
|
if (getMethod(event) !== "POST") {
|
|
3313
3331
|
setResponseStatus(event, 405);
|
|
3314
3332
|
return { error: "Method not allowed" };
|