@agent-native/core 0.216.0 → 0.217.0

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 (56) hide show
  1. package/dist/app-config/analytics.js +1 -1
  2. package/dist/automation/index.d.ts +1 -1
  3. package/dist/client/analytics-session.d.ts +7 -0
  4. package/dist/client/analytics-session.js +27 -1
  5. package/dist/client/analytics.js +110 -15
  6. package/dist/client/consent.d.ts +12 -0
  7. package/dist/client/consent.js +132 -2
  8. package/dist/client/onboarding/index.d.ts +1 -0
  9. package/dist/client/onboarding/index.js +1 -0
  10. package/dist/client/onboarding/use-onboarding-checklist.d.ts +23 -0
  11. package/dist/client/onboarding/use-onboarding-checklist.js +115 -0
  12. package/dist/client/session-replay.d.ts +1 -1
  13. package/dist/client/session-replay.js +142 -3
  14. package/dist/collab/routes.d.ts +2 -2
  15. package/dist/collab/struct-routes.d.ts +1 -1
  16. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  17. package/dist/localization/consent-banner-messages.d.ts +16 -0
  18. package/dist/localization/consent-banner-messages.js +149 -0
  19. package/dist/localization/core-messages.js +4 -0
  20. package/dist/localization/default-messages.d.ts +1 -0
  21. package/dist/localization/default-messages.js +2 -0
  22. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  23. package/dist/notifications/routes.d.ts +2 -2
  24. package/dist/observability/routes.d.ts +6 -6
  25. package/dist/onboarding/index.d.ts +2 -1
  26. package/dist/onboarding/index.js +1 -0
  27. package/dist/onboarding/plugin.js +55 -46
  28. package/dist/onboarding/status.d.ts +15 -0
  29. package/dist/onboarding/status.js +59 -0
  30. package/dist/onboarding/types.d.ts +12 -0
  31. package/dist/onboarding/types.js +2 -1
  32. package/dist/org/workspace-app-access.js +19 -9
  33. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  34. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  35. package/dist/resources/handlers.d.ts +1 -1
  36. package/dist/server/agent-capabilities.js +13 -6
  37. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  38. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  39. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  40. package/dist/server/analytics.d.ts +0 -1
  41. package/dist/server/analytics.js +81 -20
  42. package/dist/server/builder-api-auth.d.ts +7 -0
  43. package/dist/server/builder-api-auth.js +24 -0
  44. package/dist/server/builder-oauth.d.ts +5 -1
  45. package/dist/server/builder-oauth.js +5 -0
  46. package/dist/server/core-routes-plugin.d.ts +1 -1
  47. package/dist/server/first-touch-route.d.ts +2 -2
  48. package/dist/server/index.d.ts +1 -1
  49. package/dist/server/index.js +1 -1
  50. package/dist/shared/consent.d.ts +2 -0
  51. package/dist/shared/consent.js +4 -0
  52. package/dist/triggers/actions/manage-automation.d.ts +5 -5
  53. package/dist/usage/actions/get-usage-metrics.js +3 -3
  54. package/docs/content/deployment-environment-variables.mdx +1 -1
  55. package/docs/content/environment-variables.mdx +1 -1
  56. package/package.json +5 -3
@@ -1,5 +1,7 @@
1
1
  import { getAppConfig } from "../app-config/index.js";
2
+ import { CONSENT_REGION_PATH, CONSENT_REGION_TIME_ZONE_LIST, } from "../shared/consent.js";
2
3
  import { SYNTHETIC_TRAFFIC_BETA_E2E } from "../shared/test-traffic.js";
4
+ import { publicFrameworkPath } from "./framework-route-prefix.js";
3
5
  const AGENT_NATIVE_ANALYTICS_DEFAULT_ENDPOINT = "https://analytics.agent-native.com/track";
4
6
  function normalizeMeasurementId(value) {
5
7
  const trimmed = value?.trim();
@@ -54,18 +56,18 @@ export function getAgentNativeAnalyticsConfigScript() {
54
56
  ");</script>",
55
57
  ].join("");
56
58
  }
