@agent-native/core 0.175.2-nightly-20260826150235 → 0.175.3
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/clips/app/components/player/comments-panel.tsx +1 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +5 -3
- package/corpus/templates/clips/desktop/src/app.tsx +171 -51
- package/corpus/templates/clips/desktop/src/lib/pill-completion.ts +111 -0
- package/corpus/templates/clips/desktop/src/lib/pill-session.ts +34 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +181 -79
- package/corpus/templates/clips/desktop/src/lib/rewind-recording-start.ts +28 -4
- package/corpus/templates/clips/desktop/src/main.tsx +4 -4
- package/corpus/templates/clips/desktop/src/overlays/record-pill.tsx +1320 -0
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +1 -1
- package/corpus/templates/clips/desktop/src/styles.css +20 -308
- package/corpus/templates/clips/desktop/src/tailwind.css +85 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +153 -70
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +15 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +25 -7
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +3 -3
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +375 -24
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +22 -30
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +5 -0
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory.rs +134 -14
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +233 -4
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +8 -5
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -1
- package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +3 -2
- package/corpus/templates/design/.generated/bridge/zoom.generated.ts +8 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +46 -10
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +89 -63
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -1
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +8 -2
- package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +11 -2
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -4
- package/corpus/templates/design/app/components/design/multi-screen/zoom-gesture.ts +19 -63
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +2 -1
- package/corpus/templates/design/shared/canvas-math.ts +11 -1
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +44 -18
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +88 -23
- package/corpus/templates/slides/app/context/DeckContext.tsx +155 -86
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +7 -5
- package/corpus/templates/slides/changelog/2026-08-26-thumbnail-arrow-keys-now-navigate-slides-after-selection.md +6 -0
- package/dist/client/hooks/index.d.ts +1 -0
- package/dist/client/hooks/index.js +1 -0
- package/dist/client/use-pinch-zoom.js +17 -4
- package/dist/client/zoom-gesture.d.ts +74 -0
- package/dist/client/zoom-gesture.js +100 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-browser.d.ts +13 -13
- package/dist/server/builder-browser.js +46 -15
- package/dist/server/builder-oauth.d.ts +12 -0
- package/dist/server/builder-oauth.js +13 -2
- package/dist/server/core-routes-plugin.js +54 -19
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/vite/client.js +2 -0
- package/docs/content/template-chat-developers.mdx +100 -13
- package/docs/content/template-chat-first-edits.mdx +5 -5
- package/docs/content/template-chat.mdx +84 -36
- package/package.json +4 -3
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +0 -458
|
@@ -10,5 +10,6 @@ export { createAgentNativeQueryClient } from "../create-query-client.js";
|
|
|
10
10
|
export { AppProviders } from "../app-providers.js";
|
|
11
11
|
export { APP_CHAT_SIDEBAR_STATE_EVENT, APP_CHAT_SIDEBAR_STATE_MESSAGE, APP_CHAT_SIDEBAR_STATE_REQUEST_MESSAGE, buildAppChatSidebarStateMessage, buildAppChatSidebarStateRequest, isPerAppChatStorageKey, requestPerAppChatCommand, usePerAppChatState, usePerAppChatOpen, } from "../app-chat-sidebar.js";
|
|
12
12
|
export { usePinchZoom } from "../use-pinch-zoom.js";
|
|
13
|
+
export { isPinchZoomDelta, normalizeWheelDeltaPx, resolveZoomGestureDevice, MAX_PINCH_DELTA_PX, ZOOM_GESTURE_IDLE_RESET_MS, } from "../zoom-gesture.js";
|
|
13
14
|
export { useAvatarUrl, uploadAvatar, invalidateAvatarCache, } from "../use-avatar.js";
|
|
14
15
|
export { usePollLoop, } from "../use-poll-loop.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
|
+
import { clampZoomFactor, normalizeWheelDeltaPx, resolveZoomGestureDevice, zoomFactorForWheelDelta, } from "./zoom-gesture.js";
|
|
2
3
|
/**
|
|
3
4
|
* Pinch-to-zoom for canvas-style editors. Wires the trackpad pinch / Cmd+scroll
|
|
4
5
|
* wheel gesture and 2-pointer touchscreen pinch onto a scrolling container.
|
|
@@ -46,6 +47,7 @@ export function usePinchZoom({ containerRef, zoom, setZoom, min = 25, max = 400,
|
|
|
46
47
|
let simScrollLeft = 0;
|
|
47
48
|
let simScrollTop = 0;
|
|
48
49
|
let rafId = null;
|
|
50
|
+
let gestureDevice = null;
|
|
49
51
|
const flush = () => {
|
|
50
52
|
rafId = null;
|
|
51
53
|
if (pendingZoom === null)
|
|
@@ -68,13 +70,23 @@ export function usePinchZoom({ containerRef, zoom, setZoom, min = 25, max = 400,
|
|
|
68
70
|
const handleWheel = (e) => {
|
|
69
71
|
if (!(e.ctrlKey || e.metaKey))
|
|
70
72
|
return;
|
|
71
|
-
|
|
73
|
+
// Chrome sends non-cancelable wheel events during a fling; cancelling one
|
|
74
|
+
// is a no-op that logs an Intervention per event and still scrolls.
|
|
75
|
+
if (e.cancelable)
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
gestureDevice = resolveZoomGestureDevice({
|
|
78
|
+
deltaY: e.deltaY,
|
|
79
|
+
deltaMode: e.deltaMode,
|
|
80
|
+
ctrlKey: e.ctrlKey,
|
|
81
|
+
metaKey: e.metaKey,
|
|
82
|
+
atMs: e.timeStamp,
|
|
83
|
+
previous: gestureDevice,
|
|
84
|
+
});
|
|
72
85
|
// Use the latest not-yet-applied zoom (if a flush is pending) so rapid
|
|
73
86
|
// wheel events within the same frame compound correctly instead of
|
|
74
87
|
// each computing off the last-committed React state.
|
|
75
88
|
const currentZoom = pendingZoom ?? zoomRef.current;
|
|
76
|
-
const
|
|
77
|
-
const factor = Math.exp(-clampedDelta * 0.01);
|
|
89
|
+
const factor = clampZoomFactor(zoomFactorForWheelDelta(normalizeWheelDeltaPx(e.deltaY, e.deltaMode), gestureDevice.pinch));
|
|
78
90
|
const nextZoom = clamp(currentZoom * factor);
|
|
79
91
|
if (nextZoom === currentZoom)
|
|
80
92
|
return;
|
|
@@ -137,7 +149,8 @@ export function usePinchZoom({ containerRef, zoom, setZoom, min = 25, max = 400,
|
|
|
137
149
|
pendingZoom = nextZoom;
|
|
138
150
|
scheduleFlush();
|
|
139
151
|
}
|
|
140
|
-
e.
|
|
152
|
+
if (e.cancelable)
|
|
153
|
+
e.preventDefault();
|
|
141
154
|
}
|
|
142
155
|
};
|
|
143
156
|
const handlePointerEnd = (e) => {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wheel/pinch → zoom-factor conversion, shared by every zoomable canvas.
|
|
3
|
+
*
|
|
4
|
+
* A mouse wheel and a trackpad pinch arrive as the same event type, their
|
|
5
|
+
* deltas overlap, and the sensitivity each needs differs by roughly 8x — so a
|
|
6
|
+
* surface that re-implements either half gets the split wrong the same way.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Largest |deltaY| finger separation produces; above it every device is a
|
|
10
|
+
* wheel. macOS reports an accelerated mouse wheel as large FRACTIONAL deltas,
|
|
11
|
+
* so fractionality alone cannot separate the two.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MAX_PINCH_DELTA_PX = 40;
|
|
14
|
+
/**
|
|
15
|
+
* A ctrl/meta wheel run with a longer gap than this starts a new gesture and
|
|
16
|
+
* the device is classified again.
|
|
17
|
+
*/
|
|
18
|
+
export declare const ZOOM_GESTURE_IDLE_RESET_MS = 150;
|
|
19
|
+
/** Which curve a zoom gesture's deltas run through, latched for its duration. */
|
|
20
|
+
export type ZoomGestureDevice = {
|
|
21
|
+
pinch: boolean;
|
|
22
|
+
lastEventAtMs: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Whether a delta is small enough to be finger separation. Magnitude only —
|
|
26
|
+
* `resolveZoomGestureDevice` owns the modifier and delta-mode part of the
|
|
27
|
+
* decision, and is what callers should ask.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isPinchZoomDelta(deltaY: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Latch the input device for a zoom gesture: one delta cannot identify a device
|
|
32
|
+
* (macOS ramps an accelerated wheel up from pinch-sized values), so this only
|
|
33
|
+
* ever loosens pinch → wheel, and re-decides after an idle gap.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveZoomGestureDevice(args: {
|
|
36
|
+
deltaY: number;
|
|
37
|
+
deltaMode: number;
|
|
38
|
+
ctrlKey: boolean;
|
|
39
|
+
metaKey: boolean;
|
|
40
|
+
atMs: number;
|
|
41
|
+
previous: ZoomGestureDevice | null;
|
|
42
|
+
}): ZoomGestureDevice;
|
|
43
|
+
/** One mouse-wheel detent in `deltaMode === 0` pixels (Chrome/Safari). */
|
|
44
|
+
export declare const MOUSE_WHEEL_NOTCH_PX = 100;
|
|
45
|
+
/** Zoom multiplier for one full mouse-wheel notch, matching Figma's feel. */
|
|
46
|
+
export declare const ZOOM_STEP_PER_NOTCH = 1.1;
|
|
47
|
+
/** Multiplier exponent per pixel of trackpad pinch delta. */
|
|
48
|
+
export declare const PINCH_ZOOM_SENSITIVITY = 0.0075;
|
|
49
|
+
/** Ceiling on a single frame's zoom change, in either direction. */
|
|
50
|
+
export declare const MAX_ZOOM_FACTOR_PER_FRAME = 1.6;
|
|
51
|
+
/** Pixels one `DOM_DELTA_LINE` step stands for. */
|
|
52
|
+
export declare const WHEEL_LINE_HEIGHT_PX = 16;
|
|
53
|
+
/** Pixels one `DOM_DELTA_PAGE` step stands for. */
|
|
54
|
+
export declare const WHEEL_PAGE_HEIGHT_PX = 800;
|
|
55
|
+
/**
|
|
56
|
+
* Convert a delta to pixels. The curves below are calibrated in pixels, so a
|
|
57
|
+
* Firefox line-mode tick of 3 is a full notch, not 3px of travel. Classify
|
|
58
|
+
* with the RAW delta and its real mode — normalising first would push a line
|
|
59
|
+
* tick into the pinch band.
|
|
60
|
+
*/
|
|
61
|
+
export declare function normalizeWheelDeltaPx(delta: number, deltaMode: number): number;
|
|
62
|
+
/** Unclamped zoom multiplier for a wheel/pinch delta. Negative delta (scroll
|
|
63
|
+
* up / pinch open) zooms in, matching the browser's wheel convention. */
|
|
64
|
+
export declare function zoomFactorForWheelDelta(deltaY: number, pinch: boolean): number;
|
|
65
|
+
/** Bounds one frame's zoom change symmetrically in multiplicative space, so
|
|
66
|
+
* zooming in and back out by the same clamped amount is a round trip. */
|
|
67
|
+
export declare function clampZoomFactor(factor: number): number;
|
|
68
|
+
/**
|
|
69
|
+
* Fold one event into a frame's accumulated zoom. Both curves are exponential
|
|
70
|
+
* in the delta, so multiplying per-event factors equals summing same-curve
|
|
71
|
+
* deltas — and unlike a delta sum it stays exact when a frame catches two
|
|
72
|
+
* curves, instead of forcing the accumulator to discard one of them.
|
|
73
|
+
*/
|
|
74
|
+
export declare function accumulateZoomFactor(pendingFactor: number, deltaY: number, pinch: boolean): number;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wheel/pinch → zoom-factor conversion, shared by every zoomable canvas.
|
|
3
|
+
*
|
|
4
|
+
* A mouse wheel and a trackpad pinch arrive as the same event type, their
|
|
5
|
+
* deltas overlap, and the sensitivity each needs differs by roughly 8x — so a
|
|
6
|
+
* surface that re-implements either half gets the split wrong the same way.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Largest |deltaY| finger separation produces; above it every device is a
|
|
10
|
+
* wheel. macOS reports an accelerated mouse wheel as large FRACTIONAL deltas,
|
|
11
|
+
* so fractionality alone cannot separate the two.
|
|
12
|
+
*/
|
|
13
|
+
export const MAX_PINCH_DELTA_PX = 40;
|
|
14
|
+
/**
|
|
15
|
+
* A ctrl/meta wheel run with a longer gap than this starts a new gesture and
|
|
16
|
+
* the device is classified again.
|
|
17
|
+
*/
|
|
18
|
+
export const ZOOM_GESTURE_IDLE_RESET_MS = 150;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a delta is small enough to be finger separation. Magnitude only —
|
|
21
|
+
* `resolveZoomGestureDevice` owns the modifier and delta-mode part of the
|
|
22
|
+
* decision, and is what callers should ask.
|
|
23
|
+
*/
|
|
24
|
+
export function isPinchZoomDelta(deltaY) {
|
|
25
|
+
if (!Number.isFinite(deltaY))
|
|
26
|
+
return false;
|
|
27
|
+
return Math.abs(deltaY) < MAX_PINCH_DELTA_PX;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Latch the input device for a zoom gesture: one delta cannot identify a device
|
|
31
|
+
* (macOS ramps an accelerated wheel up from pinch-sized values), so this only
|
|
32
|
+
* ever loosens pinch → wheel, and re-decides after an idle gap.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveZoomGestureDevice(args) {
|
|
35
|
+
const { deltaY, deltaMode, ctrlKey, metaKey, atMs, previous } = args;
|
|
36
|
+
const at = Number.isFinite(atMs) ? atMs : 0;
|
|
37
|
+
// Line/page modes are always discrete wheels. A held Cmd means the user
|
|
38
|
+
// reached for a modifier, so the wheel is whatever device they are holding —
|
|
39
|
+
// only the browser's synthetic ctrl+wheel can be a trackpad pinch.
|
|
40
|
+
const looksLikePinch = deltaMode === 0 && ctrlKey && !metaKey && isPinchZoomDelta(deltaY);
|
|
41
|
+
const continuesGesture = previous !== null &&
|
|
42
|
+
Number.isFinite(previous.lastEventAtMs) &&
|
|
43
|
+
at - previous.lastEventAtMs <= ZOOM_GESTURE_IDLE_RESET_MS;
|
|
44
|
+
if (!continuesGesture)
|
|
45
|
+
return { pinch: looksLikePinch, lastEventAtMs: at };
|
|
46
|
+
return { pinch: previous.pinch && looksLikePinch, lastEventAtMs: at };
|
|
47
|
+
}
|
|
48
|
+
/** One mouse-wheel detent in `deltaMode === 0` pixels (Chrome/Safari). */
|
|
49
|
+
export const MOUSE_WHEEL_NOTCH_PX = 100;
|
|
50
|
+
/** Zoom multiplier for one full mouse-wheel notch, matching Figma's feel. */
|
|
51
|
+
export const ZOOM_STEP_PER_NOTCH = 1.1;
|
|
52
|
+
/** Multiplier exponent per pixel of trackpad pinch delta. */
|
|
53
|
+
export const PINCH_ZOOM_SENSITIVITY = 0.0075;
|
|
54
|
+
/** Ceiling on a single frame's zoom change, in either direction. */
|
|
55
|
+
export const MAX_ZOOM_FACTOR_PER_FRAME = 1.6;
|
|
56
|
+
/** Pixels one `DOM_DELTA_LINE` step stands for. */
|
|
57
|
+
export const WHEEL_LINE_HEIGHT_PX = 16;
|
|
58
|
+
/** Pixels one `DOM_DELTA_PAGE` step stands for. */
|
|
59
|
+
export const WHEEL_PAGE_HEIGHT_PX = 800;
|
|
60
|
+
/**
|
|
61
|
+
* Convert a delta to pixels. The curves below are calibrated in pixels, so a
|
|
62
|
+
* Firefox line-mode tick of 3 is a full notch, not 3px of travel. Classify
|
|
63
|
+
* with the RAW delta and its real mode — normalising first would push a line
|
|
64
|
+
* tick into the pinch band.
|
|
65
|
+
*/
|
|
66
|
+
export function normalizeWheelDeltaPx(delta, deltaMode) {
|
|
67
|
+
if (!Number.isFinite(delta))
|
|
68
|
+
return 0;
|
|
69
|
+
if (deltaMode === 1)
|
|
70
|
+
return delta * WHEEL_LINE_HEIGHT_PX;
|
|
71
|
+
if (deltaMode === 2)
|
|
72
|
+
return delta * WHEEL_PAGE_HEIGHT_PX;
|
|
73
|
+
return delta;
|
|
74
|
+
}
|
|
75
|
+
/** Unclamped zoom multiplier for a wheel/pinch delta. Negative delta (scroll
|
|
76
|
+
* up / pinch open) zooms in, matching the browser's wheel convention. */
|
|
77
|
+
export function zoomFactorForWheelDelta(deltaY, pinch) {
|
|
78
|
+
if (!Number.isFinite(deltaY) || deltaY === 0)
|
|
79
|
+
return 1;
|
|
80
|
+
return pinch
|
|
81
|
+
? Math.exp(-deltaY * PINCH_ZOOM_SENSITIVITY)
|
|
82
|
+
: Math.pow(ZOOM_STEP_PER_NOTCH, -deltaY / MOUSE_WHEEL_NOTCH_PX);
|
|
83
|
+
}
|
|
84
|
+
/** Bounds one frame's zoom change symmetrically in multiplicative space, so
|
|
85
|
+
* zooming in and back out by the same clamped amount is a round trip. */
|
|
86
|
+
export function clampZoomFactor(factor) {
|
|
87
|
+
if (!Number.isFinite(factor) || factor <= 0)
|
|
88
|
+
return 1;
|
|
89
|
+
return Math.min(MAX_ZOOM_FACTOR_PER_FRAME, Math.max(1 / MAX_ZOOM_FACTOR_PER_FRAME, factor));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Fold one event into a frame's accumulated zoom. Both curves are exponential
|
|
93
|
+
* in the delta, so multiplying per-event factors equals summing same-curve
|
|
94
|
+
* deltas — and unlike a delta sum it stays exact when a frame catches two
|
|
95
|
+
* curves, instead of forcing the accumulator to discard one of them.
|
|
96
|
+
*/
|
|
97
|
+
export function accumulateZoomFactor(pendingFactor, deltaY, pinch) {
|
|
98
|
+
const base = Number.isFinite(pendingFactor) && pendingFactor > 0 ? pendingFactor : 1;
|
|
99
|
+
return base * zoomFactorForWheelDelta(deltaY, pinch);
|
|
100
|
+
}
|
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
|
-
error: string;
|
|
30
29
|
ok?: undefined;
|
|
30
|
+
error: string;
|
|
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;
|
|
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
+
error?: undefined;
|
|
44
45
|
summary: import("./types.js").TraceSummary;
|
|
45
46
|
spans: import("./types.js").TraceSpan[];
|
|
46
47
|
id?: undefined;
|
|
47
|
-
error?: undefined;
|
|
48
48
|
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
+
error?: undefined;
|
|
50
51
|
summary?: undefined;
|
|
51
52
|
spans?: undefined;
|
|
52
53
|
id: string;
|
|
53
|
-
error?: undefined;
|
|
54
54
|
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
56
|
summary?: undefined;
|
|
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
59
59
|
error: any;
|
|
60
60
|
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
+
error?: undefined;
|
|
62
63
|
summary?: undefined;
|
|
63
64
|
spans?: undefined;
|
|
64
65
|
id?: undefined;
|
|
65
66
|
ok: boolean;
|
|
66
|
-
error?: undefined;
|
|
67
67
|
}>>;
|
|
@@ -76,8 +76,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
78
|
id?: undefined;
|
|
79
|
+
provider?: undefined;
|
|
79
80
|
deleted?: undefined;
|
|
80
|
-
|
|
81
|
+
message?: undefined;
|
|
81
82
|
providers: {
|
|
82
83
|
id: string;
|
|
83
84
|
label: string;
|
|
@@ -88,46 +89,45 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
88
89
|
updatedAt: number;
|
|
89
90
|
}[];
|
|
90
91
|
count: number;
|
|
91
|
-
|
|
92
|
+
found?: undefined;
|
|
92
93
|
registered?: undefined;
|
|
93
94
|
label?: undefined;
|
|
94
|
-
message?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
id?: undefined;
|
|
97
96
|
count?: undefined;
|
|
97
|
+
id?: undefined;
|
|
98
98
|
deleted?: undefined;
|
|
99
|
+
message?: undefined;
|
|
99
100
|
providers?: undefined;
|
|
100
101
|
found: boolean;
|
|
101
102
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
102
103
|
registered?: undefined;
|
|
103
104
|
label?: undefined;
|
|
104
|
-
message?: undefined;
|
|
105
105
|
} | {
|
|
106
106
|
count?: undefined;
|
|
107
|
+
provider?: undefined;
|
|
107
108
|
deleted?: undefined;
|
|
109
|
+
message?: undefined;
|
|
108
110
|
providers?: undefined;
|
|
109
|
-
provider?: undefined;
|
|
110
111
|
found: boolean;
|
|
111
112
|
id: string;
|
|
112
113
|
registered?: undefined;
|
|
113
114
|
label?: undefined;
|
|
114
|
-
message?: undefined;
|
|
115
115
|
} | {
|
|
116
116
|
count?: undefined;
|
|
117
|
-
found?: undefined;
|
|
118
|
-
providers?: undefined;
|
|
119
117
|
provider?: undefined;
|
|
118
|
+
message?: undefined;
|
|
119
|
+
providers?: undefined;
|
|
120
|
+
found?: undefined;
|
|
120
121
|
deleted: boolean;
|
|
121
122
|
id: string;
|
|
122
123
|
registered?: undefined;
|
|
123
124
|
label?: undefined;
|
|
124
|
-
message?: undefined;
|
|
125
125
|
} | {
|
|
126
126
|
count?: undefined;
|
|
127
|
+
provider?: undefined;
|
|
127
128
|
deleted?: undefined;
|
|
128
|
-
found?: undefined;
|
|
129
129
|
providers?: undefined;
|
|
130
|
-
|
|
130
|
+
found?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
@@ -311,11 +311,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
311
311
|
notes?: string | undefined;
|
|
312
312
|
scope?: "org" | "user" | undefined;
|
|
313
313
|
}, {
|
|
314
|
-
message?: undefined;
|
|
315
|
-
id?: undefined;
|
|
316
|
-
provider?: undefined;
|
|
317
314
|
deleted?: undefined;
|
|
318
|
-
|
|
315
|
+
id?: undefined;
|
|
319
316
|
providers: {
|
|
320
317
|
id: string;
|
|
321
318
|
label: string;
|
|
@@ -326,44 +323,47 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
326
323
|
updatedAt: number;
|
|
327
324
|
}[];
|
|
328
325
|
count: number;
|
|
326
|
+
provider?: undefined;
|
|
327
|
+
found?: undefined;
|
|
329
328
|
registered?: undefined;
|
|
330
329
|
label?: undefined;
|
|
331
|
-
} | {
|
|
332
330
|
message?: undefined;
|
|
333
|
-
|
|
331
|
+
} | {
|
|
334
332
|
deleted?: undefined;
|
|
333
|
+
id?: undefined;
|
|
335
334
|
providers?: undefined;
|
|
336
335
|
count?: undefined;
|
|
337
336
|
found: boolean;
|
|
338
337
|
provider: import("../custom-registry.js").CustomProviderConfig;
|
|
339
338
|
registered?: undefined;
|
|
340
339
|
label?: undefined;
|
|
341
|
-
} | {
|
|
342
340
|
message?: undefined;
|
|
343
|
-
|
|
341
|
+
} | {
|
|
344
342
|
deleted?: undefined;
|
|
345
343
|
providers?: undefined;
|
|
346
344
|
count?: undefined;
|
|
345
|
+
provider?: undefined;
|
|
347
346
|
found: boolean;
|
|
348
347
|
id: string;
|
|
349
348
|
registered?: undefined;
|
|
350
349
|
label?: undefined;
|
|
351
|
-
} | {
|
|
352
350
|
message?: undefined;
|
|
353
|
-
|
|
354
|
-
found?: undefined;
|
|
351
|
+
} | {
|
|
355
352
|
providers?: undefined;
|
|
356
353
|
count?: undefined;
|
|
354
|
+
provider?: undefined;
|
|
355
|
+
found?: undefined;
|
|
357
356
|
deleted: boolean;
|
|
358
357
|
id: string;
|
|
359
358
|
registered?: undefined;
|
|
360
359
|
label?: undefined;
|
|
360
|
+
message?: undefined;
|
|
361
361
|
} | {
|
|
362
|
-
provider?: undefined;
|
|
363
362
|
deleted?: undefined;
|
|
364
|
-
found?: undefined;
|
|
365
363
|
providers?: undefined;
|
|
366
364
|
count?: undefined;
|
|
365
|
+
provider?: undefined;
|
|
366
|
+
found?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
369
369
|
label: string;
|
|
@@ -34,10 +34,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
34
34
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
35
35
|
error: any;
|
|
36
36
|
} | {
|
|
37
|
+
error?: undefined;
|
|
37
38
|
ok: boolean;
|
|
38
39
|
key: string;
|
|
39
40
|
baseUrlKey?: string;
|
|
40
41
|
scope: AgentEngineApiKeyScope;
|
|
41
|
-
error?: undefined;
|
|
42
42
|
}>>;
|
|
43
43
|
export {};
|
|
@@ -54,9 +54,10 @@ export declare function isBuilderConnectCallbackUrlAllowed(candidate: string, ev
|
|
|
54
54
|
* `getAppBasePath()` + `BUILDER_CALLBACK_PATH`. Intentionally ignores any
|
|
55
55
|
* `?redirect_uri=` query override — connect always returns to this app's own
|
|
56
56
|
* callback. Validated with `isBuilderConnectCallbackUrlAllowed` (Railway-safe,
|
|
57
|
-
* no fixed domain allowlist).
|
|
57
|
+
* no fixed domain allowlist). When state is provided, bind it into the exact
|
|
58
|
+
* registered callback URI because Builder can omit top-level OAuth state.
|
|
58
59
|
*/
|
|
59
|
-
export declare function resolveBuilderConnectCallbackUrl(event: H3Event): string | null;
|
|
60
|
+
export declare function resolveBuilderConnectCallbackUrl(event: H3Event, state?: string): string | null;
|
|
60
61
|
export declare function isSafeBuilderRelayTargetOrigin(value: string): boolean;
|
|
61
62
|
export declare function isTrustedBuilderRelayTargetOrigin(value: string): boolean;
|
|
62
63
|
/**
|
|
@@ -109,21 +110,22 @@ export declare function verifyBuilderRelayRequest(input: {
|
|
|
109
110
|
body: BuilderRelayRequestBody;
|
|
110
111
|
} | null;
|
|
111
112
|
/**
|
|
112
|
-
* Query-param name carrying the signed CSRF state on the
|
|
113
|
-
* round-trip. Prefixed with `_an_` to avoid collisions if
|
|
114
|
-
* adds standard OAuth `state` support to cli-auth.
|
|
115
|
-
* the path/query of `redirect_url` verbatim when redirecting back, so
|
|
116
|
-
* we embed `_an_state=…` inside the redirect_url query string at
|
|
117
|
-
* connect time and read it back on the callback.
|
|
113
|
+
* Query-param name carrying the signed CSRF state on the legacy
|
|
114
|
+
* connect→callback round-trip. Prefixed with `_an_` to avoid collisions if
|
|
115
|
+
* Builder ever adds standard OAuth `state` support to cli-auth.
|
|
118
116
|
*/
|
|
119
117
|
export declare const BUILDER_STATE_PARAM = "_an_state";
|
|
120
118
|
export declare const BUILDER_CONNECT_PARAM = "_an_connect";
|
|
119
|
+
export declare const BUILDER_CONNECT_STATE_COOKIE = "an_builder_connect_state";
|
|
121
120
|
export declare const BUILDER_CONNECT_OWNER_COOKIE = "an_builder_connect_owner";
|
|
122
121
|
export declare const BUILDER_SIGNUP_SOURCE_PARAM = "signupSource";
|
|
123
122
|
export declare const BUILDER_AGENT_NATIVE_FLOW_PARAM = "agentNativeFlow";
|
|
124
123
|
export declare const BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM = "agentNativeConnectSource";
|
|
125
124
|
export declare const BUILDER_AGENT_NATIVE_APP_PARAM = "agentNativeApp";
|
|
126
125
|
export declare const BUILDER_AGENT_NATIVE_TEMPLATE_PARAM = "agentNativeTemplate";
|
|
126
|
+
export declare function appendBuilderConnectStateCookie(value: string | null | undefined, state: string): string;
|
|
127
|
+
export declare function removeBuilderConnectStateCookie(value: string | null | undefined, state: string): string;
|
|
128
|
+
export declare function resolveBuilderConnectCallbackState(queryState: string | null, cookieState: string | null | undefined): string | null;
|
|
127
129
|
export interface BuilderConnectTrackingParams {
|
|
128
130
|
signupSource?: string;
|
|
129
131
|
agentNativeFlow?: string;
|
|
@@ -240,11 +242,9 @@ export declare function resolveIsBuilderBranchingEnabled(): Promise<boolean>;
|
|
|
240
242
|
export declare const BUILDER_OPENER_PARAM = "_an_opener";
|
|
241
243
|
/**
|
|
242
244
|
* Build the Builder cli-auth URL for the connect popup. When a signed
|
|
243
|
-
* `state` token is supplied it is embedded inside the `redirect_url`
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* api-key / etc., so we don't depend on Builder echoing a top-level
|
|
247
|
-
* `state` parameter (it doesn't).
|
|
245
|
+
* `state` token is supplied it is embedded inside the `redirect_url` query
|
|
246
|
+
* string. The connect route also stores it in an HttpOnly cookie because
|
|
247
|
+
* Builder may strip the callback query while appending its response params.
|
|
248
248
|
*
|
|
249
249
|
* Status responses can surface this URL directly; the legacy
|
|
250
250
|
* `/_agent-native/builder/connect` trampoline still calls this helper for
|
|
@@ -109,15 +109,17 @@ export function isBuilderConnectCallbackUrlAllowed(candidate, event) {
|
|
|
109
109
|
* `getAppBasePath()` + `BUILDER_CALLBACK_PATH`. Intentionally ignores any
|
|
110
110
|
* `?redirect_uri=` query override — connect always returns to this app's own
|
|
111
111
|
* callback. Validated with `isBuilderConnectCallbackUrlAllowed` (Railway-safe,
|
|
112
|
-
* no fixed domain allowlist).
|
|
112
|
+
* no fixed domain allowlist). When state is provided, bind it into the exact
|
|
113
|
+
* registered callback URI because Builder can omit top-level OAuth state.
|
|
113
114
|
*/
|
|
114
|
-
export function resolveBuilderConnectCallbackUrl(event) {
|
|
115
|
-
const
|
|
115
|
+
export function resolveBuilderConnectCallbackUrl(event, state) {
|
|
116
|
+
const stateSuffix = state ? `?state=${encodeURIComponent(state)}` : "";
|
|
117
|
+
const withBase = `${getOrigin(event)}${getAppBasePath()}${BUILDER_CALLBACK_PATH}${stateSuffix}`;
|
|
116
118
|
if (isBuilderConnectCallbackUrlAllowed(withBase, event))
|
|
117
119
|
return withBase;
|
|
118
120
|
// Match google-oauth default-redirect behavior when the request is not under
|
|
119
121
|
// APP_BASE_PATH: fall back to the root `/_agent-native/...` callback.
|
|
120
|
-
const root = `${getOrigin(event)}${BUILDER_CALLBACK_PATH}`;
|
|
122
|
+
const root = `${getOrigin(event)}${BUILDER_CALLBACK_PATH}${stateSuffix}`;
|
|
121
123
|
if (root !== withBase && isBuilderConnectCallbackUrlAllowed(root, event)) {
|
|
122
124
|
return root;
|
|
123
125
|
}
|
|
@@ -404,21 +406,52 @@ function escapeHtml(value) {
|
|
|
404
406
|
});
|
|
405
407
|
}
|
|
406
408
|
/**
|
|
407
|
-
* Query-param name carrying the signed CSRF state on the
|
|
408
|
-
* round-trip. Prefixed with `_an_` to avoid collisions if
|
|
409
|
-
* adds standard OAuth `state` support to cli-auth.
|
|
410
|
-
* the path/query of `redirect_url` verbatim when redirecting back, so
|
|
411
|
-
* we embed `_an_state=…` inside the redirect_url query string at
|
|
412
|
-
* connect time and read it back on the callback.
|
|
409
|
+
* Query-param name carrying the signed CSRF state on the legacy
|
|
410
|
+
* connect→callback round-trip. Prefixed with `_an_` to avoid collisions if
|
|
411
|
+
* Builder ever adds standard OAuth `state` support to cli-auth.
|
|
413
412
|
*/
|
|
414
413
|
export const BUILDER_STATE_PARAM = "_an_state";
|
|
415
414
|
export const BUILDER_CONNECT_PARAM = "_an_connect";
|
|
415
|
+
export const BUILDER_CONNECT_STATE_COOKIE = "an_builder_connect_state";
|
|
416
416
|
export const BUILDER_CONNECT_OWNER_COOKIE = "an_builder_connect_owner";
|
|
417
417
|
export const BUILDER_SIGNUP_SOURCE_PARAM = "signupSource";
|
|
418
418
|
export const BUILDER_AGENT_NATIVE_FLOW_PARAM = "agentNativeFlow";
|
|
419
419
|
export const BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM = "agentNativeConnectSource";
|
|
420
420
|
export const BUILDER_AGENT_NATIVE_APP_PARAM = "agentNativeApp";
|
|
421
421
|
export const BUILDER_AGENT_NATIVE_TEMPLATE_PARAM = "agentNativeTemplate";
|
|
422
|
+
const BUILDER_CONNECT_STATE_COOKIE_MAX_ENTRIES = 4;
|
|
423
|
+
function parseBuilderConnectStateCookie(value) {
|
|
424
|
+
if (!value)
|
|
425
|
+
return [];
|
|
426
|
+
const states = value.split(",");
|
|
427
|
+
if (states.length > BUILDER_CONNECT_STATE_COOKIE_MAX_ENTRIES ||
|
|
428
|
+
states.some((state) => !isSignedBuilderConnectState(state))) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
return [...new Set(states)];
|
|
432
|
+
}
|
|
433
|
+
export function appendBuilderConnectStateCookie(value, state) {
|
|
434
|
+
const states = parseBuilderConnectStateCookie(value) ?? [];
|
|
435
|
+
return [...states.filter((candidate) => candidate !== state), state]
|
|
436
|
+
.slice(-BUILDER_CONNECT_STATE_COOKIE_MAX_ENTRIES)
|
|
437
|
+
.join(",");
|
|
438
|
+
}
|
|
439
|
+
export function removeBuilderConnectStateCookie(value, state) {
|
|
440
|
+
return (parseBuilderConnectStateCookie(value) ?? [])
|
|
441
|
+
.filter((candidate) => candidate !== state)
|
|
442
|
+
.join(",");
|
|
443
|
+
}
|
|
444
|
+
export function resolveBuilderConnectCallbackState(queryState, cookieState) {
|
|
445
|
+
const cookieStates = parseBuilderConnectStateCookie(cookieState);
|
|
446
|
+
if (cookieState && !cookieStates)
|
|
447
|
+
return null;
|
|
448
|
+
if (queryState !== null) {
|
|
449
|
+
if (cookieStates?.length && !cookieStates.includes(queryState))
|
|
450
|
+
return null;
|
|
451
|
+
return queryState;
|
|
452
|
+
}
|
|
453
|
+
return cookieStates?.length === 1 ? cookieStates[0] : null;
|
|
454
|
+
}
|
|
422
455
|
const BUILDER_STATE_TTL_MS = 10 * 60 * 1000;
|
|
423
456
|
const BUILDER_SIGNUP_SOURCE = "agent-native";
|
|
424
457
|
function cleanTrackingParam(value) {
|
|
@@ -764,11 +797,9 @@ function isBuilderOpenerOriginSafe(value) {
|
|
|
764
797
|
}
|
|
765
798
|
/**
|
|
766
799
|
* Build the Builder cli-auth URL for the connect popup. When a signed
|
|
767
|
-
* `state` token is supplied it is embedded inside the `redirect_url`
|
|
768
|
-
*
|
|
769
|
-
*
|
|
770
|
-
* api-key / etc., so we don't depend on Builder echoing a top-level
|
|
771
|
-
* `state` parameter (it doesn't).
|
|
800
|
+
* `state` token is supplied it is embedded inside the `redirect_url` query
|
|
801
|
+
* string. The connect route also stores it in an HttpOnly cookie because
|
|
802
|
+
* Builder may strip the callback query while appending its response params.
|
|
772
803
|
*
|
|
773
804
|
* Status responses can surface this URL directly; the legacy
|
|
774
805
|
* `/_agent-native/builder/connect` trampoline still calls this helper for
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type McpOAuthCredentialBundle } from "../mcp-client/oauth-client.js";
|
|
1
2
|
export declare const BUILDER_OAUTH_ISSUER = "https://mcp.builder.io";
|
|
2
3
|
export declare const BUILDER_OAUTH_RESOURCE = "https://api.builder.io";
|
|
3
4
|
export declare const BUILDER_OAUTH_SCOPE = "builder:ai:invoke";
|
|
@@ -26,6 +27,17 @@ export declare function startBuilderOAuthAuthorization(input: {
|
|
|
26
27
|
authorizationUrl: string;
|
|
27
28
|
pending: BuilderOAuthPendingFlow;
|
|
28
29
|
}>;
|
|
30
|
+
export declare function exchangeBuilderOAuthAuthorization(input: {
|
|
31
|
+
ownerEmail: string;
|
|
32
|
+
code: string;
|
|
33
|
+
iss?: string;
|
|
34
|
+
pending: BuilderOAuthPendingFlow;
|
|
35
|
+
}): Promise<McpOAuthCredentialBundle>;
|
|
36
|
+
export declare function saveBuilderOAuthCredentials(input: {
|
|
37
|
+
ownerEmail: string;
|
|
38
|
+
orgId?: string;
|
|
39
|
+
credentials: McpOAuthCredentialBundle;
|
|
40
|
+
}): Promise<void>;
|
|
29
41
|
export declare function finishBuilderOAuthAuthorization(input: {
|
|
30
42
|
ownerEmail: string;
|
|
31
43
|
orgId?: string;
|
|
@@ -133,7 +133,7 @@ export async function startBuilderOAuthAuthorization(input) {
|
|
|
133
133
|
},
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
|
-
export async function
|
|
136
|
+
export async function exchangeBuilderOAuthAuthorization(input) {
|
|
137
137
|
validateMcpOAuthCallbackIssuer(input.pending.discoveryState, input.iss);
|
|
138
138
|
const result = await finishMcpOAuthAuthorization({
|
|
139
139
|
serverUrl: BUILDER_OAUTH_RESOURCE,
|
|
@@ -148,11 +148,22 @@ export async function finishBuilderOAuthAuthorization(input) {
|
|
|
148
148
|
if (!isBuilderCredential(result.credentials)) {
|
|
149
149
|
throw new Error("Builder OAuth exchange returned credentials for another resource");
|
|
150
150
|
}
|
|
151
|
+
return withRecordedScopes(result.credentials);
|
|
152
|
+
}
|
|
153
|
+
export async function saveBuilderOAuthCredentials(input) {
|
|
151
154
|
await saveMcpOAuthCredentials({
|
|
152
155
|
...(input.orgId
|
|
153
156
|
? orgOwnerOptions(input.orgId)
|
|
154
157
|
: await ownerOptions(input.ownerEmail)),
|
|
155
|
-
credentials:
|
|
158
|
+
credentials: input.credentials,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
export async function finishBuilderOAuthAuthorization(input) {
|
|
162
|
+
const credentials = await exchangeBuilderOAuthAuthorization(input);
|
|
163
|
+
await saveBuilderOAuthCredentials({
|
|
164
|
+
ownerEmail: input.ownerEmail,
|
|
165
|
+
orgId: input.orgId,
|
|
166
|
+
credentials,
|
|
156
167
|
});
|
|
157
168
|
}
|
|
158
169
|
export async function markBuilderOAuthReconnectRequired(ownerEmail) {
|