@agent-native/core 0.175.1 → 0.175.2-nightly-20260826165737

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.
Files changed (46) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/clips/app/components/player/video-player.tsx +5 -3
  3. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -1
  4. package/corpus/templates/design/.generated/bridge/embedded-wheel.generated.ts +3 -2
  5. package/corpus/templates/design/.generated/bridge/zoom.generated.ts +8 -2
  6. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +46 -10
  7. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +89 -63
  8. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -1
  9. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +8 -2
  10. package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +11 -2
  11. package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -4
  12. package/corpus/templates/design/app/components/design/multi-screen/zoom-gesture.ts +19 -63
  13. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +2 -1
  14. package/corpus/templates/design/shared/canvas-math.ts +11 -1
  15. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +44 -18
  16. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +44 -1
  17. package/corpus/templates/slides/app/context/DeckContext.tsx +77 -63
  18. package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -1
  19. package/corpus/templates/slides/changelog/2026-08-26-thumbnail-arrow-keys-now-navigate-slides-after-selection.md +6 -0
  20. package/dist/client/embed-auth.js +4 -2
  21. package/dist/client/hooks/index.d.ts +1 -0
  22. package/dist/client/hooks/index.js +1 -0
  23. package/dist/client/use-pinch-zoom.js +17 -4
  24. package/dist/client/zoom-gesture.d.ts +74 -0
  25. package/dist/client/zoom-gesture.js +100 -0
  26. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  27. package/dist/notifications/routes.d.ts +3 -3
  28. package/dist/observability/routes.d.ts +5 -5
  29. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  30. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  31. package/dist/secrets/routes.d.ts +9 -9
  32. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  33. package/dist/server/builder-browser.d.ts +13 -13
  34. package/dist/server/builder-browser.js +46 -15
  35. package/dist/server/builder-oauth.d.ts +12 -0
  36. package/dist/server/builder-oauth.js +13 -2
  37. package/dist/server/core-routes-plugin.js +54 -19
  38. package/dist/server/embed-session.js +1 -1
  39. package/dist/server/security-headers.d.ts +3 -0
  40. package/dist/server/security-headers.js +10 -1
  41. package/dist/server/transcribe-voice.d.ts +1 -1
  42. package/dist/vite/client.js +2 -0
  43. package/docs/content/template-chat-developers.mdx +100 -13
  44. package/docs/content/template-chat-first-edits.mdx +5 -5
  45. package/docs/content/template-chat.mdx +84 -36
  46. package/package.json +3 -2
