@agent-native/core 0.216.0 → 0.218.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.
- package/dist/app-config/analytics.js +1 -1
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/analytics-session.d.ts +7 -0
- package/dist/client/analytics-session.js +27 -1
- package/dist/client/analytics.js +110 -15
- package/dist/client/consent.d.ts +12 -0
- package/dist/client/consent.js +132 -2
- package/dist/client/onboarding/index.d.ts +1 -0
- package/dist/client/onboarding/index.js +1 -0
- package/dist/client/onboarding/use-onboarding-checklist.d.ts +23 -0
- package/dist/client/onboarding/use-onboarding-checklist.js +115 -0
- package/dist/client/session-replay.d.ts +1 -1
- package/dist/client/session-replay.js +142 -3
- package/dist/client/use-chat-thread-list.d.ts +3 -0
- package/dist/client/use-chat-thread-list.js +23 -7
- package/dist/collab/routes.d.ts +1 -1
- package/dist/localization/consent-banner-messages.d.ts +16 -0
- package/dist/localization/consent-banner-messages.js +149 -0
- package/dist/localization/core-messages.js +4 -0
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.js +2 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +7 -7
- package/dist/onboarding/index.d.ts +2 -1
- package/dist/onboarding/index.js +1 -0
- package/dist/onboarding/plugin.js +55 -46
- package/dist/onboarding/status.d.ts +15 -0
- package/dist/onboarding/status.js +59 -0
- package/dist/onboarding/types.d.ts +12 -0
- package/dist/onboarding/types.js +2 -1
- package/dist/org/workspace-app-access.js +19 -9
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +10 -10
- package/dist/server/agent-capabilities.js +13 -6
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/analytics.d.ts +0 -1
- package/dist/server/analytics.js +81 -20
- package/dist/server/builder-api-auth.d.ts +7 -0
- package/dist/server/builder-api-auth.js +24 -0
- package/dist/server/builder-oauth.d.ts +5 -1
- package/dist/server/builder-oauth.js +5 -0
- package/dist/server/first-touch-route.d.ts +2 -2
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/shared/consent.d.ts +2 -0
- package/dist/shared/consent.js +4 -0
- package/dist/templates/builder-code-starter/template-layer.json +1 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +62 -101
- package/dist/triggers/actions/manage-automation.d.ts +1 -1
- package/dist/usage/actions/get-usage-metrics.js +3 -3
- package/docs/content/components.mdx +19 -18
- package/docs/content/deployment-environment-variables.mdx +1 -1
- package/docs/content/environment-variables.mdx +1 -1
- package/docs/content/sharing.mdx +4 -0
- package/docs/content/toolkit-sharing.mdx +31 -51
- package/migration-manifest.json +1 -1
- package/package.json +5 -3
- package/src/templates/builder-code-starter/template-layer.json +1 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +62 -101
- package/dist/templates/chat/app/lib/sidebar-thread-state.ts +0 -29
- package/src/templates/chat/app/lib/sidebar-thread-state.ts +0 -29
package/dist/server/analytics.js
CHANGED
|
@@ -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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.replace(/"/g, """)
|
|
61
|
-
.replace(/</g, "<")
|
|
62
|
-
.replace(/>/g, ">");
|
|
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
|
-
|
|
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
|
|
162
|
+
return inlineBody ? consentGatedScript("performance", inlineBody) : null;
|
|
109
163
|
}
|
|
110
164
|
function getGtmGaFallbackScript() {
|
|
111
165
|
const inlineBody = getGaInlineConfigScriptBody({
|
|
112
|
-
dataLayerName:
|
|
166
|
+
dataLayerName: GA_FALLBACK_DATA_LAYER,
|
|
113
167
|
sendPageView: false,
|
|
114
168
|
});
|
|
115
|
-
return inlineBody ?
|
|
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
|
|
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 =
|
|
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:
|
|
194
|
+
body: "",
|
|
140
195
|
};
|
|
141
196
|
}
|
|
142
197
|
const gaScript = getGaScript();
|
|
143
|
-
const head = [
|
|
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
|
|
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) {
|
|
@@ -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
|
}>>;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -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";
|
package/dist/server/index.js
CHANGED
|
@@ -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";
|
|
@@ -54,8 +54,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
54
54
|
expiresAt?: undefined;
|
|
55
55
|
ttlSeconds?: undefined;
|
|
56
56
|
} | {
|
|
57
|
-
error?: undefined;
|
|
58
57
|
token: string;
|
|
59
58
|
expiresAt: string;
|
|
60
59
|
ttlSeconds: number;
|
|
60
|
+
error?: undefined;
|
|
61
61
|
}>>;
|
package/dist/shared/consent.d.ts
CHANGED
|
@@ -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
|
/**
|
package/dist/shared/consent.js
CHANGED
|
@@ -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
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { appPath } from "@agent-native/core/client/api-path";
|
|
1
2
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
3
|
import {
|
|
3
4
|
navigateWithAgentChatViewTransition,
|
|
@@ -5,14 +6,15 @@ import {
|
|
|
5
6
|
useChatThreads,
|
|
6
7
|
type ChatThreadSummary,
|
|
7
8
|
} from "@agent-native/toolkit/app/chat/agentkit-chat/rail";
|
|
9
|
+
import {
|
|
10
|
+
ownDraftRows,
|
|
11
|
+
OwnershipChatHistoryRail,
|
|
12
|
+
useOwnershipChatHistory,
|
|
13
|
+
type OwnDraftRow,
|
|
14
|
+
} from "@agent-native/toolkit/app/chat/ownership-history";
|
|
8
15
|
import { OrgSwitcher } from "@agent-native/toolkit/app/org";
|
|
9
16
|
import { openCommandMenu } from "@agent-native/toolkit/app/shared";
|
|
10
17
|
import { AgentNativeIcon } from "@agent-native/toolkit/app/shared/AgentNativeIcon";
|
|
11
|
-
import {
|
|
12
|
-
ChatHistoryList,
|
|
13
|
-
type ChatHistoryItem,
|
|
14
|
-
type ChatHistorySection,
|
|
15
|
-
} from "@agent-native/toolkit/chat-history/ChatHistoryList";
|
|
16
18
|
import {
|
|
17
19
|
IconApps,
|
|
18
20
|
IconClock,
|
|
@@ -25,7 +27,7 @@ import {
|
|
|
25
27
|
IconPin,
|
|
26
28
|
IconSearch,
|
|
27
29
|
} from "@tabler/icons-react";
|
|
28
|
-
import { useEffect,
|
|
30
|
+
import { useEffect, useRef, useState } from "react";
|
|
29
31
|
import { Link, useLocation, useNavigate } from "react-router";
|
|
30
32
|
import { toast } from "sonner";
|
|
31
33
|
|
|
@@ -41,7 +43,6 @@ import {
|
|
|
41
43
|
} from "@/components/ui/tooltip";
|
|
42
44
|
import { APP_TITLE } from "@/lib/app-config";
|
|
43
45
|
import { chatThreadPath, HOME_PATH, threadIdFromPath } from "@/lib/chat-paths";
|
|
44
|
-
import { visibleChatThreads } from "@/lib/sidebar-thread-state";
|
|
45
46
|
import { cn } from "@/lib/utils";
|
|
46
47
|
|
|
47
48
|
const CHAT_STORAGE_KEY = "chat";
|
|
@@ -53,11 +54,9 @@ interface SidebarProps {
|
|
|
53
54
|
onCollapsedChange?: (collapsed: boolean) => void;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
function threadUpdatedAt(thread: ChatThreadSummary) {
|
|
57
|
+
function threadUpdatedAt(
|
|
58
|
+
thread: Pick<ChatThreadSummary, "createdAt" | "updatedAt">,
|
|
59
|
+
) {
|
|
61
60
|
return Number.isFinite(thread.updatedAt)
|
|
62
61
|
? thread.updatedAt
|
|
63
62
|
: Number.isFinite(thread.createdAt)
|
|
@@ -65,14 +64,6 @@ function threadUpdatedAt(thread: ChatThreadSummary) {
|
|
|
65
64
|
: 0;
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
function compareRecentThreads(a: ChatThreadSummary, b: ChatThreadSummary) {
|
|
69
|
-
return threadUpdatedAt(b) - threadUpdatedAt(a);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function comparePinnedThreads(a: ChatThreadSummary, b: ChatThreadSummary) {
|
|
73
|
-
return (b.pinnedAt ?? 0) - (a.pinnedAt ?? 0);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
67
|
function formatRelativeTime(timestamp: number) {
|
|
77
68
|
const elapsed = timestamp - Date.now();
|
|
78
69
|
const intervals = [
|
|
@@ -106,7 +97,10 @@ function ThreadHistoryTitle({
|
|
|
106
97
|
title,
|
|
107
98
|
running,
|
|
108
99
|
}: {
|
|
109
|
-
thread:
|
|
100
|
+
thread: OwnDraftRow &
|
|
101
|
+
Partial<
|
|
102
|
+
Pick<ChatThreadSummary, "preview" | "scope" | "source" | "pinnedAt">
|
|
103
|
+
>;
|
|
110
104
|
title: string;
|
|
111
105
|
running: boolean;
|
|
112
106
|
}) {
|
|
@@ -287,7 +281,7 @@ function ChatThreadsSection({ collapsed }: { collapsed: boolean }) {
|
|
|
287
281
|
pinThread,
|
|
288
282
|
archiveThread,
|
|
289
283
|
renameThread,
|
|
290
|
-
|
|
284
|
+
isNewThread,
|
|
291
285
|
} = useChatThreads(undefined, CHAT_STORAGE_KEY, undefined, {
|
|
292
286
|
autoCreate: false,
|
|
293
287
|
restoreActiveThread: false,
|
|
@@ -295,66 +289,46 @@ function ChatThreadsSection({ collapsed }: { collapsed: boolean }) {
|
|
|
295
289
|
const { workingThreadIds, observedThreadStarts } =
|
|
296
290
|
useAgentChatRunningThreads();
|
|
297
291
|
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
292
|
+
const localMineRows = ownDraftRows({
|
|
293
|
+
threads,
|
|
294
|
+
isNewThread,
|
|
295
|
+
observedThreadStarts,
|
|
296
|
+
});
|
|
297
|
+
const history = useOwnershipChatHistory({
|
|
298
|
+
getThreadUrl: (threadId) => appPath(chatThreadPath(threadId)),
|
|
299
|
+
activeId:
|
|
300
|
+
threadIdFromPath(location.pathname) ??
|
|
301
|
+
activeThreadId ??
|
|
302
|
+
persistedActiveThreadId(),
|
|
303
|
+
localMineRows,
|
|
304
|
+
pinned: { label: t("chat.pinned") },
|
|
305
|
+
mutations: {
|
|
306
|
+
pin: pinThread,
|
|
307
|
+
rename: renameThread,
|
|
308
|
+
archive: archiveThread,
|
|
309
|
+
},
|
|
310
|
+
onMutationFailed: (kind) => {
|
|
311
|
+
if (kind === "archive") toast.error(t("chat.archiveFailed"));
|
|
312
|
+
if (kind === "rename") toast.error(t("chat.renameFailed"));
|
|
313
|
+
},
|
|
314
|
+
decorateItem: (item, row) => {
|
|
315
|
+
const title = row.title || row.preview || t("chat.untitledChat");
|
|
311
316
|
return {
|
|
312
|
-
|
|
317
|
+
...item,
|
|
313
318
|
title: (
|
|
314
319
|
<ThreadHistoryTitle
|
|
315
|
-
thread={
|
|
320
|
+
thread={row}
|
|
316
321
|
title={title}
|
|
317
|
-
running={workingThreadIds.has(
|
|
322
|
+
running={workingThreadIds.has(row.id)}
|
|
318
323
|
/>
|
|
319
324
|
),
|
|
320
|
-
titleText: title,
|
|
321
|
-
pinned: Boolean(thread.pinnedAt),
|
|
322
325
|
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
.filter((thread) => !thread.pinnedAt)
|
|
330
|
-
.sort(compareRecentThreads)
|
|
331
|
-
.slice(0, 30)
|
|
332
|
-
.map(toItem);
|
|
333
|
-
|
|
334
|
-
return [
|
|
335
|
-
{ id: "pinned", label: t("chat.pinned"), items: pinned },
|
|
336
|
-
{ id: "recents", label: t("chat.recents"), items: recent },
|
|
337
|
-
];
|
|
338
|
-
}, [t, visibleThreads, workingThreadIds]);
|
|
339
|
-
|
|
340
|
-
useEffect(() => {
|
|
341
|
-
const refresh = () => refreshThreads();
|
|
342
|
-
const handleRunning = (event: Event) => {
|
|
343
|
-
const detail = (event as CustomEvent).detail as
|
|
344
|
-
| { isRunning?: unknown }
|
|
345
|
-
| undefined;
|
|
346
|
-
if (typeof detail?.isRunning === "boolean") refreshThreads();
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
window.addEventListener("agent-chat:threads-updated", refresh);
|
|
350
|
-
window.addEventListener("agentNative.chatRunning", handleRunning);
|
|
351
|
-
window.addEventListener("focus", refresh);
|
|
352
|
-
return () => {
|
|
353
|
-
window.removeEventListener("agent-chat:threads-updated", refresh);
|
|
354
|
-
window.removeEventListener("agentNative.chatRunning", handleRunning);
|
|
355
|
-
window.removeEventListener("focus", refresh);
|
|
356
|
-
};
|
|
357
|
-
}, [refreshThreads]);
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
const displayedActiveThreadId =
|
|
329
|
+
threadIdFromPath(location.pathname) ??
|
|
330
|
+
activeThreadId ??
|
|
331
|
+
persistedActiveThreadId();
|
|
358
332
|
|
|
359
333
|
function openThread(threadId: string, options?: { isNew?: boolean }) {
|
|
360
334
|
switchThread(threadId);
|
|
@@ -382,23 +356,6 @@ function ChatThreadsSection({ collapsed }: { collapsed: boolean }) {
|
|
|
382
356
|
if (threadId) openThread(threadId, { isNew: true });
|
|
383
357
|
}
|
|
384
358
|
|
|
385
|
-
async function handleArchiveThread(threadId: string) {
|
|
386
|
-
const wasActive =
|
|
387
|
-
threadId === activeThreadId || threadId === persistedActiveThreadId();
|
|
388
|
-
const archived = await archiveThread(threadId);
|
|
389
|
-
if (!archived) {
|
|
390
|
-
toast.error(t("chat.archiveFailed"));
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
if (wasActive) await handleNewChat();
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
function handleRenameThread(threadId: string, title: string) {
|
|
397
|
-
void renameThread(threadId, title).then((renamed) => {
|
|
398
|
-
if (!renamed) toast.error(t("chat.renameFailed"));
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
359
|
const newChatButton = (
|
|
403
360
|
<button
|
|
404
361
|
type="button"
|
|
@@ -430,17 +387,20 @@ function ChatThreadsSection({ collapsed }: { collapsed: boolean }) {
|
|
|
430
387
|
return (
|
|
431
388
|
<div className="flex min-h-0 flex-1 flex-col">
|
|
432
389
|
<div className="px-2 pb-3">{newChatButton}</div>
|
|
433
|
-
<
|
|
434
|
-
|
|
390
|
+
<OwnershipChatHistoryRail
|
|
391
|
+
{...history}
|
|
392
|
+
onNewChat={() => void handleNewChat()}
|
|
393
|
+
showNewChat={false}
|
|
435
394
|
activeId={displayedActiveThreadId}
|
|
436
395
|
onSelect={openThread}
|
|
437
|
-
|
|
438
|
-
const
|
|
439
|
-
|
|
396
|
+
onDelete={async (threadId) => {
|
|
397
|
+
const wasActive =
|
|
398
|
+
threadId === activeThreadId ||
|
|
399
|
+
threadId === persistedActiveThreadId();
|
|
400
|
+
const archived = await history.listProps.onDelete?.(threadId);
|
|
401
|
+
if (archived && wasActive) await handleNewChat();
|
|
440
402
|
}}
|
|
441
|
-
onRename={handleRenameThread}
|
|
442
403
|
renameMaxLength={160}
|
|
443
|
-
onDelete={(threadId) => void handleArchiveThread(threadId)}
|
|
444
404
|
labels={{
|
|
445
405
|
options: (item) =>
|
|
446
406
|
t("chat.optionsFor", { title: item.titleText ?? "" }),
|
|
@@ -451,8 +411,9 @@ function ChatThreadsSection({ collapsed }: { collapsed: boolean }) {
|
|
|
451
411
|
unpin: t("chat.unpinChat"),
|
|
452
412
|
delete: t("chat.archiveChat"),
|
|
453
413
|
}}
|
|
454
|
-
|
|
455
|
-
|
|
414
|
+
railLabels={{
|
|
415
|
+
newChat: t("chat.newChat"),
|
|
416
|
+
}}
|
|
456
417
|
className="chat-sidebar-history min-h-0 flex-1"
|
|
457
418
|
listClassName="pb-4"
|
|
458
419
|
/>
|
|
@@ -93,7 +93,6 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
93
93
|
previouslyEnabled?: undefined;
|
|
94
94
|
requestedEnabled?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
scope?: undefined;
|
|
97
96
|
enabled?: undefined;
|
|
98
97
|
nextRun?: undefined;
|
|
99
98
|
created?: undefined;
|
|
@@ -101,6 +100,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
101
100
|
resourceId: string;
|
|
102
101
|
name: string;
|
|
103
102
|
updated?: undefined;
|
|
103
|
+
scope?: undefined;
|
|
104
104
|
triggerType?: undefined;
|
|
105
105
|
event?: undefined;
|
|
106
106
|
schedule?: undefined;
|