57
- function escapeHtmlAttribute(value) {
58
- return value
59
- .replace(/&/g, "&amp;")
60
- .replace(/"/g, "&quot;")
61
- .replace(/</g, "&lt;")
62
- .replace(/>/g, "&gt;");
63
- }
64
- export function getHeadScriptTag() {
59
+ // A deployment's widget may set cookies or track, so it waits for
60
+ // performance consent like GA does.
61
+ function getHeadScript() {
65
62
  const src = getAppConfig().analytics.headScriptSrc;
66
63
  if (!src)
67
64
  return null;
68
- return `<script src="${escapeHtmlAttribute(src)}" defer data-agent-native-head-script></script>`;
65
+ // "<" inside an inline script could close it early.
66
+ const jsSrc = JSON.stringify(src).replace(/</g, "\\x3c");
67
+ return consentGatedScript("performance", `var agentNativeHeadScript=document.createElement('script');` +
68
+ `agentNativeHeadScript.src=${jsSrc};` +
69
+ `agentNativeHeadScript.setAttribute('data-agent-native-head-script','');` +
70
+ `document.head.appendChild(agentNativeHeadScript);`);
69
71
  }
70
72
  export function getGaInlineConfigScriptBody(options) {
71
73
  const id = getGaMeasurementId();
@@ -100,47 +102,106 @@ export function getGaInlineConfigScriptBody(options) {
100
102
  `document.head.appendChild(agentNativeGtagScript);` +
101
103
  `}`);
102
104
  }
105
+ /**
106
+ * Queue `body` until the visitor's region and choice allow `category`; the
107
+ * bootstrap after it, or `client/consent.ts` once loaded, runs it. A reject
108
+ * then a fresh accept calls it again, so it loads its tag only once a page.
109
+ */
110
+ function consentGatedScript(category, body) {
111
+ return `<script>(window.__AN_CONSENT_QUEUE__=window.__AN_CONSENT_QUEUE__||[]).push([${JSON.stringify(category)},(function(){var ran=false;return function(){if(ran)return;ran=true;${body}}})()]);</script>`;
112
+ }
113
+ const GA_FALLBACK_DATA_LAYER = "__AGENT_NATIVE_GA_DATA_LAYER__";
114
+ // gtag reads an `arguments` object from the data layer, never an array.
115
+ const GOOGLE_CONSENT_PUSH = `function push(g){for(var i=0;i<L.length;i++){var l=w[L[i]]=w[L[i]]||[];` +
116
+ `(function(){l.push(arguments)})("consent",g.mode,{analytics_storage:g.p?"granted":"denied",ad_storage:g.t?"granted":"denied",ad_user_data:g.t?"granted":"denied",ad_personalization:g.t?"granted":"denied"})}}`;
117
+ /**
118
+ * Google Consent Mode: before any Google tag loads, tell each data layer
119
+ * what the stored choice allows (nothing, without one), so tags already on
120
+ * the page stop storing and sending when `client/consent.ts` later pushes a
121
+ * reject. Lists the layers there, under `__AN_CONSENT_LAYERS__`.
122
+ */
123
+ function getGoogleConsentDefaultScript(dataLayers) {
124
+ return (`<script data-agent-native-consent-mode>(function(w,d){var L=${JSON.stringify(dataLayers)};w.__AN_CONSENT_LAYERS__=L;` +
125
+ GOOGLE_CONSENT_PUSH +
126
+ `var m=/(?:^|;\\s*)an_consent=1\\.p([01])\\.t([01])(?:;|$)/.exec(d.cookie||"");` +
127
+ `push({mode:"default",p:!!m&&m[1]==="1",t:!!m&&m[2]==="1"})` +
128
+ `})(window,document);</script>`);
129
+ }
130
+ /**
131
+ * Runs the queued tags on pages that never load the app bundle, like the
132
+ * plain sign-in page, and runs them without waiting for it elsewhere: at once
133
+ * for a stored choice or a region already known this session, else after
134
+ * asking the server, with the time zone as fallback. Once
135
+ * `client/consent.ts` replaces the queue it owns what's left, so nothing runs
136
+ * twice. Keep its cookie and region rules in step with that module.
137
+ */
138
+ function getConsentBootstrapScript() {
139
+ const zones = JSON.stringify(CONSENT_REGION_TIME_ZONE_LIST);
140
+ const regionPath = JSON.stringify(publicFrameworkPath(CONSENT_REGION_PATH));
141
+ return (`<script data-agent-native-consent>(function(w,d){var Q="__AN_CONSENT_QUEUE__",K="an_consent_region";` +
142
+ `function choice(){var m=/(?:^|;\\s*)an_consent=1\\.p([01])\\.t([01])(?:;|$)/.exec(d.cookie||"");return m?{performance:m[1]==="1",targeting:m[2]==="1"}:null}` +
143
+ `function allows(c,k,region){return c?c[k]:region==="none"}` +
144
+ `function run(region){var q=w[Q];if(!Array.isArray(q))return;var c=choice(),keep=[],L=w.__AN_CONSENT_LAYERS__||[];` +
145
+ GOOGLE_CONSENT_PUSH +
146
+ `push({mode:"update",p:allows(c,"performance",region),t:allows(c,"targeting",region)});` +
147
+ `for(var i=0;i<q.length;i++){var e=q[i];if(allows(c,e[0],region)){e[1]()}else{keep.push(e)}}q.length=0;q.push.apply(q,keep)}` +
148
+ `function zone(){try{return ${zones}.indexOf(Intl.DateTimeFormat().resolvedOptions().timeZone)>-1?"consent":"none"}catch(e){return"consent"}}` +
149
+ // coercion-ok: a page without session storage asks the server again.
150
+ `var cached=null;try{cached=w.sessionStorage.getItem(K)}catch(e){}` +
151
+ `if(choice()||cached==="consent"||cached==="none"){run(cached);return}` +
152
+ // An unreachable server falls back to the time zone.
153
+ // coercion-ok: a region it can't save is asked again on the next page.
154
+ `fetch(${regionPath},{credentials:"same-origin"}).then(function(r){return r.ok?r.json():{}}).then(function(b){return b&&(b.region==="consent"||b.region==="none")?b.region:zone()},zone).then(function(region){try{w.sessionStorage.setItem(K,region)}catch(e){}run(region)})` +
155
+ `})(window,document);</script>`);
156
+ }
103
157
  function getGaScript() {
104
158
  const id = getGaMeasurementId();
105
159
  if (!id)
106
160
  return null;
107
161
  const inlineBody = getGaInlineConfigScriptBody();
108
- return `<script>${inlineBody}</script>`;
162
+ return inlineBody ? consentGatedScript("performance", inlineBody) : null;
109
163
  }
110
164
  function getGtmGaFallbackScript() {
111
165
  const inlineBody = getGaInlineConfigScriptBody({
112
- dataLayerName: "__AGENT_NATIVE_GA_DATA_LAYER__",
166
+ dataLayerName: GA_FALLBACK_DATA_LAYER,
113
167
  sendPageView: false,
114
168
  });
115
- return inlineBody ? `<script>${inlineBody}</script>` : null;
169
+ return inlineBody ? consentGatedScript("performance", inlineBody) : null;
116
170
  }
171
+ // The container carries the ad pixels (Meta, LinkedIn, Reddit, X, Bing,
172
+ // Google Ads, OpenAI) and B2B identification tags alongside GA events, so it
173
+ // all waits for targeting. Its <noscript> iframe can't wait, so there is none.
117
174
  function getGtmHeadScript(containerId) {
118
175
  const jsId = JSON.stringify(containerId);
119
- return `<script>if(${getSyntheticTrafficBrowserGuard()}){(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer',${jsId});}</script>`;
120
- }
121
- function getGtmBodyFallback(containerId) {
122
- const src = encodeURIComponent(containerId);
123
- return `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${src}" height="0" width="0" style="display:none;visibility:hidden" title="Google Tag Manager"></iframe></noscript>`;
176
+ return consentGatedScript("targeting", `if(${getSyntheticTrafficBrowserGuard()}){(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer',${jsId});}`);
124
177
  }
125
178
  function getAnalyticsInjection() {
126
179
  const agentNativeAnalytics = getAgentNativeAnalyticsConfigScript();
127
- const headScript = getHeadScriptTag();
180
+ const headScript = getHeadScript();
128
181
  const containerId = getGtmContainerId();
129
182
  if (containerId) {
130
183
  return {
131
184
  head: [
132
185
  agentNativeAnalytics,
186
+ getGoogleConsentDefaultScript(["dataLayer", GA_FALLBACK_DATA_LAYER]),
133
187
  getGtmHeadScript(containerId),
134
188
  getGtmGaFallbackScript(),
135
189
  headScript,
190
+ getConsentBootstrapScript(),
136
191
  ]
137
192
  .filter(Boolean)
138
193
  .join(""),
139
- body: getGtmBodyFallback(containerId),
194
+ body: "",
140
195
  };
141
196
  }
142
197
  const gaScript = getGaScript();
143
- const head = [agentNativeAnalytics, gaScript, headScript]
198
+ const head = [
199
+ agentNativeAnalytics,
200
+ gaScript ? getGoogleConsentDefaultScript(["dataLayer"]) : null,
201
+ gaScript,
202
+ headScript,
203
+ gaScript || headScript ? getConsentBootstrapScript() : null,
204
+ ]
144
205
  .filter(Boolean)
145
206
  .join("");
146
207
  return head ? { head, body: "" } : null;
@@ -16,6 +16,13 @@ export interface BuilderRequestAuthorization {
16
16
  authorization: string;
17
17
  source: "oauth" | "legacy";
18
18
  oauthScope?: RemoteMcpScope;
19
+ oauthResource?: "general" | "publish";
20
+ oauthConnectionId?: string;
21
+ /**
22
+ * Space selected during Builder OAuth. This is only a request locator; the
23
+ * provider must verify the token and reject a different apiKey.
24
+ */
25
+ oauthSelectedPublicKey?: string;
19
26
  legacyCredentialKey?: BuilderLegacyCredentialKey;
20
27
  legacyPublicKey?: string;
21
28
  userId?: string;
@@ -51,6 +51,22 @@ function isBuilderPublishResource(value) {
51
51
  !url.search &&
52
52
  !url.hash);
53
53
  }
54
+ function selectedPublicKeyFromBuilderAccessToken(token) {
55
+ const payload = token.split(".")[1];
56
+ if (!payload)
57
+ return undefined;
58
+ try {
59
+ const decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
60
+ return typeof decoded.org === "string" && decoded.org.trim()
61
+ ? decoded.org.trim()
62
+ : undefined;
63
+ }
64
+ catch {
65
+ // coercion-ok: an opaque or malformed optional locator claim is absent;
66
+ // authorization remains the provider's signed-token responsibility.
67
+ return undefined;
68
+ }
69
+ }
54
70
  async function resolveBuilderPublishAuthorization(ownerEmail, orgId) {
55
71
  const candidates = orgId
56
72
  ? [{ scope: "org", scopeId: orgId }]
@@ -108,6 +124,7 @@ async function resolveBuilderPublishAuthorization(ownerEmail, orgId) {
108
124
  authorization: `Bearer ${match[1]}`,
109
125
  source: "oauth",
110
126
  oauthScope: candidate.scope,
127
+ oauthResource: "publish",
111
128
  };
112
129
  }
113
130
  if (ownerEmail) {
@@ -154,6 +171,7 @@ export async function resolveBuilderRequestAuthorization(input = {}) {
154
171
  throw new ActionContractError(`Builder.io access needs re-authorizing to grant ${input.requiredScope}. Open Settings and authorize Builder.io again.`, {
155
172
  errorCode: "builder_oauth_reauthorization_required",
156
173
  statusCode: 400,
174
+ details: { reason: "missing_scope", scope: input.requiredScope },
157
175
  });
158
176
  }
159
177
  throw err;
@@ -168,6 +186,7 @@ export async function resolveBuilderRequestAuthorization(input = {}) {
168
186
  throw new ActionContractError(`Builder.io access needs re-authorizing to grant ${input.requiredScope}. Open Settings and authorize Builder.io again.`, {
169
187
  errorCode: "builder_oauth_reauthorization_required",
170
188
  statusCode: 400,
189
+ details: { reason: "missing_scope", scope: input.requiredScope },
171
190
  });
172
191
  }
173
192
  return {
@@ -175,6 +194,11 @@ export async function resolveBuilderRequestAuthorization(input = {}) {
175
194
  authorization: `Bearer ${session.accessToken}`,
176
195
  source: "oauth",
177
196
  oauthScope: session.scope,
197
+ oauthResource: "general",
198
+ ...(session.connectionId
199
+ ? { oauthConnectionId: session.connectionId }
200
+ : {}),
201
+ oauthSelectedPublicKey: selectedPublicKeyFromBuilderAccessToken(session.accessToken),
178
202
  };
179
203
  }
180
204
  return resolveBuilderLegacyRequestAuthorization(input.legacyCredentialKeys);
@@ -3,7 +3,9 @@ export declare const BUILDER_OAUTH_ISSUER = "https://mcp.builder.io";
3
3
  export declare const BUILDER_OAUTH_RESOURCE = "https://api.builder.io";
4
4
  export declare const BUILDER_OAUTH_SCOPE = "builder:ai:invoke";
5
5
  export declare const BUILDER_ASSETS_WRITE_SCOPE = "builder:assets:write";
6
- export declare const BUILDER_OAUTH_SCOPES: readonly ["builder:ai:invoke", "builder:agents:run", "builder:browser:connect", "builder:assets:write", "builder:projects:read", "builder:projects:write", "builder:designsystem:read", "builder:designsystem:write"];
6
+ export declare const BUILDER_CONTENT_READ_SCOPE = "builder:content:read";
7
+ export declare const BUILDER_CONTENT_WRITE_SCOPE = "builder:content:write";
8
+ export declare const BUILDER_OAUTH_SCOPES: readonly ["builder:ai:invoke", "builder:agents:run", "builder:browser:connect", "builder:assets:write", "builder:content:read", "builder:content:write", "builder:projects:read", "builder:projects:write", "builder:designsystem:read", "builder:designsystem:write"];
7
9
  export type BuilderOAuthPermissionScope = (typeof BUILDER_OAUTH_SCOPES)[number];
8
10
  export type BuilderOAuthPendingFlow = {
9
11
  codeVerifier: string;
@@ -43,6 +45,8 @@ export type BuilderOAuthSession = {
43
45
  expiresAt?: number;
44
46
  scopes: string[];
45
47
  scope: BuilderOAuthScope;
48
+ /** Opaque identity of the selected stored OAuth credential lane. */
49
+ connectionId?: string;
46
50
  };
47
51
  export type BuilderOAuthRequestAccess = BuilderOAuthSession & {
48
52
  ownerEmail: string;
@@ -9,11 +9,15 @@ export const BUILDER_OAUTH_ISSUER = "https://mcp.builder.io";
9
9
  export const BUILDER_OAUTH_RESOURCE = "https://api.builder.io";
10
10
  export const BUILDER_OAUTH_SCOPE = "builder:ai:invoke";
11
11
  export const BUILDER_ASSETS_WRITE_SCOPE = "builder:assets:write";
12
+ export const BUILDER_CONTENT_READ_SCOPE = "builder:content:read";
13
+ export const BUILDER_CONTENT_WRITE_SCOPE = "builder:content:write";
12
14
  export const BUILDER_OAUTH_SCOPES = [
13
15
  BUILDER_OAUTH_SCOPE,
14
16
  "builder:agents:run",
15
17
  "builder:browser:connect",
16
18
  BUILDER_ASSETS_WRITE_SCOPE,
19
+ BUILDER_CONTENT_READ_SCOPE,
20
+ BUILDER_CONTENT_WRITE_SCOPE,
17
21
  "builder:projects:read",
18
22
  "builder:projects:write",
19
23
  "builder:designsystem:read",
@@ -290,6 +294,7 @@ export async function getBuilderOAuthSession(ownerEmail, orgId, requiredScope, a
290
294
  expiresAt: credentials.tokenExpiresAt,
291
295
  scopes,
292
296
  scope: options.scope,
297
+ connectionId: options.key,
293
298
  };
294
299
  }
295
300
  if (requiredScope && missingRequiredScope) {
@@ -588,8 +588,8 @@ export declare function createPublicRemoteAgentsHandler(discover?: PublicAgentDi
588
588
  error: string;
589
589
  agents?: undefined;
590
590
  } | {
591
- error?: undefined;
592
591
  agents: Omit<import("./agent-discovery.js").DiscoveredAgent, "auth" | "kind">[];
592
+ error?: undefined;
593
593
  }>>;
594
594
  export declare function getBuilderConnectErrorDisposition(error: unknown, connectAttemptId: string | null): "correlated" | "legacy" | null;
595
595
  export declare function getBuilderConnectErrorKey(ownerEmail: string, connectAttemptId?: string | null): string;
@@ -17,8 +17,8 @@ export type FirstTouchSyncResult = {
17
17
  * browser's `an_ft` and `an_lt` again, so Safari keeps them their 30 days.
18
18
  */
19
19
  export declare function createFirstTouchHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
20
- reason?: undefined;
21
20
  error: string;
21
+ reason?: undefined;
22
22
  stored?: undefined;
23
23
  firstTouch?: undefined;
24
24
  } | {
@@ -32,8 +32,8 @@ export declare function createFirstTouchHandler(): import("h3").EventHandlerWith
32
32
  reason: "expired";
33
33
  firstTouch?: undefined;
34
34
  } | {
35
- reason?: undefined;
36
35
  error?: undefined;
36
+ reason?: undefined;
37
37
  stored: true;
38
38
  firstTouch: FirstTouchAttribution;
39
39
  }>>;
@@ -104,7 +104,7 @@ export { resolveDeployPlatform, type DeployPlatform, } from "./deploy-environmen
104
104
  export { isServerlessRuntime } from "../db/client.js";
105
105
  export { BUILDER_PUBLISH_MCP_RESOURCE, canAuthorizeBuilderApiRequest, hasBuilderApiCredentialCustody, resolveBuilderApiAuthorization, resolveBuilderLegacyRequestAuthorization, resolveBuilderRequestAuthorization, type BuilderLegacyCredentialKey, type BuilderRequestAuthorization, } from "./builder-api-auth.js";
106
106
  export { createFusionAgentFeed, fusionStepToAgentChatEvents, type FusionAgentFeedSummary, } from "./fusion-agent-feed.js";
107
- export { BUILDER_ASSETS_WRITE_SCOPE, BUILDER_OAUTH_SCOPE, type BuilderOAuthPermissionScope, } from "./builder-oauth.js";
107
+ export { BUILDER_ASSETS_WRITE_SCOPE, BUILDER_CONTENT_READ_SCOPE, BUILDER_CONTENT_WRITE_SCOPE, BUILDER_OAUTH_RESOURCE, BUILDER_OAUTH_SCOPE, type BuilderOAuthPermissionScope, } from "./builder-oauth.js";
108
108
  export { assertBuilderDesignSystemCodeIndexingAllowed, builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, collectBuilderDesignSystemGitHubFiles, createBuilderDesignSystemProxyFields, designSystemTierUpgradeUrl, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, fetchBuilderDesignSystemDocumentCount, fetchBuilderDesignSystemRecord, fetchBuilderDesignSystemTierLimit, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, isBuilderDesignSystemReadyByCount, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, type BuildBuilderDesignSystemIndexFilesOptions, type BuilderDesignSystemCodeFileInput, type BuilderDesignSystemDecodeJobStatus, type BuilderDesignSystemDocsOptions, type BuilderDesignSystemDocument, type BuilderDesignSystemDocumentCountResult, type BuilderDesignSystemHydratedReference, type BuilderDesignSystemIndexFile, type BuilderDesignSystemIndexFromSourcesOptions, type BuilderDesignSystemIndexOptions, type BuilderDesignSystemIndexResult, type BuilderDesignSystemRecord, type BuilderDesignSystemStatus, type BuilderDesignSystemTierLimit, type BuilderDesignSystemGitHubFile, type BuilderDesignSystemGitHubFileCollection, type BuilderDesignSystemGitHubSource, type BuilderDesignSystemUploadAttachment, type BuilderDesignSystemUploadSlot, type BuilderDesignSystemProxyFields, type BuilderDesignSystemProxyFieldsOptions, type BuilderDesignSystemProxyReference, type BuilderDesignSystemSourceKind, } from "./builder-design-systems.js";
109
109
  export { cdnSafeOriginStatus, createBuilderProject, ensureBuilderProject, findBuilderProjectForRepo, getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, normalizeBuilderAgentAttachments, runBuilderAgent, type BuilderAgentAttachment, type BuilderAgentUploadAttachment, type BuilderAgentUrlAttachment, type BuilderProjectResult, type RunBuilderAgentResult, } from "./builder-browser.js";
110
110
  export { BuilderBranchError, getBuilderBranchStatus, sendBuilderBranchMessage, type BuilderBranchAgentState, type BuilderBranchErrorCode, type BuilderBranchOperation, type BuilderBranchPrStatus, type BuilderBranchRef, type BuilderBranchState, type BuilderBranchStatus, type GetBuilderBranchStatusOptions, type SendBuilderBranchMessageOptions, type SendBuilderBranchMessageResult, } from "./builder-branch.js";
@@ -98,7 +98,7 @@ export { resolveDeployPlatform, } from "./deploy-environment.js";
98
98
  export { isServerlessRuntime } from "../db/client.js";
99
99
  export { BUILDER_PUBLISH_MCP_RESOURCE, canAuthorizeBuilderApiRequest, hasBuilderApiCredentialCustody, resolveBuilderApiAuthorization, resolveBuilderLegacyRequestAuthorization, resolveBuilderRequestAuthorization, } from "./builder-api-auth.js";
100
100
  export { createFusionAgentFeed, fusionStepToAgentChatEvents, } from "./fusion-agent-feed.js";
101
- export { BUILDER_ASSETS_WRITE_SCOPE, BUILDER_OAUTH_SCOPE, } from "./builder-oauth.js";
101
+ export { BUILDER_ASSETS_WRITE_SCOPE, BUILDER_CONTENT_READ_SCOPE, BUILDER_CONTENT_WRITE_SCOPE, BUILDER_OAUTH_RESOURCE, BUILDER_OAUTH_SCOPE, } from "./builder-oauth.js";
102
102
  export { assertBuilderDesignSystemCodeIndexingAllowed, builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, collectBuilderDesignSystemGitHubFiles, createBuilderDesignSystemProxyFields, designSystemTierUpgradeUrl, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, fetchBuilderDesignSystemDocumentCount, fetchBuilderDesignSystemRecord, fetchBuilderDesignSystemTierLimit, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, isBuilderDesignSystemReadyByCount, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, } from "./builder-design-systems.js";
103
103
  export { cdnSafeOriginStatus, createBuilderProject, ensureBuilderProject, findBuilderProjectForRepo, getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, normalizeBuilderAgentAttachments, runBuilderAgent, } from "./builder-browser.js";
104
104
  export { BuilderBranchError, getBuilderBranchStatus, sendBuilderBranchMessage, } from "./builder-branch.js";
@@ -3,6 +3,8 @@
3
3
  * follow builder.io's consent banner: visitors in these countries opt in, and
4
4
  * every other visitor is tracked as before, with no banner.
5
5
  */
6
+ /** For the inline bootstrap the server writes into each page. */
7
+ export declare const CONSENT_REGION_TIME_ZONE_LIST: readonly string[];
6
8
  export declare function isConsentRegionCountry(code: string | null | undefined): boolean;
7
9
  export declare function isConsentRegionTimeZone(timeZone: string | null | undefined): boolean;
8
10
  /**
@@ -106,6 +106,10 @@ const CONSENT_REGION_TIME_ZONES = new Set([
106
106
  "Portugal",
107
107
  "WET",
108
108
  ]);
109
+ /** For the inline bootstrap the server writes into each page. */
110
+ export const CONSENT_REGION_TIME_ZONE_LIST = [
111
+ ...CONSENT_REGION_TIME_ZONES,
112
+ ];
109
113
  export function isConsentRegionCountry(code) {
110
114
  return CONSENT_REGION_COUNTRY_CODES.has(code?.trim().toUpperCase() ?? "");
111
115
  }
@@ -67,7 +67,6 @@ declare const _default: import("../../action.js").ActionDefinition<{
67
67
  triggerType: "event" | "manual" | "schedule" | "webhook";
68
68
  body: string;
69
69
  }, {
70
- deleted?: undefined;
71
70
  created: boolean;
72
71
  resourceId: string;
73
72
  name: string;
@@ -88,25 +87,26 @@ declare const _default: import("../../action.js").ActionDefinition<{
88
87
  executionCwd: string;
89
88
  mcpTools: string[];
90
89
  webhookPath: string;
90
+ deleted?: undefined;
91
91
  updated?: undefined;
92
92
  changed?: undefined;
93
93
  previouslyEnabled?: undefined;
94
94
  requestedEnabled?: undefined;
95
95
  } | {
96
- scope?: undefined;
97
- enabled?: undefined;
98
- nextRun?: undefined;
99
96
  created?: undefined;
100
97
  deleted: boolean;
101
98
  resourceId: string;
102
99
  name: string;
103
100
  updated?: undefined;
101
+ scope?: undefined;
104
102
  triggerType?: undefined;
105
103
  event?: undefined;
106
104
  schedule?: undefined;
107
105
  timezone?: undefined;
108
106
  condition?: undefined;
109
107
  body?: undefined;
108
+ enabled?: undefined;
109
+ nextRun?: undefined;
110
110
  createdBy?: undefined;
111
111
  model?: undefined;
112
112
  reasoningEffort?: undefined;
@@ -119,8 +119,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
119
119
  requestedEnabled?: undefined;
120
120
  webhookPath?: undefined;
121
121
  } | {
122
- deleted?: undefined;
123
122
  created?: undefined;
123
+ deleted?: undefined;
124
124
  updated: boolean;
125
125
  resourceId: string;
126
126
  name: string;
@@ -17,7 +17,7 @@ function resolveAppSelection(app, appId) {
17
17
  return app;
18
18
  }
19
19
  export default defineAction({
20
- description: 'Reports this workspace\'s own agent/LLM usage (Settings › Usage) for members of this organization only; it does NOT cover usage, credits, or activity of external customers, accounts, companies, or product usage, which belong to the app that owns that data (see <relevant-apps>, or search with describe-workspace-apps). Returns lookback totals, the daily trend (dailyBy feature, app, model and surface), top features, models, apps, chats and people, tool calls per day, and recent prompts, across every app unless app names one. Members see only their own usage; scope "workspace" (everyone in the organization) is for owners and admins. billing.unit identifies Builder.io credits, estimated dollars, mixed billing, or unknown.',
20
+ description: "Reports this workspace's own agent/LLM usage (Settings › Usage) for members of this organization only; it does NOT cover usage, credits, or activity of external customers, accounts, companies, or product usage, use this app's own customer or billing actions for those, or the app that owns that data (see <relevant-apps>, or search with describe-workspace-apps). Returns lookback totals, the daily trend (dailyBy feature, app, model and surface), top features, models, apps, chats and people, tool calls per day, and recent prompts, across every app unless app names one. Members see only their own usage; scope \"workspace\" (everyone in the organization) is for owners and admins. billing.unit identifies Builder.io credits, estimated dollars, mixed billing, or unknown.",
21
21
  http: { method: "GET" },
22
22
  schema: z.object({
23
23
  sinceDays: z.coerce.number().int().min(1).max(365).default(30),
@@ -56,10 +56,10 @@ export default defineAction({
56
56
  ownerEmail: ctx.userEmail,
57
57
  orgId: ctx.orgId,
58
58
  }))) {
59
- fail("Only organization owners and admins can look up another person's usage with get-usage-metrics. Usage, credits, or activity for customers, accounts, or companies belongs to the app that owns that data (see <relevant-apps> or run describe-workspace-apps with a query).", { errorCode: "usage_user_lookup_forbidden", statusCode: 403 });
59
+ fail(`get-usage-metrics cannot answer this. For a teammate in this organization, only owners and admins can look up their usage. For a customer or other external user, get-usage-metrics has no data: use this app's own customer or billing actions if it has any, or find the app that owns that data with describe-workspace-apps query="<what you need>" and delegate with call-agent.`, { errorCode: "usage_user_lookup_forbidden", statusCode: 403 });
60
60
  }
61
61
  if (!(await isOrgMember(ctx.orgId, userEmail))) {
62
- fail(`${userEmail} is not a member of this organization. get-usage-metrics only covers this workspace's own agent usage; usage, credits, or activity for customers, accounts, or companies belongs to the app that owns that data (see <relevant-apps> or run describe-workspace-apps with a query).`, { errorCode: "usage_user_not_org_member", statusCode: 404 });
62
+ fail(`${userEmail} is not a member of this organization, so get-usage-metrics has no data on them. For a customer's or account's usage or credits, use this app's own customer or billing actions if it has any, or find the app that owns that data with describe-workspace-apps query="<what you need>" and delegate with call-agent.`, { errorCode: "usage_user_not_org_member", statusCode: 404 });
63
63
  }
64
64
  }
65
65
  const selection = resolveAppSelection(app, appId);
@@ -20,7 +20,7 @@ hosting behavior.
20
20
  | `APP_URL` | Optional canonical public origin. Checked ahead of `BETTER_AUTH_URL` when resolving the A2A JWT audience, the OAuth public origin, self-dispatch webhook targets, and generated resource links. Set it explicitly on preview/staging deploys where the request host is unreliable. |
21
21
  | `AGENT_PROD_CODE_EXECUTION` | Optional production code-execution mode: `off` (default), `sandboxed`, or `trusted`. See [Production Code Execution](/docs/actions-agent-tools#production-code-execution). |
22
22
  | `AGENT_NATIVE_SSR_CACHE` | Deployment-wide SSR shell cache policy: unset/`on` keeps the default hard-cache, `off` sends `no-store`, or a duration such as `30s` / `5m` sets a shorter freshness. See [SSR Caching](/docs/ssr-caching). |
23
- | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Optional HTTPS URL of a script loaded with `defer` in the `<head>` of every server-rendered page. Use it for deployment-specific tooling such as an internal feedback widget, without changing app source. Non-HTTPS URLs fail config validation. |
23
+ | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Optional HTTPS URL of a script added to the `<head>` of every server-rendered page. Where the consent banner shows, it waits for analytics consent, like Google Analytics. Use it for deployment-specific tooling such as an internal feedback widget, without changing app source. Non-HTTPS URLs fail config validation. |
24
24
  | `AGENT_NATIVE_ENABLE_KEEP_WARM` | Opt into the Netlify keep-warm scheduled function. Unset by default. See [Keep-warm](/docs/netlify#netlify-keep-warm). |
25
25
  | `AGENT_NATIVE_DISABLE_KEEP_WARM` | Compatibility kill switch for the Netlify keep-warm scheduled function. See [Keep-warm](/docs/netlify#netlify-keep-warm). |
26
26
  | `AGENT_NATIVE_KEEP_WARM_SCHEDULE` | Override the keep-warm cadence with a 5-field cron expression (default `* * * * *` when enabled). An unparseable value fails the build. See [Keep-warm](/docs/netlify#netlify-keep-warm). |
@@ -95,7 +95,7 @@ public app behavior, use the config paths above instead.
95
95
  | `ACCESS_TOKEN` / `ACCESS_TOKENS` | Static bearer fallback for MCP and Connect clients. | One token or a delimited token list; these are not browser auth. |
96
96
  | `AGENT_PROD_CODE_EXECUTION` | Production code-execution policy. | `off`, `sandboxed`, or `trusted`. See [Production Code Execution](/docs/actions-agent-tools#production-code-execution). |
97
97
  | `AGENT_NATIVE_SSR_CACHE` | Deployment-wide public SSR shell cache policy. | Unset/`on`, `off`, or a duration such as `30s` or `5m`. See [SSR Caching](/docs/ssr-caching). |
98
- | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Extra script injected into every server-rendered page head with `defer`. | An absolute `https://` URL; non-HTTPS values fail config validation. |
98
+ | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Extra script added to every server-rendered page head. Where the consent banner shows, it waits for analytics consent, like Google Analytics. | An absolute `https://` URL; non-HTTPS values fail config validation. |
99
99
  | `AGENT_NATIVE_ENABLE_KEEP_WARM` | Opts into the Netlify keep-warm scheduled function; unset by default. | `1`; see [Keep-warm](/docs/netlify#netlify-keep-warm). |
100
100
  | `AGENT_NATIVE_DISABLE_KEEP_WARM` | Compatibility kill switch for the Netlify keep-warm scheduled function. | `1`; see [Keep-warm](/docs/netlify#netlify-keep-warm). |
101
101
  | `AGENT_NATIVE_KEEP_WARM_SCHEDULE` | Keep-warm cadence override when enabled. | A 5-field cron expression such as `*/5 * * * *`; an unparseable value fails the build. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.216.0",
3
+ "version": "0.217.0",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -552,6 +552,7 @@
552
552
  "./client/onboarding/first-run-registry": "./dist/client/onboarding/first-run-registry.js",
553
553
  "./client/onboarding/first-run-status": "./dist/client/onboarding/first-run-status.js",
554
554
  "./client/onboarding/use-onboarding": "./dist/client/onboarding/use-onboarding.js",
555
+ "./client/onboarding/use-onboarding-checklist": "./dist/client/onboarding/use-onboarding-checklist.js",
555
556
  "./client/onboarding/use-preview-mode": "./dist/client/onboarding/use-preview-mode.js",
556
557
  "./client/org/hooks": "./dist/client/org/hooks.js",
557
558
  "./client/resources/mcp-connection-resume": "./dist/client/resources/mcp-connection-resume.js",
@@ -601,6 +602,7 @@
601
602
  "./notifications/types": "./dist/notifications/types.js",
602
603
  "./observability/types": "./dist/observability/types.js",
603
604
  "./onboarding/types": "./dist/onboarding/types.js",
605
+ "./onboarding/status": "./dist/onboarding/status.js",
604
606
  "./onboarding/workspace-services": "./dist/onboarding/workspace-services.js",
605
607
  "./onboarding/app-profile-data": "./dist/onboarding/app-profile-data.js",
606
608
  "./org/app-roles": "./dist/org/app-roles.js",
@@ -728,8 +730,8 @@
728
730
  "yaml": "^2.9.0",
729
731
  "yjs": "^13.6.33",
730
732
  "zod": "^4.3.6",
731
- "@agent-native/agentkit": "^0.216.0",
732
- "@agent-native/recap-cli": "^0.5.85"
733
+ "@agent-native/agentkit": "^0.217.0",
734
+ "@agent-native/recap-cli": "^0.5.86"
733
735
  },
734
736
  "devDependencies": {
735
737
  "@ai-sdk/anthropic": "^3.0.71",