@@ -137,13 +137,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
137
137
  inputSchema: {
138
138
  type: string;
139
139
  properties: {
140
+ count?: undefined;
140
141
  query?: undefined;
141
142
  minutes?: undefined;
142
143
  limit?: undefined;
143
144
  clientHint?: undefined;
144
145
  timestamp?: undefined;
145
146
  chapterId?: undefined;
146
- count?: undefined;
147
147
  startAt?: undefined;
148
148
  endAt?: undefined;
149
149
  reason?: undefined;
@@ -159,6 +159,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
159
159
  inputSchema: {
160
160
  type: string;
161
161
  properties: {
162
+ count?: undefined;
162
163
  query: {
163
164
  type: string;
164
165
  description: string;
@@ -174,7 +175,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
174
175
  clientHint?: undefined;
175
176
  timestamp?: undefined;
176
177
  chapterId?: undefined;
177
- count?: undefined;
178
178
  startAt?: undefined;
179
179
  endAt?: undefined;
180
180
  reason?: undefined;
@@ -190,6 +190,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
190
190
  inputSchema: {
191
191
  type: string;
192
192
  properties: {
193
+ count?: undefined;
193
194
  minutes: {
194
195
  type: string;
195
196
  description: string;
@@ -199,7 +200,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
199
200
  clientHint?: undefined;
200
201
  timestamp?: undefined;
201
202
  chapterId?: undefined;
202
- count?: undefined;
203
203
  startAt?: undefined;
204
204
  endAt?: undefined;
205
205
  reason?: undefined;
@@ -216,6 +216,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
216
216
  type: string;
217
217
  required: string[];
218
218
  properties: {
219
+ count?: undefined;
219
220
  query: {
220
221
  type: string;
221
222
  description: string;
@@ -234,7 +235,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
234
235
  };
235
236
  timestamp?: undefined;
236
237
  chapterId?: undefined;
237
- count?: undefined;
238
238
  startAt?: undefined;
239
239
  endAt?: undefined;
240
240
  reason?: undefined;
@@ -250,6 +250,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
250
250
  type: string;
251
251
  required: string[];
252
252
  properties: {
253
+ count?: undefined;
253
254
  query?: undefined;
254
255
  minutes?: undefined;
255
256
  limit?: undefined;
@@ -263,7 +264,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
263
264
  description: string;
264
265
  };
265
266
  chapterId?: undefined;
266
- count?: undefined;
267
267
  startAt?: undefined;
268
268
  endAt?: undefined;
269
269
  includeMicrophone?: undefined;
@@ -314,13 +314,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
314
314
  type: string;
315
315
  required: string[];
316
316
  properties: {
317
+ count?: undefined;
317
318
  query?: undefined;
318
319
  minutes?: undefined;
319
320
  limit?: undefined;
320
321
  clientHint?: undefined;
321
322
  timestamp?: undefined;
322
323
  chapterId?: undefined;
323
- count?: undefined;
324
324
  startAt: {
325
325
  type: string;
326
326
  description: string;
@@ -349,13 +349,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
349
349
  type: string;
350
350
  required: string[];
351
351
  properties: {
352
+ count?: undefined;
352
353
  query?: undefined;
353
354
  minutes?: undefined;
354
355
  limit?: undefined;
355
356
  clientHint?: undefined;
356
357
  timestamp?: undefined;
357
358
  chapterId?: undefined;
358
- count?: undefined;
359
359
  startAt?: undefined;
360
360
  endAt?: undefined;
361
361
  reason?: undefined;
@@ -16,18 +16,18 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
16
16
  error?: undefined;
17
17
  ok?: undefined;
18
18
  } | {
19
+ count?: undefined;
19
20
  updated: number;
20
21
  error?: undefined;
21
22
  ok?: undefined;
22
- count?: undefined;
23
23
  } | {
24
+ count?: undefined;
24
25
  updated?: undefined;
25
26
  error: string;
26
27
  ok?: undefined;
27
- count?: undefined;
28
28
  } | {
29
+ count?: undefined;
29
30
  updated?: undefined;
30
31
  error?: undefined;
31
32
  ok: boolean;
32
- count?: undefined;
33
33
  }>>;
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
+ error?: undefined;
45
+ ok?: undefined;
44
46
  summary: import("./types.js").TraceSummary;
45
47
  spans: import("./types.js").TraceSpan[];
46
48
  id?: undefined;
49
+ } | {
47
50
  error?: undefined;
48
51
  ok?: undefined;
49
- } | {
50
52
  summary?: undefined;
51
53
  spans?: undefined;
52
54
  id: string;
53
- error?: undefined;
54
- ok?: undefined;
55
55
  } | {
56
+ ok?: undefined;
56
57
  summary?: undefined;
57
58
  spans?: undefined;
58
59
  id?: undefined;
59
60
  error: any;
60
- ok?: undefined;
61
61
  } | {
62
+ error?: undefined;
62
63
  summary?: undefined;
63
64
  spans?: undefined;
64
65
  id?: undefined;
65
- error?: undefined;
66
66
  ok: boolean;
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
- found?: undefined;
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
- provider?: undefined;
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
- provider?: undefined;
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
- found?: undefined;
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
- id?: undefined;
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
- provider?: undefined;
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
- provider?: undefined;
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,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- status?: undefined;
38
37
  ok?: undefined;
38
+ status?: undefined;
39
39
  } | {
40
+ error?: undefined;
40
41
  ok: boolean;
41
42
  status: string;
42
- error?: undefined;
43
43
  } | {
44
+ ok?: undefined;
44
45
  error: string;
45
46
  removed?: undefined;
46
- ok?: undefined;
47
47
  } | {
48
+ error?: undefined;
48
49
  ok: boolean;
49
50
  removed: boolean;
50
- error?: undefined;
51
51
  }>>;
52
52
  /**
53
53
  * POST /_agent-native/secrets/:key/test — validate an optional candidate value
54
54
  * or the current stored value without changing anything.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
+ ok?: undefined;
57
58
  error: string;
58
59
  note?: undefined;
59
- ok?: undefined;
60
60
  } | {
61
+ error?: undefined;
61
62
  ok: boolean;
62
63
  note?: undefined;
63
- error?: undefined;
64
64
  } | {
65
+ error?: undefined;
65
66
  ok: boolean;
66
67
  note: string;
67
- error?: undefined;
68
68
  } | {
69
69
  note?: undefined;
70
70
  ok: boolean;
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
95
95
  export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
96
96
  error: string;
97
97
  } | {
98
+ error?: undefined;
98
99
  ok: boolean;
99
100
  key: string;
100
- error?: undefined;
101
101
  } | {
102
+ error?: undefined;
102
103
  ok: boolean;
103
104
  removed: boolean;
104
- error?: undefined;
105
105
  }>>;
@@ -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 connect→callback
113
- * round-trip. Prefixed with `_an_` to avoid collisions if Builder ever
114
- * adds standard OAuth `state` support to cli-auth. Builder preserves
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
- * query string so it survives Builder's redirect verbatim — Builder
245
- * preserves the redirect_url's existing query when appending p-key /
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 withBase = `${getOrigin(event)}${getAppBasePath()}${BUILDER_CALLBACK_PATH}`;
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 connect→callback
408
- * round-trip. Prefixed with `_an_` to avoid collisions if Builder ever
409
- * adds standard OAuth `state` support to cli-auth. Builder preserves
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
- * query string so it survives Builder's redirect verbatim — Builder
769
- * preserves the redirect_url's existing query when appending p-key /
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 finishBuilderOAuthAuthorization(input) {
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: withRecordedScopes(result.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) {