@agent-native/core 0.90.8 → 0.90.10
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/README.md +7 -28
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +16 -0
- package/corpus/core/docs/content/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +3 -3
- package/corpus/core/docs/content/tracking.mdx +3 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +15 -4
- package/corpus/core/src/cli/deploy-build.ts +50 -0
- package/corpus/core/src/cli/index.ts +9 -4
- package/corpus/core/src/client/analytics.ts +17 -3
- package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +3 -1
- package/corpus/core/src/client/blocks/library/wireframe.tsx +6 -1
- package/corpus/core/src/deploy/build.ts +64 -27
- package/corpus/core/src/file-upload/builder.ts +10 -23
- package/corpus/core/src/file-upload/types.ts +3 -3
- package/corpus/core/src/styles/blocks.css +7 -0
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +9 -4
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +21 -7
- package/corpus/templates/analytics/app/entry.client.tsx +6 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-07-07-analytics-now-recovers-from-stale-route-chunks-after-deploys.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-07-metric-dashboard-cards-now-show-warehouse-backed-numeric-val.md +6 -0
- package/corpus/templates/clips/actions/create-recording.ts +1 -1
- package/corpus/templates/clips/actions/finalize-recording.ts +2 -2
- package/corpus/templates/clips/actions/import-loom-recording.ts +1 -1
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +1 -1
- package/corpus/templates/clips/changelog/2026-07-07-clip-video-uploads-now-compress-in-the-background-while-keeping.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-desktop-settings-and-fn-dictation-are-more-reliable.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-desktop-settings-now-includes-a-manual-update-check-with-res.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +95 -8
- package/corpus/templates/clips/desktop/src/lib/updater.ts +60 -43
- package/corpus/templates/clips/desktop/src/styles.css +5 -0
- package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +93 -23
- package/corpus/templates/dispatch/changelog/2026-07-07-overview-is-now-just-ask-dispatch-and-a-list-of-apps.md +6 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +16 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/deploy-build.d.ts +12 -0
- package/dist/cli/deploy-build.d.ts.map +1 -0
- package/dist/cli/deploy-build.js +30 -0
- package/dist/cli/deploy-build.js.map +1 -0
- package/dist/cli/index.js +8 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +14 -3
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.d.ts +1 -0
- package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.js +2 -1
- package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe.js +6 -1
- package/dist/client/blocks/library/wireframe.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +6 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +54 -25
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/file-upload/builder.d.ts.map +1 -1
- package/dist/file-upload/builder.js +9 -19
- package/dist/file-upload/builder.js.map +1 -1
- package/dist/file-upload/types.d.ts +3 -3
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/styles/blocks.css +7 -0
- package/docs/content/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/ar-SA/tracking.mdx +3 -3
- package/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/de-DE/tracking.mdx +3 -3
- package/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/es-ES/tracking.mdx +3 -3
- package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/fr-FR/tracking.mdx +3 -3
- package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/hi-IN/tracking.mdx +3 -3
- package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/ja-JP/tracking.mdx +3 -3
- package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/ko-KR/tracking.mdx +3 -3
- package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/pt-BR/tracking.mdx +3 -3
- package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/zh-CN/tracking.mdx +3 -3
- package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
- package/docs/content/locales/zh-TW/tracking.mdx +3 -3
- package/docs/content/tracking.mdx +3 -3
- package/package.json +1 -1
|
@@ -17,12 +17,12 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
17
17
|
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
|
+
error?: undefined;
|
|
20
21
|
configured?: undefined;
|
|
21
22
|
connectPath?: undefined;
|
|
22
23
|
url: string;
|
|
23
24
|
id: string;
|
|
24
25
|
provider: string;
|
|
25
|
-
error?: undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export default _default;
|
|
28
28
|
//# sourceMappingURL=upload-image.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/file-upload/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAKnB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/file-upload/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAKnB,MAAM,YAAY,CAAC;AA8NpB;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,EAAE,kBAkMvC,CAAC"}
|
|
@@ -3,12 +3,6 @@ const DEFAULT_BUILDER_APP_HOST = "https://builder.io";
|
|
|
3
3
|
const LARGE_FILE_THRESHOLD_BYTES = 30 * 1024 * 1024;
|
|
4
4
|
const UPLOAD_TIMEOUT_MS = 120_000;
|
|
5
5
|
const SMALL_FILE_RETRY_DELAYS_MS = [600, 1800];
|
|
6
|
-
function enabledFlag(value) {
|
|
7
|
-
return /^(true|1|yes|on)$/i.test(String(value || "").trim());
|
|
8
|
-
}
|
|
9
|
-
function stableUrlOptInEnabled() {
|
|
10
|
-
return enabledFlag(process.env.CLIPS_STABLE_URL_OPTIN);
|
|
11
|
-
}
|
|
12
6
|
function builderUploadHost() {
|
|
13
7
|
return (process.env.BUILDER_APP_HOST ||
|
|
14
8
|
process.env.BUILDER_PUBLIC_APP_HOST ||
|
|
@@ -27,12 +21,9 @@ function fetchWithTimeout(url, init) {
|
|
|
27
21
|
const timer = setTimeout(() => controller.abort(), UPLOAD_TIMEOUT_MS);
|
|
28
22
|
return fetch(url, { ...init, signal: controller.signal }).finally(() => clearTimeout(timer));
|
|
29
23
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
url.searchParams.set("
|
|
33
|
-
if (stableUrlOptInEnabled()) {
|
|
34
|
-
url.searchParams.set("stableUrl", "true");
|
|
35
|
-
}
|
|
24
|
+
function setStableUrlQueryParam(url) {
|
|
25
|
+
// Stable URLs let Builder compress asynchronously without changing the media URL.
|
|
26
|
+
url.searchParams.set("stableUrl", "true");
|
|
36
27
|
}
|
|
37
28
|
function setRecordAssetQueryParam(url, recordAsset) {
|
|
38
29
|
if (recordAsset === false) {
|
|
@@ -66,7 +57,7 @@ async function uploadLargeFileViaSignedUrl(input, privateKey, bareMimeType, byte
|
|
|
66
57
|
// Step 3 — register the asset and get the CDN URL.
|
|
67
58
|
console.log(`[builder-upload] step 3: registering asset - ${assetId}, ${input.filename}`);
|
|
68
59
|
const { url, id } = await completeBuilderUpload(privateKey, assetId, input.filename, {
|
|
69
|
-
|
|
60
|
+
stableUrl: input.stableUrl,
|
|
70
61
|
recordAsset: input.recordAsset,
|
|
71
62
|
});
|
|
72
63
|
console.log(`[builder-upload] done [${assetId}]: ${url}`);
|
|
@@ -102,8 +93,8 @@ async function requestBuilderSignedUrl(privateKey, filename, mimeType, size, res
|
|
|
102
93
|
async function completeBuilderUpload(privateKey, assetId, filename, options) {
|
|
103
94
|
const host = builderUploadHost();
|
|
104
95
|
const url = new URL("/api/v1/upload/complete", host);
|
|
105
|
-
if (options?.
|
|
106
|
-
|
|
96
|
+
if (options?.stableUrl) {
|
|
97
|
+
setStableUrlQueryParam(url);
|
|
107
98
|
}
|
|
108
99
|
setRecordAssetQueryParam(url, options?.recordAsset);
|
|
109
100
|
const res = await fetchWithTimeout(url.toString(), {
|
|
@@ -190,8 +181,8 @@ export const builderFileUploadProvider = {
|
|
|
190
181
|
const url = new URL("/api/v1/upload", builderUploadHost());
|
|
191
182
|
if (filename)
|
|
192
183
|
url.searchParams.set("name", filename);
|
|
193
|
-
if (input.
|
|
194
|
-
|
|
184
|
+
if (input.stableUrl) {
|
|
185
|
+
setStableUrlQueryParam(url);
|
|
195
186
|
}
|
|
196
187
|
setRecordAssetQueryParam(url, input.recordAsset);
|
|
197
188
|
const response = await uploadSmallFile(url, {
|
|
@@ -297,8 +288,7 @@ export const builderFileUploadProvider = {
|
|
|
297
288
|
const assetId = session.meta.assetId;
|
|
298
289
|
console.log(`[builder-resumable] completing upload: assetId=${assetId}`);
|
|
299
290
|
const { url } = await completeBuilderUpload(privateKey, assetId, filename, {
|
|
300
|
-
|
|
301
|
-
session.meta.skipCompressionWait === true,
|
|
291
|
+
stableUrl: options?.stableUrl || session.meta.stableUrl === true,
|
|
302
292
|
recordAsset: options?.recordAsset ??
|
|
303
293
|
(session.meta.recordAsset === false ? false : undefined),
|
|
304
294
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/file-upload/builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n FileUploadProvider,\n FileUploadInput,\n FileUploadResult,\n ResumableUploadSession,\n ResumableChunkResult,\n} from \"./types.js\";\n\nconst DEFAULT_BUILDER_APP_HOST = \"https://builder.io\";\n\n/** Files larger than this are routed through the GCS signed-URL flow. */\nconst LARGE_FILE_THRESHOLD_BYTES = 30 * 1024 * 1024;\nconst UPLOAD_TIMEOUT_MS = 120_000;\nconst SMALL_FILE_RETRY_DELAYS_MS = [600, 1800];\n\nfunction enabledFlag(value: unknown): boolean {\n return /^(true|1|yes|on)$/i.test(String(value || \"\").trim());\n}\n\nfunction stableUrlOptInEnabled(): boolean {\n return enabledFlag(process.env.CLIPS_STABLE_URL_OPTIN);\n}\n\nfunction builderUploadHost(): string {\n return (\n process.env.BUILDER_APP_HOST ||\n process.env.BUILDER_PUBLIC_APP_HOST ||\n DEFAULT_BUILDER_APP_HOST\n );\n}\n\nfunction makeBody(bytes: Uint8Array, mimeType: string): BodyInit {\n return typeof Blob !== \"undefined\"\n ? new Blob([bytes as unknown as BlobPart], { type: mimeType })\n : (bytes as unknown as BodyInit);\n}\n\nfunction shouldUseSignedUrlUpload(\n bytes: Uint8Array,\n mimeType: string,\n): boolean {\n return (\n bytes.byteLength > LARGE_FILE_THRESHOLD_BYTES || /^video\\//i.test(mimeType)\n );\n}\n\nfunction fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), UPLOAD_TIMEOUT_MS);\n return fetch(url, { ...init, signal: controller.signal }).finally(() =>\n clearTimeout(timer),\n );\n}\n\nfunction setSkipCompressionQueryParams(url: URL): void {\n url.searchParams.set(\"skipCompressionWait\", \"true\");\n url.searchParams.set(\"skipCompression\", \"true\");\n if (stableUrlOptInEnabled()) {\n url.searchParams.set(\"stableUrl\", \"true\");\n }\n}\n\nfunction setRecordAssetQueryParam(\n url: URL,\n recordAsset: boolean | undefined,\n): void {\n if (recordAsset === false) {\n url.searchParams.set(\"record\", \"false\");\n }\n}\n\nasync function assertOk(res: Response, label: string): Promise<void> {\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`${label} (${res.status}): ${body || res.statusText}`);\n }\n}\n\nasync function uploadLargeFileViaSignedUrl(\n input: FileUploadInput,\n privateKey: string,\n bareMimeType: string,\n bytes: Uint8Array,\n): Promise<FileUploadResult> {\n const name = input.filename ?? \"upload\";\n const mb = (bytes.byteLength / (1024 * 1024)).toFixed(1);\n\n console.log(\n `[builder-upload] large-file path: ${name} ${mb}MB ${bareMimeType}`,\n );\n\n // Step 1 — request a signed URL.\n console.log(`[builder-upload] step 1: requesting signed URL`);\n const { uploadUrl, assetId, requiredHeaders } = await requestBuilderSignedUrl(\n privateKey,\n name,\n bareMimeType,\n bytes.byteLength,\n );\n console.log(`[builder-upload] step 1 ok: assetId=${assetId}`);\n\n // Step 2 — PUT bytes directly to GCS. Only requiredHeaders; no Authorization\n // (signed URL carries its own auth — extra signed headers break the signature).\n console.log(`[builder-upload] step 2 [${assetId}]: PUT ${mb}MB to GCS`);\n const step2Res = await fetchWithTimeout(uploadUrl, {\n method: \"PUT\",\n headers: requiredHeaders,\n body: makeBody(bytes, bareMimeType),\n });\n await assertOk(step2Res, \"GCS upload failed\");\n console.log(\n `[builder-upload] step 2 ok [${assetId}]: GCS ${step2Res.status} etag=${step2Res.headers.get(\"etag\") ?? \"none\"}`,\n );\n\n // Step 3 — register the asset and get the CDN URL.\n console.log(\n `[builder-upload] step 3: registering asset - ${assetId}, ${input.filename}`,\n );\n const { url, id } = await completeBuilderUpload(\n privateKey,\n assetId,\n input.filename,\n {\n skipCompressionWait: input.skipCompressionWait,\n recordAsset: input.recordAsset,\n },\n );\n console.log(`[builder-upload] done [${assetId}]: ${url}`);\n return { url, id, provider: \"builder\" };\n}\n\nasync function requestBuilderSignedUrl(\n privateKey: string,\n filename: string,\n mimeType: string,\n size: number,\n resumable = false,\n): Promise<{\n uploadUrl: string;\n assetId: string;\n requiredHeaders: Record<string, string>;\n}> {\n const host = builderUploadHost();\n const url = new URL(\"/api/v1/upload/signed-url\", host);\n const res = await fetchWithTimeout(url.toString(), {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n fileName: filename,\n contentType: mimeType,\n size,\n resumable,\n }),\n });\n await assertOk(res, \"Builder.io signed-URL request failed\");\n const json = (await res.json()) as {\n uploadUrl?: string;\n assetId?: string;\n requiredHeaders?: Record<string, string>;\n };\n if (!json.uploadUrl || !json.assetId || !json.requiredHeaders) {\n throw new Error(\n `Builder.io signed-URL response missing required fields: ${JSON.stringify(Object.keys(json))}`,\n );\n }\n return {\n uploadUrl: json.uploadUrl,\n assetId: json.assetId,\n requiredHeaders: json.requiredHeaders,\n };\n}\n\nasync function completeBuilderUpload(\n privateKey: string,\n assetId: string,\n filename: string | undefined,\n options?: { skipCompressionWait?: boolean; recordAsset?: boolean },\n): Promise<{ url: string; id?: string }> {\n const host = builderUploadHost();\n const url = new URL(\"/api/v1/upload/complete\", host);\n if (options?.skipCompressionWait) {\n setSkipCompressionQueryParams(url);\n }\n setRecordAssetQueryParam(url, options?.recordAsset);\n const res = await fetchWithTimeout(url.toString(), {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n assetId,\n name: filename,\n ...(options?.recordAsset === false ? { record: false } : {}),\n }),\n });\n await assertOk(res, \"Builder.io upload complete failed\");\n const json = (await res.json()) as { url?: string; id?: string };\n if (!json.url) throw new Error(\"Builder.io upload/complete returned no URL\");\n return { url: json.url, id: json.id };\n}\n\n// Retry transient 5xx once with backoff. Builder.io's upload service\n// occasionally returns a bodyless 500 (\"Internal Error\") on the first\n// attempt — usually GCS write hiccups that succeed on retry.\nasync function uploadSmallFile(url: URL, init: RequestInit): Promise<Response> {\n let response: Response | null = null;\n let lastErrorBody = \"\";\n\n for (\n let attempt = 0;\n attempt <= SMALL_FILE_RETRY_DELAYS_MS.length;\n attempt++\n ) {\n const retryDelay = SMALL_FILE_RETRY_DELAYS_MS[attempt]; // undefined on last attempt\n try {\n response = await fetchWithTimeout(url.toString(), init);\n } catch (err) {\n if (!retryDelay) throw err;\n await new Promise((r) => setTimeout(r, retryDelay));\n continue;\n }\n if (response.ok) return response;\n lastErrorBody = await response.text().catch(() => \"\");\n const isTransient = response.status >= 500 && response.status !== 501;\n if (!isTransient || !retryDelay) break;\n await new Promise((r) => setTimeout(r, retryDelay));\n }\n\n const status = response?.status ?? 0;\n const statusText = response?.statusText ?? \"no response\";\n throw new Error(\n `Builder.io upload failed (${status}): ${lastErrorBody || statusText}`,\n );\n}\n\n/**\n * Built-in Builder.io file upload provider.\n * Uses the same BUILDER_PRIVATE_KEY as the browser/background-agent flows,\n * so connecting Builder once (via the sidebar \"Connect Builder\" action)\n * automatically enables file uploads.\n *\n * Upload API: https://www.builder.io/c/docs/upload-api\n */\nexport const builderFileUploadProvider: FileUploadProvider = {\n id: \"builder\",\n name: \"Builder.io\",\n isConfigured: () => !!process.env.BUILDER_PRIVATE_KEY,\n upload: async (input: FileUploadInput) => {\n const { data, filename, mimeType } = input;\n const { resolveBuilderPrivateKey } =\n await import(\"../server/credential-provider.js\");\n const privateKey = await resolveBuilderPrivateKey();\n if (!privateKey) {\n throw new Error(\"BUILDER_PRIVATE_KEY is not set\");\n }\n\n // Strip any media-type parameters (e.g. `;codecs=avc1,opus` from\n // MediaRecorder blobs) — Builder's upload API parses the body as raw\n // binary only when Content-Type is a bare MIME type. A parameterized\n // Content-Type falls through to the multipart/base64 paths which look\n // for an `image` field, and returns \"No image specified\" when it\n // doesn't find one.\n const bareMimeType = (mimeType || \"application/octet-stream\")\n .split(\";\")[0]\n .trim();\n\n const bytes =\n data instanceof Uint8Array ? data : new Uint8Array(data as any);\n const mb = (bytes.byteLength / (1024 * 1024)).toFixed(1);\n\n if (shouldUseSignedUrlUpload(bytes, bareMimeType)) {\n return uploadLargeFileViaSignedUrl(\n input,\n privateKey,\n bareMimeType,\n bytes,\n );\n }\n\n console.log(\n `[builder-upload] small-file path: ${filename ?? \"upload\"} ${mb}MB ${bareMimeType}`,\n );\n\n const url = new URL(\"/api/v1/upload\", builderUploadHost());\n if (filename) url.searchParams.set(\"name\", filename);\n if (input.skipCompressionWait) {\n setSkipCompressionQueryParams(url);\n }\n setRecordAssetQueryParam(url, input.recordAsset);\n\n const response = await uploadSmallFile(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${privateKey}`,\n \"Content-Type\": bareMimeType,\n },\n body: makeBody(bytes, bareMimeType),\n });\n\n const json = (await response.json().catch(() => ({}))) as {\n url?: string;\n id?: string;\n };\n if (!json.url) throw new Error(\"Builder.io upload returned no URL\");\n\n console.log(`[builder-upload] done: ${json.url}`);\n return { url: json.url, id: json.id, provider: \"builder\" };\n },\n\n resumable: {\n async startSession(filename, mimeType, maxBytes) {\n const { resolveBuilderPrivateKey } =\n await import(\"../server/credential-provider.js\");\n const privateKey = await resolveBuilderPrivateKey();\n if (!privateKey) throw new Error(\"BUILDER_PRIVATE_KEY is not set\");\n\n console.log(\n `[builder-resumable] starting session: ${filename} ${mimeType} ${maxBytes} bytes`,\n );\n const { uploadUrl, assetId, requiredHeaders } =\n await requestBuilderSignedUrl(\n privateKey,\n filename,\n mimeType,\n maxBytes,\n true,\n );\n console.log(`[builder-resumable] session step 1 ok: assetId=${assetId}`);\n\n const initHeaders: Record<string, string> = {\n \"Content-Type\": mimeType,\n \"x-goog-resumable\": \"start\",\n };\n const contentLengthRange =\n requiredHeaders?.[\"x-goog-content-length-range\"];\n if (contentLengthRange)\n initHeaders[\"x-goog-content-length-range\"] = contentLengthRange;\n\n console.log(`[builder-resumable] session step 2: initiating GCS session`);\n const initRes = await fetchWithTimeout(uploadUrl, {\n method: \"POST\",\n headers: initHeaders,\n body: new Uint8Array(0),\n });\n if (!initRes.ok) {\n const body = await initRes.text().catch(() => \"\");\n throw new Error(\n `GCS resumable session initiation failed (${initRes.status}): ${body}`,\n );\n }\n const sessionUri = initRes.headers.get(\"location\");\n if (!sessionUri)\n throw new Error(\n \"GCS did not return a Location header for the resumable session\",\n );\n\n console.log(`[builder-resumable] session ready: assetId=${assetId}`);\n return {\n sessionId: sessionUri,\n meta: { assetId, filename, mimeType },\n } satisfies ResumableUploadSession;\n },\n\n async relayChunk(session, contentRange, bytes, options) {\n const sessionUri = session.sessionId;\n const MAX_ATTEMPTS = 4;\n const RETRYABLE = new Set([408, 429, 500, 502, 503, 504]);\n const delayMs = (attempt: number) =>\n Math.min(2000, 300 * 2 ** (attempt - 1));\n\n let lastError: unknown = null;\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const headers: Record<string, string> = {\n \"Content-Range\": contentRange,\n };\n if (options?.mimeType) headers[\"Content-Type\"] = options.mimeType;\n const res = await fetch(sessionUri, {\n method: \"PUT\",\n headers,\n body: bytes as unknown as BodyInit,\n });\n if (res.status === 308 || res.ok)\n return {\n ok: true,\n status: res.status,\n } satisfies ResumableChunkResult;\n if (RETRYABLE.has(res.status) && attempt < MAX_ATTEMPTS) {\n await res.text().catch(() => \"\");\n console.warn(\n `[builder-resumable] transient ${res.status} on attempt ${attempt}, retrying`,\n );\n await new Promise((r) => setTimeout(r, delayMs(attempt)));\n continue;\n }\n return {\n ok: false,\n status: res.status,\n } satisfies ResumableChunkResult;\n } catch (err) {\n lastError = err;\n if (attempt >= MAX_ATTEMPTS) break;\n console.warn(\n `[builder-resumable] network error on attempt ${attempt}:`,\n err instanceof Error ? err.message : String(err),\n );\n await new Promise((r) => setTimeout(r, delayMs(attempt)));\n }\n }\n throw lastError instanceof Error\n ? lastError\n : new Error(\"GCS PUT failed after retries\");\n },\n\n async completeSession(session, filename, options) {\n const { resolveBuilderPrivateKey } =\n await import(\"../server/credential-provider.js\");\n const privateKey = await resolveBuilderPrivateKey();\n if (!privateKey) throw new Error(\"BUILDER_PRIVATE_KEY is not set\");\n\n const assetId = session.meta.assetId as string;\n console.log(`[builder-resumable] completing upload: assetId=${assetId}`);\n const { url } = await completeBuilderUpload(\n privateKey,\n assetId,\n filename,\n {\n skipCompressionWait:\n options?.skipCompressionWait ||\n session.meta.skipCompressionWait === true,\n recordAsset:\n options?.recordAsset ??\n (session.meta.recordAsset === false ? false : undefined),\n },\n );\n console.log(`[builder-resumable] upload complete: ${url}`);\n return url;\n },\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/file-upload/builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n FileUploadProvider,\n FileUploadInput,\n FileUploadResult,\n ResumableUploadSession,\n ResumableChunkResult,\n} from \"./types.js\";\n\nconst DEFAULT_BUILDER_APP_HOST = \"https://builder.io\";\n\n/** Files larger than this are routed through the GCS signed-URL flow. */\nconst LARGE_FILE_THRESHOLD_BYTES = 30 * 1024 * 1024;\nconst UPLOAD_TIMEOUT_MS = 120_000;\nconst SMALL_FILE_RETRY_DELAYS_MS = [600, 1800];\n\nfunction builderUploadHost(): string {\n return (\n process.env.BUILDER_APP_HOST ||\n process.env.BUILDER_PUBLIC_APP_HOST ||\n DEFAULT_BUILDER_APP_HOST\n );\n}\n\nfunction makeBody(bytes: Uint8Array, mimeType: string): BodyInit {\n return typeof Blob !== \"undefined\"\n ? new Blob([bytes as unknown as BlobPart], { type: mimeType })\n : (bytes as unknown as BodyInit);\n}\n\nfunction shouldUseSignedUrlUpload(\n bytes: Uint8Array,\n mimeType: string,\n): boolean {\n return (\n bytes.byteLength > LARGE_FILE_THRESHOLD_BYTES || /^video\\//i.test(mimeType)\n );\n}\n\nfunction fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), UPLOAD_TIMEOUT_MS);\n return fetch(url, { ...init, signal: controller.signal }).finally(() =>\n clearTimeout(timer),\n );\n}\n\nfunction setStableUrlQueryParam(url: URL): void {\n // Stable URLs let Builder compress asynchronously without changing the media URL.\n url.searchParams.set(\"stableUrl\", \"true\");\n}\n\nfunction setRecordAssetQueryParam(\n url: URL,\n recordAsset: boolean | undefined,\n): void {\n if (recordAsset === false) {\n url.searchParams.set(\"record\", \"false\");\n }\n}\n\nasync function assertOk(res: Response, label: string): Promise<void> {\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`${label} (${res.status}): ${body || res.statusText}`);\n }\n}\n\nasync function uploadLargeFileViaSignedUrl(\n input: FileUploadInput,\n privateKey: string,\n bareMimeType: string,\n bytes: Uint8Array,\n): Promise<FileUploadResult> {\n const name = input.filename ?? \"upload\";\n const mb = (bytes.byteLength / (1024 * 1024)).toFixed(1);\n\n console.log(\n `[builder-upload] large-file path: ${name} ${mb}MB ${bareMimeType}`,\n );\n\n // Step 1 — request a signed URL.\n console.log(`[builder-upload] step 1: requesting signed URL`);\n const { uploadUrl, assetId, requiredHeaders } = await requestBuilderSignedUrl(\n privateKey,\n name,\n bareMimeType,\n bytes.byteLength,\n );\n console.log(`[builder-upload] step 1 ok: assetId=${assetId}`);\n\n // Step 2 — PUT bytes directly to GCS. Only requiredHeaders; no Authorization\n // (signed URL carries its own auth — extra signed headers break the signature).\n console.log(`[builder-upload] step 2 [${assetId}]: PUT ${mb}MB to GCS`);\n const step2Res = await fetchWithTimeout(uploadUrl, {\n method: \"PUT\",\n headers: requiredHeaders,\n body: makeBody(bytes, bareMimeType),\n });\n await assertOk(step2Res, \"GCS upload failed\");\n console.log(\n `[builder-upload] step 2 ok [${assetId}]: GCS ${step2Res.status} etag=${step2Res.headers.get(\"etag\") ?? \"none\"}`,\n );\n\n // Step 3 — register the asset and get the CDN URL.\n console.log(\n `[builder-upload] step 3: registering asset - ${assetId}, ${input.filename}`,\n );\n const { url, id } = await completeBuilderUpload(\n privateKey,\n assetId,\n input.filename,\n {\n stableUrl: input.stableUrl,\n recordAsset: input.recordAsset,\n },\n );\n console.log(`[builder-upload] done [${assetId}]: ${url}`);\n return { url, id, provider: \"builder\" };\n}\n\nasync function requestBuilderSignedUrl(\n privateKey: string,\n filename: string,\n mimeType: string,\n size: number,\n resumable = false,\n): Promise<{\n uploadUrl: string;\n assetId: string;\n requiredHeaders: Record<string, string>;\n}> {\n const host = builderUploadHost();\n const url = new URL(\"/api/v1/upload/signed-url\", host);\n const res = await fetchWithTimeout(url.toString(), {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n fileName: filename,\n contentType: mimeType,\n size,\n resumable,\n }),\n });\n await assertOk(res, \"Builder.io signed-URL request failed\");\n const json = (await res.json()) as {\n uploadUrl?: string;\n assetId?: string;\n requiredHeaders?: Record<string, string>;\n };\n if (!json.uploadUrl || !json.assetId || !json.requiredHeaders) {\n throw new Error(\n `Builder.io signed-URL response missing required fields: ${JSON.stringify(Object.keys(json))}`,\n );\n }\n return {\n uploadUrl: json.uploadUrl,\n assetId: json.assetId,\n requiredHeaders: json.requiredHeaders,\n };\n}\n\nasync function completeBuilderUpload(\n privateKey: string,\n assetId: string,\n filename: string | undefined,\n options?: { stableUrl?: boolean; recordAsset?: boolean },\n): Promise<{ url: string; id?: string }> {\n const host = builderUploadHost();\n const url = new URL(\"/api/v1/upload/complete\", host);\n if (options?.stableUrl) {\n setStableUrlQueryParam(url);\n }\n setRecordAssetQueryParam(url, options?.recordAsset);\n const res = await fetchWithTimeout(url.toString(), {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${privateKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n assetId,\n name: filename,\n ...(options?.recordAsset === false ? { record: false } : {}),\n }),\n });\n await assertOk(res, \"Builder.io upload complete failed\");\n const json = (await res.json()) as { url?: string; id?: string };\n if (!json.url) throw new Error(\"Builder.io upload/complete returned no URL\");\n return { url: json.url, id: json.id };\n}\n\n// Retry transient 5xx once with backoff. Builder.io's upload service\n// occasionally returns a bodyless 500 (\"Internal Error\") on the first\n// attempt — usually GCS write hiccups that succeed on retry.\nasync function uploadSmallFile(url: URL, init: RequestInit): Promise<Response> {\n let response: Response | null = null;\n let lastErrorBody = \"\";\n\n for (\n let attempt = 0;\n attempt <= SMALL_FILE_RETRY_DELAYS_MS.length;\n attempt++\n ) {\n const retryDelay = SMALL_FILE_RETRY_DELAYS_MS[attempt]; // undefined on last attempt\n try {\n response = await fetchWithTimeout(url.toString(), init);\n } catch (err) {\n if (!retryDelay) throw err;\n await new Promise((r) => setTimeout(r, retryDelay));\n continue;\n }\n if (response.ok) return response;\n lastErrorBody = await response.text().catch(() => \"\");\n const isTransient = response.status >= 500 && response.status !== 501;\n if (!isTransient || !retryDelay) break;\n await new Promise((r) => setTimeout(r, retryDelay));\n }\n\n const status = response?.status ?? 0;\n const statusText = response?.statusText ?? \"no response\";\n throw new Error(\n `Builder.io upload failed (${status}): ${lastErrorBody || statusText}`,\n );\n}\n\n/**\n * Built-in Builder.io file upload provider.\n * Uses the same BUILDER_PRIVATE_KEY as the browser/background-agent flows,\n * so connecting Builder once (via the sidebar \"Connect Builder\" action)\n * automatically enables file uploads.\n *\n * Upload API: https://www.builder.io/c/docs/upload-api\n */\nexport const builderFileUploadProvider: FileUploadProvider = {\n id: \"builder\",\n name: \"Builder.io\",\n isConfigured: () => !!process.env.BUILDER_PRIVATE_KEY,\n upload: async (input: FileUploadInput) => {\n const { data, filename, mimeType } = input;\n const { resolveBuilderPrivateKey } =\n await import(\"../server/credential-provider.js\");\n const privateKey = await resolveBuilderPrivateKey();\n if (!privateKey) {\n throw new Error(\"BUILDER_PRIVATE_KEY is not set\");\n }\n\n // Strip any media-type parameters (e.g. `;codecs=avc1,opus` from\n // MediaRecorder blobs) — Builder's upload API parses the body as raw\n // binary only when Content-Type is a bare MIME type. A parameterized\n // Content-Type falls through to the multipart/base64 paths which look\n // for an `image` field, and returns \"No image specified\" when it\n // doesn't find one.\n const bareMimeType = (mimeType || \"application/octet-stream\")\n .split(\";\")[0]\n .trim();\n\n const bytes =\n data instanceof Uint8Array ? data : new Uint8Array(data as any);\n const mb = (bytes.byteLength / (1024 * 1024)).toFixed(1);\n\n if (shouldUseSignedUrlUpload(bytes, bareMimeType)) {\n return uploadLargeFileViaSignedUrl(\n input,\n privateKey,\n bareMimeType,\n bytes,\n );\n }\n\n console.log(\n `[builder-upload] small-file path: ${filename ?? \"upload\"} ${mb}MB ${bareMimeType}`,\n );\n\n const url = new URL(\"/api/v1/upload\", builderUploadHost());\n if (filename) url.searchParams.set(\"name\", filename);\n if (input.stableUrl) {\n setStableUrlQueryParam(url);\n }\n setRecordAssetQueryParam(url, input.recordAsset);\n\n const response = await uploadSmallFile(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${privateKey}`,\n \"Content-Type\": bareMimeType,\n },\n body: makeBody(bytes, bareMimeType),\n });\n\n const json = (await response.json().catch(() => ({}))) as {\n url?: string;\n id?: string;\n };\n if (!json.url) throw new Error(\"Builder.io upload returned no URL\");\n\n console.log(`[builder-upload] done: ${json.url}`);\n return { url: json.url, id: json.id, provider: \"builder\" };\n },\n\n resumable: {\n async startSession(filename, mimeType, maxBytes) {\n const { resolveBuilderPrivateKey } =\n await import(\"../server/credential-provider.js\");\n const privateKey = await resolveBuilderPrivateKey();\n if (!privateKey) throw new Error(\"BUILDER_PRIVATE_KEY is not set\");\n\n console.log(\n `[builder-resumable] starting session: ${filename} ${mimeType} ${maxBytes} bytes`,\n );\n const { uploadUrl, assetId, requiredHeaders } =\n await requestBuilderSignedUrl(\n privateKey,\n filename,\n mimeType,\n maxBytes,\n true,\n );\n console.log(`[builder-resumable] session step 1 ok: assetId=${assetId}`);\n\n const initHeaders: Record<string, string> = {\n \"Content-Type\": mimeType,\n \"x-goog-resumable\": \"start\",\n };\n const contentLengthRange =\n requiredHeaders?.[\"x-goog-content-length-range\"];\n if (contentLengthRange)\n initHeaders[\"x-goog-content-length-range\"] = contentLengthRange;\n\n console.log(`[builder-resumable] session step 2: initiating GCS session`);\n const initRes = await fetchWithTimeout(uploadUrl, {\n method: \"POST\",\n headers: initHeaders,\n body: new Uint8Array(0),\n });\n if (!initRes.ok) {\n const body = await initRes.text().catch(() => \"\");\n throw new Error(\n `GCS resumable session initiation failed (${initRes.status}): ${body}`,\n );\n }\n const sessionUri = initRes.headers.get(\"location\");\n if (!sessionUri)\n throw new Error(\n \"GCS did not return a Location header for the resumable session\",\n );\n\n console.log(`[builder-resumable] session ready: assetId=${assetId}`);\n return {\n sessionId: sessionUri,\n meta: { assetId, filename, mimeType },\n } satisfies ResumableUploadSession;\n },\n\n async relayChunk(session, contentRange, bytes, options) {\n const sessionUri = session.sessionId;\n const MAX_ATTEMPTS = 4;\n const RETRYABLE = new Set([408, 429, 500, 502, 503, 504]);\n const delayMs = (attempt: number) =>\n Math.min(2000, 300 * 2 ** (attempt - 1));\n\n let lastError: unknown = null;\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const headers: Record<string, string> = {\n \"Content-Range\": contentRange,\n };\n if (options?.mimeType) headers[\"Content-Type\"] = options.mimeType;\n const res = await fetch(sessionUri, {\n method: \"PUT\",\n headers,\n body: bytes as unknown as BodyInit,\n });\n if (res.status === 308 || res.ok)\n return {\n ok: true,\n status: res.status,\n } satisfies ResumableChunkResult;\n if (RETRYABLE.has(res.status) && attempt < MAX_ATTEMPTS) {\n await res.text().catch(() => \"\");\n console.warn(\n `[builder-resumable] transient ${res.status} on attempt ${attempt}, retrying`,\n );\n await new Promise((r) => setTimeout(r, delayMs(attempt)));\n continue;\n }\n return {\n ok: false,\n status: res.status,\n } satisfies ResumableChunkResult;\n } catch (err) {\n lastError = err;\n if (attempt >= MAX_ATTEMPTS) break;\n console.warn(\n `[builder-resumable] network error on attempt ${attempt}:`,\n err instanceof Error ? err.message : String(err),\n );\n await new Promise((r) => setTimeout(r, delayMs(attempt)));\n }\n }\n throw lastError instanceof Error\n ? lastError\n : new Error(\"GCS PUT failed after retries\");\n },\n\n async completeSession(session, filename, options) {\n const { resolveBuilderPrivateKey } =\n await import(\"../server/credential-provider.js\");\n const privateKey = await resolveBuilderPrivateKey();\n if (!privateKey) throw new Error(\"BUILDER_PRIVATE_KEY is not set\");\n\n const assetId = session.meta.assetId as string;\n console.log(`[builder-resumable] completing upload: assetId=${assetId}`);\n const { url } = await completeBuilderUpload(\n privateKey,\n assetId,\n filename,\n {\n stableUrl: options?.stableUrl || session.meta.stableUrl === true,\n recordAsset:\n options?.recordAsset ??\n (session.meta.recordAsset === false ? false : undefined),\n },\n );\n console.log(`[builder-resumable] upload complete: ${url}`);\n return url;\n },\n },\n};\n"]}
|
|
@@ -15,8 +15,8 @@ export interface FileUploadInput {
|
|
|
15
15
|
mimeType?: string;
|
|
16
16
|
/** Optional owner email for per-user scoping in fallback storage. */
|
|
17
17
|
ownerEmail?: string;
|
|
18
|
-
/** Builder.io upload hint: return
|
|
19
|
-
|
|
18
|
+
/** Builder.io upload hint: return one stable URL while compression finishes asynchronously. */
|
|
19
|
+
stableUrl?: boolean;
|
|
20
20
|
/** Builder.io upload hint: set false for internal artifacts that should not appear in the asset library. */
|
|
21
21
|
recordAsset?: boolean;
|
|
22
22
|
}
|
|
@@ -67,7 +67,7 @@ export interface FileUploadProvider {
|
|
|
67
67
|
mimeType?: string;
|
|
68
68
|
}): Promise<ResumableChunkResult>;
|
|
69
69
|
completeSession(session: ResumableUploadSession, filename: string, options?: {
|
|
70
|
-
|
|
70
|
+
stableUrl?: boolean;
|
|
71
71
|
recordAsset?: boolean;
|
|
72
72
|
}): Promise<string>;
|
|
73
73
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/file-upload/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,eAAe;IAC9B,qBAAqB;IACrB,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IAC1B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/file-upload/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,eAAe;IAC9B,qBAAqB;IACrB,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IAC1B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4GAA4G;IAC5G,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;qFAEqF;AACrF,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf;uEACmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,YAAY,EAAE,MAAM,OAAO,CAAC;IAC5B;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,wDAAwD;IACxD,MAAM,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9D;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,YAAY,CACV,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,sBAAsB,CAAC,CAAC;QACnC,UAAU,CACR,OAAO,EAAE,sBAAsB,EAC/B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAAC;QACjC,eAAe,CACb,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;YAAE,SAAS,CAAC,EAAE,OAAO,CAAC;YAAC,WAAW,CAAC,EAAE,OAAO,CAAA;SAAE,GACvD,OAAO,CAAC,MAAM,CAAC,CAAC;KACpB,CAAC;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/file-upload/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG","sourcesContent":["/**\n * File upload framework primitive.\n *\n * Templates call `uploadFile()` to upload a file and get back a URL.\n * The framework dispatches to whichever provider is registered (Builder.io\n * built-in, or a user-supplied one). If no provider is active, it falls back\n * to the SQL resources store — fine for dev, not recommended for production.\n */\n\nexport interface FileUploadInput {\n /** File contents. */\n data: Uint8Array | Buffer;\n /** Original filename, used for extension/display. */\n filename?: string;\n /** MIME type, e.g. \"image/png\". */\n mimeType?: string;\n /** Optional owner email for per-user scoping in fallback storage. */\n ownerEmail?: string;\n /** Builder.io upload hint: return
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/file-upload/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG","sourcesContent":["/**\n * File upload framework primitive.\n *\n * Templates call `uploadFile()` to upload a file and get back a URL.\n * The framework dispatches to whichever provider is registered (Builder.io\n * built-in, or a user-supplied one). If no provider is active, it falls back\n * to the SQL resources store — fine for dev, not recommended for production.\n */\n\nexport interface FileUploadInput {\n /** File contents. */\n data: Uint8Array | Buffer;\n /** Original filename, used for extension/display. */\n filename?: string;\n /** MIME type, e.g. \"image/png\". */\n mimeType?: string;\n /** Optional owner email for per-user scoping in fallback storage. */\n ownerEmail?: string;\n /** Builder.io upload hint: return one stable URL while compression finishes asynchronously. */\n stableUrl?: boolean;\n /** Builder.io upload hint: set false for internal artifacts that should not appear in the asset library. */\n recordAsset?: boolean;\n}\n\nexport interface FileUploadResult {\n /** Public URL where the file can be fetched. */\n url: string;\n /** Optional provider-specific id (e.g. resource id, Builder asset id). */\n id?: string;\n /** The provider that handled the upload. */\n provider: string;\n}\n\n/** Opaque session handle returned by {@link FileUploadProvider.resumable.startSession}.\n * `sessionId` is provider-specific (GCS Location URI, S3 UploadId, etc.).\n * `meta` holds any provider state needed for subsequent relay and complete calls. */\nexport interface ResumableUploadSession {\n sessionId: string;\n meta: Record<string, unknown>;\n}\n\nexport interface ResumableChunkResult {\n ok: boolean;\n status: number;\n /** Providers that need per-chunk state (e.g. S3 ETags) return updated meta\n * here; the chunk route merges it back into the stored session. */\n updatedMeta?: Record<string, unknown>;\n}\n\nexport interface FileUploadProvider {\n /** Unique id, e.g. \"builder\", \"s3\". */\n id: string;\n /** Human-readable name. */\n name: string;\n /** Returns true if this provider is configured from synchronous runtime state. */\n isConfigured: () => boolean;\n /**\n * Returns true if this provider is configured for the active request.\n * Use for DB-backed user/org/workspace secrets that require request context.\n */\n isConfiguredForRequest?: () => Promise<boolean>;\n /** Upload a file and return a URL. Throw on failure. */\n upload: (input: FileUploadInput) => Promise<FileUploadResult>;\n /**\n * Optional resumable/streaming upload capability.\n * When present, create-recording will initialise a session and stream chunks\n * during recording instead of assembling the full blob after stop().\n */\n resumable?: {\n startSession(\n filename: string,\n mimeType: string,\n maxBytes: number,\n ): Promise<ResumableUploadSession>;\n relayChunk(\n session: ResumableUploadSession,\n contentRange: string,\n bytes: Uint8Array,\n options?: { mimeType?: string },\n ): Promise<ResumableChunkResult>;\n completeSession(\n session: ResumableUploadSession,\n filename: string,\n options?: { stableUrl?: boolean; recordAsset?: boolean },\n ): Promise<string>;\n };\n}\n"]}
|
|
@@ -49,11 +49,11 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
49
49
|
}>;
|
|
50
50
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
51
51
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
52
|
-
ok?: undefined;
|
|
53
52
|
error: string;
|
|
53
|
+
ok?: undefined;
|
|
54
54
|
} | {
|
|
55
|
-
error?: undefined;
|
|
56
55
|
ok: boolean;
|
|
56
|
+
error?: undefined;
|
|
57
57
|
}>;
|
|
58
58
|
/** POST /_agent-native/resources/upload — upload a file as a resource */
|
|
59
59
|
export declare function handleUploadResource(event: any): Promise<import("./store.js").Resource | {
|
|
@@ -73,9 +73,9 @@ export declare function handleUploadResource(event: any): Promise<import("./stor
|
|
|
73
73
|
runId: string | null;
|
|
74
74
|
expiresAt: number | null;
|
|
75
75
|
metadata: string | null;
|
|
76
|
-
error?: undefined;
|
|
77
76
|
url: string;
|
|
78
77
|
provider: string;
|
|
78
|
+
error?: undefined;
|
|
79
79
|
}>;
|
|
80
80
|
export {};
|
|
81
81
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -27,11 +27,11 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
27
27
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
28
28
|
error: any;
|
|
29
29
|
} | {
|
|
30
|
-
error?: undefined;
|
|
31
30
|
ok: boolean;
|
|
32
31
|
key: string;
|
|
33
32
|
baseUrlKey?: string;
|
|
34
33
|
scope: AgentEngineApiKeyScope;
|
|
34
|
+
error?: undefined;
|
|
35
35
|
}>>;
|
|
36
36
|
export {};
|
|
37
37
|
//# sourceMappingURL=agent-engine-api-key-route.d.ts.map
|
package/dist/styles/blocks.css
CHANGED
|
@@ -1007,6 +1007,13 @@
|
|
|
1007
1007
|
min-height: 100%;
|
|
1008
1008
|
}
|
|
1009
1009
|
|
|
1010
|
+
.plan-html-frame[data-frame="hide"]:not([data-render-mode="design"])
|
|
1011
|
+
> .plan-html-frame-content
|
|
1012
|
+
> :first-child {
|
|
1013
|
+
margin: 0 !important;
|
|
1014
|
+
padding: 0 !important;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1010
1017
|
.plan-html-frame[data-prototype-live="true"] {
|
|
1011
1018
|
overflow: auto;
|
|
1012
1019
|
}
|
|
@@ -21,7 +21,7 @@ being rebuilt in slightly different ways every time.
|
|
|
21
21
|
<Screen
|
|
22
22
|
surface="desktop"
|
|
23
23
|
html={
|
|
24
|
-
"<div style='min-height:560px;box-sizing:border-box;
|
|
24
|
+
"<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
|
|
25
25
|
}
|
|
26
26
|
/>
|
|
27
27
|
</WireframeBlock>
|
|
@@ -23,7 +23,7 @@ being rebuilt in slightly different ways every time.
|
|
|
23
23
|
<Screen
|
|
24
24
|
surface="desktop"
|
|
25
25
|
html={
|
|
26
|
-
"<div style='min-height:560px;box-sizing:border-box;
|
|
26
|
+
"<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
|
|
27
27
|
}
|
|
28
28
|
/>
|
|
29
29
|
</WireframeBlock>
|
|
@@ -200,7 +200,7 @@ configureTracking({
|
|
|
200
200
|
endpoint: "https://analytics.example.com/api/analytics/track",
|
|
201
201
|
sessionReplay: {
|
|
202
202
|
enabled: true,
|
|
203
|
-
sampleRate:
|
|
203
|
+
sampleRate: 1,
|
|
204
204
|
},
|
|
205
205
|
getDefaultProps: (_event, props) => ({
|
|
206
206
|
...props,
|
|
@@ -218,14 +218,14 @@ configureTracking({
|
|
|
218
218
|
VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
|
|
219
219
|
VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
|
|
220
220
|
VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
|
|
221
|
-
VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=
|
|
221
|
+
VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=1
|
|
222
222
|
```
|
|
223
223
|
|
|
224
224
|
يقوم مساعد المتصفح أيضًا بإجراء قراءة غير محظِّرة وبأفضل جهد ممكن لجلسة مصادقة Agent Native الحالية. إعادة التشغيل مخصصة لتسجيل الدخول فقط بشكل افتراضي: عندما يكون `sessionReplay` مفعّلاً، لا يبدأ التسجيل ما لم تُحلّ الجلسة إلى عنوان بريد إلكتروني لمستخدم. تتضمن إعادة تشغيل الجلسات المسجَّلة `userId`/`userEmail` المدعومين بالبريد الإلكتروني بالإضافة إلى `orgId`.
|
|
225
225
|
|
|
226
226
|
اضبط `sessionReplay.requireSignedInUser: false` أو `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false` فقط من أجل نشر إعادة تشغيل مجهولة الهوية مقصود. عندما يتم تعطيل تحكم المصادقة، تظل التسجيلات المجهولة قابلة للاستعلام حسب الزائر المجهول، والجلسة، والتطبيق/القالب، واسم المضيف، والمسار.
|
|
227
227
|
|
|
228
|
-
يتم أخذ عينات من إعادة تشغيل الجلسة بشكل حتمي لكل جلسة متصفح. يقوم `sampleRate` بقيمة `
|
|
228
|
+
يتم أخذ عينات من إعادة تشغيل الجلسة بشكل حتمي لكل جلسة متصفح. يقوم `sampleRate` بقيمة `1` بتسجيل جميع الجلسات المؤهلة؛ استخدم قيمًا أقل، مثل `0.1`، عندما تكون المجموعة المؤهلة واسعة عن قصد.
|
|
229
229
|
|
|
230
230
|
إعدادات الخصوصية الافتراضية متحفظة عن قصد لكنها لا تزال مفيدة لإعادة التشغيل:
|
|
231
231
|
|
|
@@ -23,7 +23,7 @@ being rebuilt in slightly different ways every time.
|
|
|
23
23
|
<Screen
|
|
24
24
|
surface="desktop"
|
|
25
25
|
html={
|
|
26
|
-
"<div style='min-height:560px;box-sizing:border-box;
|
|
26
|
+
"<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
|
|
27
27
|
}
|
|
28
28
|
/>
|
|
29
29
|
</WireframeBlock>
|
|
@@ -200,7 +200,7 @@ configureTracking({
|
|
|
200
200
|
endpoint: "https://analytics.example.com/api/analytics/track",
|
|
201
201
|
sessionReplay: {
|
|
202
202
|
enabled: true,
|
|
203
|
-
sampleRate:
|
|
203
|
+
sampleRate: 1,
|
|
204
204
|
},
|
|
205
205
|
getDefaultProps: (_event, props) => ({
|
|
206
206
|
...props,
|
|
@@ -218,14 +218,14 @@ Agent-Native-Template-Roots rufen `configureTracking()` bereits auf. Gehostete T
|
|
|
218
218
|
VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
|
|
219
219
|
VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
|
|
220
220
|
VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
|
|
221
|
-
VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=
|
|
221
|
+
VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=1
|
|
222
222
|
```
|
|
223
223
|
|
|
224
224
|
Der Browser-Helfer führt außerdem einen nach bestem Bemühen erfolgenden, nicht blockierenden Lesevorgang der aktuellen Agent-Native-Auth-Sitzung durch. Replay ist standardmäßig nur für angemeldete Benutzer verfügbar: Wenn `sessionReplay` aktiviert ist, startet die Aufzeichnung nur, wenn die Sitzung zu einer Benutzer-E-Mail-Adresse aufgelöst werden kann. Replays angemeldeter Benutzer enthalten E-Mail-basierte `userId`/`userEmail` sowie `orgId`.
|
|
225
225
|
|
|
226
226
|
Setzen Sie `sessionReplay.requireSignedInUser: false` oder `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false` nur für ein absichtlich anonymes Replay-Deployment. Wenn die Auth-Prüfung deaktiviert ist, bleiben anonyme Aufzeichnungen nach anonymem Besucher, Sitzung, App/Template, Hostname und Pfad abfragbar.
|
|
227
227
|
|
|
228
|
-
Session Replay wird deterministisch pro Browser-Sitzung gesampelt. Eine `sampleRate` von `
|
|
228
|
+
Session Replay wird deterministisch pro Browser-Sitzung gesampelt. Eine `sampleRate` von `1` zeichnet alle infrage kommenden Sitzungen auf; verwenden Sie niedrigere Werte wie `0.1`, wenn die infrage kommende Population absichtlich breit ist.
|
|
229
229
|
|
|
230
230
|
Die Datenschutz-Standardeinstellungen sind bewusst konservativ, aber für die Wiedergabe weiterhin nützlich:
|
|
231
231
|
|
|
@@ -23,7 +23,7 @@ being rebuilt in slightly different ways every time.
|
|
|
23
23
|
<Screen
|
|
24
24
|
surface="desktop"
|
|
25
25
|
html={
|
|
26
|
-
"<div style='min-height:560px;box-sizing:border-box;
|
|
26
|
+
"<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
|
|
27
27
|
}
|
|
28
28
|
/>
|
|
29
29
|
</WireframeBlock>
|
|
@@ -200,7 +200,7 @@ configureTracking({
|
|
|
200
200
|
endpoint: "https://analytics.example.com/api/analytics/track",
|
|
201
201
|
sessionReplay: {
|
|
202
202
|
enabled: true,
|
|
203
|
-
sampleRate:
|
|
203
|
+
sampleRate: 1,
|
|
204
204
|
},
|
|
205
205
|
getDefaultProps: (_event, props) => ({
|
|
206
206
|
...props,
|
|
@@ -218,14 +218,14 @@ Las raíces de las plantillas de Agent Native ya llaman a `configureTracking()`.
|
|
|
218
218
|
VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
|
|
219
219
|
VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
|
|
220
220
|
VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
|
|
221
|
-
VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=
|
|
221
|
+
VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=1
|
|
222
222
|
```
|
|
223
223
|
|
|
224
224
|
El ayudante del navegador también realiza una lectura sin bloqueo y de mejor esfuerzo de la sesión de autenticación actual de Agent Native. La repetición es solo para usuarios con sesión iniciada de forma predeterminada: cuando `sessionReplay` está habilitado, la grabación no se inicia a menos que la sesión se resuelva en una dirección de correo electrónico de usuario. Las repeticiones de usuarios con sesión iniciada incluyen `userId`/`userEmail` respaldados por correo electrónico más `orgId`.
|
|
225
225
|
|
|
226
226
|
Configure `sessionReplay.requireSignedInUser: false` o `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false` solo para una implementación de repetición anónima intencional. Cuando la restricción de autenticación está deshabilitada, las grabaciones anónimas siguen siendo consultables por visitante anónimo, sesión, aplicación/plantilla, nombre de host y ruta.
|
|
227
227
|
|
|
228
|
-
La repetición de sesión se muestrea de forma determinista por sesión de navegador. Un `sampleRate` de `
|
|
228
|
+
La repetición de sesión se muestrea de forma determinista por sesión de navegador. Un `sampleRate` de `1` graba todas las sesiones elegibles; use valores más bajos, como `0.1`, cuando la población elegible sea intencionalmente amplia.
|
|
229
229
|
|
|
230
230
|
Los valores predeterminados de privacidad son intencionalmente conservadores pero siguen siendo útiles para la reproducción:
|
|
231
231
|
|
|
@@ -23,7 +23,7 @@ being rebuilt in slightly different ways every time.
|
|
|
23
23
|
<Screen
|
|
24
24
|
surface="desktop"
|
|
25
25
|
html={
|
|
26
|
-
"<div style='min-height:560px;box-sizing:border-box;
|
|
26
|
+
"<div style='min-height:560px;box-sizing:border-box;display:grid;grid-template-columns:200px 1fr 280px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:8px;padding:14px'><div style='display:flex;align-items:center;gap:8px'><div style='width:26px;height:26px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='search'></span> Home</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='edit'></span> Documents</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='user'></span> Team</div><div style='display:flex;align-items:center;gap:8px;padding:7px 9px'><span data-icon='settings'></span> Settings</div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px;padding-top:10px;border-top:1.4px solid var(--wf-line)'><div style='width:24px;height:24px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><small style='flex:1'>Steve</small><span data-icon='dots'></span></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><div style='flex:1'></div><div style='display:flex'><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent-soft);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div><div style='width:26px;height:26px;border-radius:999px;background:var(--wf-accent);border:2px solid var(--wf-card);margin-left:-8px;flex:none'></div></div><button class='primary'><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:45%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:55%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:95%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;gap:10px'><div class='wf-box' style='flex:1'><small class='wf-muted'>ARR</small><br/><strong>$4.2M</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Win rate</small><br/><strong>28%</strong></div><div class='wf-box' style='flex:1'><small class='wf-muted'>Pipeline</small><br/><strong>3.2x</strong></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Agent</strong><div class='wf-box'>Summarize Q3 versus Q2 and flag risks.</div><div class='wf-box' style='background:var(--wf-accent-soft)'>Revenue up 12%. Two pipeline risks flagged.</div><div style='flex:1'></div><div class='wf-card' style='padding:10px;display:flex;flex-direction:column;gap:8px'><span class='wf-muted'>Ask about this dashboard...</span><div style='display:flex;align-items:center;gap:6px'><span class='wf-pill'>Q3 Forecast</span><span class='wf-pill'>GPT-5</span><div style='flex:1'></div><button class='primary'><span data-icon='send'></span></button></div></div></aside></div>"
|
|
27
27
|
}
|
|
28
28
|
/>
|
|
29
29
|
</WireframeBlock>
|