@agent-native/core 0.84.59 → 0.84.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/AssistantChat.tsx +49 -14
- package/corpus/core/src/db/client.ts +13 -1
- package/corpus/core/src/server/ssr-handler.ts +14 -16
- package/corpus/core/src/sharing/access.ts +79 -5
- package/corpus/templates/clips/app/i18n/ar-SA.ts +7 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +8 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +7 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +7 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +7 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +6 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +8 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +7 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +7 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +5 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +5 -0
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +174 -28
- package/corpus/templates/clips/app/routes/record.tsx +74 -6
- package/corpus/templates/plan/changelog/2026-07-02-fixed-hosted-visual-plans-getting-stuck-loading-when-a-datab.md +6 -0
- package/corpus/templates/plan/server/plugins/db.ts +25 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +42 -15
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +11 -1
- package/dist/db/client.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +14 -16
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/sharing/access.d.ts.map +1 -1
- package/dist/sharing/access.js +54 -5
- package/dist/sharing/access.js.map +1 -1
- package/package.json +1 -1
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.84.61
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3a66817: Recover share access lookups when a hosted database is missing newer additive resource columns, and prefer Netlify unpooled database URLs for migrations.
|
|
8
|
+
|
|
9
|
+
## 0.84.60
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 4b6ca6c: Loosen the document script CSP allowances so hosted Google Tag Manager scripts and framework inline bootstrap scripts do not trigger CSP violations.
|
|
14
|
+
|
|
3
15
|
## 0.84.59
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.84.
|
|
3
|
+
"version": "0.84.61",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -256,9 +256,21 @@ type ActiveRunLookup = {
|
|
|
256
256
|
status?: string;
|
|
257
257
|
heartbeatAt?: number | null;
|
|
258
258
|
lastProgressAt?: number | null;
|
|
259
|
+
dispatchMode?: string | null;
|
|
260
|
+
terminalReason?: string | null;
|
|
259
261
|
serverNow?: number;
|
|
260
262
|
};
|
|
261
263
|
|
|
264
|
+
function isReplayableTerminalRun(runInfo: ActiveRunLookup): boolean {
|
|
265
|
+
const dispatchMode =
|
|
266
|
+
typeof runInfo.dispatchMode === "string" ? runInfo.dispatchMode : "";
|
|
267
|
+
return (
|
|
268
|
+
runInfo.status !== "running" &&
|
|
269
|
+
dispatchMode.startsWith("background") &&
|
|
270
|
+
runInfo.terminalReason === "run_timeout"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
262
274
|
function activeRunLooksStale(runInfo: ActiveRunLookup): boolean {
|
|
263
275
|
const lastProgressAt =
|
|
264
276
|
typeof runInfo.lastProgressAt === "number" ? runInfo.lastProgressAt : null;
|
|
@@ -1846,7 +1858,11 @@ const AssistantChatInner = forwardRef<
|
|
|
1846
1858
|
|
|
1847
1859
|
const startReconnectToRun = useCallback(
|
|
1848
1860
|
(runInfo: ActiveRunLookup): boolean => {
|
|
1849
|
-
if (
|
|
1861
|
+
if (
|
|
1862
|
+
!threadId ||
|
|
1863
|
+
!runInfo.runId ||
|
|
1864
|
+
(runInfo.status !== "running" && !isReplayableTerminalRun(runInfo))
|
|
1865
|
+
) {
|
|
1850
1866
|
return false;
|
|
1851
1867
|
}
|
|
1852
1868
|
const runId = String(runInfo.runId);
|
|
@@ -1876,6 +1892,8 @@ const AssistantChatInner = forwardRef<
|
|
|
1876
1892
|
|
|
1877
1893
|
const abortCtrl = new AbortController();
|
|
1878
1894
|
reconnectAbortRef.current = abortCtrl;
|
|
1895
|
+
let reconnectTerminalReason: AgentAutoContinueSignal["reason"] | null =
|
|
1896
|
+
null;
|
|
1879
1897
|
|
|
1880
1898
|
const watchdog = setInterval(async () => {
|
|
1881
1899
|
try {
|
|
@@ -1888,6 +1906,9 @@ const AssistantChatInner = forwardRef<
|
|
|
1888
1906
|
return;
|
|
1889
1907
|
}
|
|
1890
1908
|
const info = (await res.json()) as ActiveRunLookup;
|
|
1909
|
+
if (isReplayableTerminalRun(info)) {
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1891
1912
|
if (info.status !== "running" || activeRunLooksStale(info)) {
|
|
1892
1913
|
abortCtrl.abort();
|
|
1893
1914
|
clearInterval(watchdog);
|
|
@@ -1911,6 +1932,7 @@ const AssistantChatInner = forwardRef<
|
|
|
1911
1932
|
lastReconnectProgressAt = Date.now();
|
|
1912
1933
|
};
|
|
1913
1934
|
const idleCheck = setInterval(() => {
|
|
1935
|
+
if (reconnectTerminalReason !== null) return;
|
|
1914
1936
|
if (
|
|
1915
1937
|
!reconnectProgressTimedOut({
|
|
1916
1938
|
lastProgressAt: lastReconnectProgressAt,
|
|
@@ -2038,6 +2060,10 @@ const AssistantChatInner = forwardRef<
|
|
|
2038
2060
|
err.reason === "no_progress"
|
|
2039
2061
|
) {
|
|
2040
2062
|
noProgressDuringReconnect = true;
|
|
2063
|
+
reconnectTerminalReason = err.reason;
|
|
2064
|
+
} else if (err instanceof AgentAutoContinueSignal) {
|
|
2065
|
+
noProgressDuringReconnect = true;
|
|
2066
|
+
reconnectTerminalReason = err.reason;
|
|
2041
2067
|
} else if (
|
|
2042
2068
|
reconnectTimedOut &&
|
|
2043
2069
|
err instanceof Error &&
|
|
@@ -2054,11 +2080,16 @@ const AssistantChatInner = forwardRef<
|
|
|
2054
2080
|
}
|
|
2055
2081
|
|
|
2056
2082
|
if (noProgressDuringReconnect && reconnectRunIdRef.current === runId) {
|
|
2057
|
-
|
|
2083
|
+
const reconnectErrorCode =
|
|
2084
|
+
reconnectTerminalReason === "run_timeout"
|
|
2085
|
+
? "run_timeout"
|
|
2086
|
+
: "reconnect_no_progress";
|
|
2087
|
+
captureError(new Error(`agent-chat:${reconnectErrorCode}`), {
|
|
2058
2088
|
tags: {
|
|
2059
2089
|
context: "agent-native-chat",
|
|
2060
|
-
errorCode:
|
|
2090
|
+
errorCode: reconnectErrorCode,
|
|
2061
2091
|
reconnectTimedOut: String(reconnectTimedOut),
|
|
2092
|
+
reconnectTerminalReason: reconnectTerminalReason ?? undefined,
|
|
2062
2093
|
},
|
|
2063
2094
|
extra: {
|
|
2064
2095
|
runId,
|
|
@@ -2067,14 +2098,16 @@ const AssistantChatInner = forwardRef<
|
|
|
2067
2098
|
contentLength: latestContent.length,
|
|
2068
2099
|
},
|
|
2069
2100
|
});
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2101
|
+
if (reconnectTerminalReason !== "run_timeout") {
|
|
2102
|
+
try {
|
|
2103
|
+
await fetch(`${apiUrl}/runs/${encodeURIComponent(runId)}/abort`, {
|
|
2104
|
+
method: "POST",
|
|
2105
|
+
headers: { "Content-Type": "application/json" },
|
|
2106
|
+
body: JSON.stringify({ reason: "no_progress" }),
|
|
2107
|
+
});
|
|
2108
|
+
} catch {
|
|
2109
|
+
// Best effort — the important part is unwinding the UI.
|
|
2110
|
+
}
|
|
2078
2111
|
}
|
|
2079
2112
|
if (afterSeq > 0) {
|
|
2080
2113
|
// Tail-resume only replays new events; never freeze that slice as a
|
|
@@ -2091,8 +2124,10 @@ const AssistantChatInner = forwardRef<
|
|
|
2091
2124
|
}
|
|
2092
2125
|
setRunErrorInfo({
|
|
2093
2126
|
message:
|
|
2094
|
-
|
|
2095
|
-
|
|
2127
|
+
reconnectTerminalReason === "run_timeout"
|
|
2128
|
+
? "The previous background agent run reached its time limit before finishing. The partial work was preserved; continue or retry to pick up from here."
|
|
2129
|
+
: "The previous agent run stopped producing visible progress during recovery, so it was stopped before it could keep looping.",
|
|
2130
|
+
errorCode: reconnectErrorCode,
|
|
2096
2131
|
recoverable: true,
|
|
2097
2132
|
runId,
|
|
2098
2133
|
});
|
|
@@ -2175,7 +2210,7 @@ const AssistantChatInner = forwardRef<
|
|
|
2175
2210
|
const runInfo = (await runRes.json()) as ActiveRunLookup;
|
|
2176
2211
|
if (
|
|
2177
2212
|
!runInfo.active ||
|
|
2178
|
-
runInfo.status !== "running" ||
|
|
2213
|
+
(runInfo.status !== "running" && !isReplayableTerminalRun(runInfo)) ||
|
|
2179
2214
|
activeRunLooksStale(runInfo)
|
|
2180
2215
|
) {
|
|
2181
2216
|
if (storedActiveRun?.threadId === threadId) {
|
|
@@ -78,6 +78,10 @@ export function getDatabaseAuthToken(): string | undefined {
|
|
|
78
78
|
);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
function getAppEnvPrefix(): string | undefined {
|
|
82
|
+
return process.env.APP_NAME?.toUpperCase().replace(/-/g, "_") || undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
81
85
|
/**
|
|
82
86
|
* Database URL to use for migrations — identical to DATABASE_URL but with the
|
|
83
87
|
* Neon connection-pooler suffix stripped. Neon's PgBouncer runs in transaction
|
|
@@ -89,7 +93,15 @@ export function getDatabaseAuthToken(): string | undefined {
|
|
|
89
93
|
* Non-Neon URLs and already-direct Neon URLs are returned unchanged.
|
|
90
94
|
*/
|
|
91
95
|
export function getMigrationDatabaseUrl(): string {
|
|
92
|
-
const
|
|
96
|
+
const appName = getAppEnvPrefix();
|
|
97
|
+
const appUnpooled = appName
|
|
98
|
+
? process.env[`${appName}_DATABASE_URL_UNPOOLED`]
|
|
99
|
+
: undefined;
|
|
100
|
+
const url =
|
|
101
|
+
appUnpooled ||
|
|
102
|
+
process.env.NETLIFY_DATABASE_URL_UNPOOLED ||
|
|
103
|
+
process.env.DATABASE_URL_UNPOOLED ||
|
|
104
|
+
getDatabaseUrl();
|
|
93
105
|
// Neon pooler hostname: ep-<id>-pooler.<region>.<cloud>.neon.tech
|
|
94
106
|
// Direct hostname: ep-<id>.<region>.<cloud>.neon.tech
|
|
95
107
|
// The region between `-pooler.` and `.neon.tech` can contain multiple
|
|
@@ -261,8 +261,7 @@ function applyDefaultSpeculationRulesHeader(
|
|
|
261
261
|
* Extract the plain JS body from a `<script ...>body</script>` string.
|
|
262
262
|
* Returns `null` if the input is falsy or has no recognisable `</script>` end.
|
|
263
263
|
* Used to compute the sha256 hash of framework-injected inline scripts so the
|
|
264
|
-
* hash can be listed in
|
|
265
|
-
* `'unsafe-inline'`.
|
|
264
|
+
* hash can be listed in app-owned `script-src` CSP directives.
|
|
266
265
|
*/
|
|
267
266
|
function extractScriptBody(scriptTag: string | null): string | null {
|
|
268
267
|
if (!scriptTag) return null;
|
|
@@ -547,13 +546,10 @@ function augmentExistingReportOnlyCspForFrameworkScripts(
|
|
|
547
546
|
*
|
|
548
547
|
* A third directive, `script-src`, is emitted via `Content-Security-Policy-
|
|
549
548
|
* Report-Only` rather than enforced when the app has no existing document CSP.
|
|
550
|
-
* The framework injects
|
|
551
|
-
*
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
* Google Tag Manager / GA4 from `GA_CSP_SCRIPT_HOSTS`. All of those are listed
|
|
555
|
-
* here so the report-only policy reflects the code the framework itself injects
|
|
556
|
-
* instead of reporting a violation on every page load.
|
|
549
|
+
* The framework injects inline scripts for analytics, Sentry, and template
|
|
550
|
+
* setup, and hosted apps need Google Tag Manager to load without noisy CSP
|
|
551
|
+
* diagnostics. The report-only policy is intentionally permissive for scripts:
|
|
552
|
+
* it includes `'unsafe-inline'` plus the known GA/GTM loader hosts.
|
|
557
553
|
*
|
|
558
554
|
* If an app or host already sends an enforced CSP with `script-src`,
|
|
559
555
|
* `script-src-elem`, `connect-src`, `img-src`, or `default-src`, we merge only
|
|
@@ -577,20 +573,22 @@ function applyDocumentCsp(headers: Headers, sentryScript: string | null): void {
|
|
|
577
573
|
if (process.env.NODE_ENV !== "production") return;
|
|
578
574
|
if (process.env.AGENT_NATIVE_DISABLE_DOC_CSP === "1") return;
|
|
579
575
|
|
|
580
|
-
// script-src as Report-Only:
|
|
581
|
-
//
|
|
582
|
-
//
|
|
583
|
-
// itself injects, so listing them keeps the report-only policy from flagging
|
|
584
|
-
// GA on every page load (and keeps it safe to graduate to enforcement).
|
|
585
|
-
// Template theme-init hashes are NOT included here — see function comment.
|
|
576
|
+
// script-src as Report-Only: keep this deliberately loose so the framework's
|
|
577
|
+
// injected analytics and template bootstrap scripts do not look blocked in
|
|
578
|
+
// browser diagnostics.
|
|
586
579
|
const sentryBody = extractScriptBody(sentryScript);
|
|
587
580
|
const sentryHash = sentryBody ? computeInlineScriptHash(sentryBody) : null;
|
|
588
581
|
const gaInlineBody = getGaInlineConfigScriptBody();
|
|
589
582
|
const gaHash = gaInlineBody ? computeInlineScriptHash(gaInlineBody) : null;
|
|
590
583
|
const gaHosts = gaInlineBody ? [...GA_CSP_SCRIPT_HOSTS] : [];
|
|
591
|
-
const gaScriptSrcTokens = [
|
|
584
|
+
const gaScriptSrcTokens = [
|
|
585
|
+
"'unsafe-inline'",
|
|
586
|
+
...(gaHash ? [gaHash] : []),
|
|
587
|
+
...gaHosts,
|
|
588
|
+
];
|
|
592
589
|
const scriptSrcTokens = [
|
|
593
590
|
"'self'",
|
|
591
|
+
"'unsafe-inline'",
|
|
594
592
|
...(sentryHash ? [sentryHash] : []),
|
|
595
593
|
...(gaHash ? [gaHash] : []),
|
|
596
594
|
...gaHosts,
|
|
@@ -250,6 +250,84 @@ function higherShareRole(a: ShareRole, b: ShareRole | null): ShareRole {
|
|
|
250
250
|
return ROLE_RANK[b] > ROLE_RANK[a] ? b : a;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
+
function columnName(column: unknown): string | null {
|
|
254
|
+
const candidate = column as
|
|
255
|
+
| {
|
|
256
|
+
name?: unknown;
|
|
257
|
+
config?: { name?: unknown };
|
|
258
|
+
_: { name?: unknown };
|
|
259
|
+
}
|
|
260
|
+
| undefined;
|
|
261
|
+
const name = candidate?.name ?? candidate?.config?.name ?? candidate?._?.name;
|
|
262
|
+
return typeof name === "string" && name ? name : null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function missingColumnName(err: unknown): string | null {
|
|
266
|
+
const error = err as { code?: string; message?: string } | undefined;
|
|
267
|
+
const message = error?.message ?? "";
|
|
268
|
+
if (
|
|
269
|
+
error?.code !== "42703" &&
|
|
270
|
+
!/no such column|does not exist/i.test(message)
|
|
271
|
+
) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
const quoted = message.match(/column\s+"([^"]+)"\s+does not exist/i)?.[1];
|
|
275
|
+
if (quoted) return quoted;
|
|
276
|
+
const sqlite = message.match(/no such column:\s+["`]?([\w.]+)["`]?/i)?.[1];
|
|
277
|
+
if (sqlite) return sqlite.split(".").pop() ?? sqlite;
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function selectAllExistingResourceColumns(
|
|
282
|
+
resourceTable: any,
|
|
283
|
+
omittedColumnNames: Set<string>,
|
|
284
|
+
): Record<string, unknown> {
|
|
285
|
+
const selection: Record<string, unknown> = {};
|
|
286
|
+
for (const [key, column] of Object.entries(resourceTable)) {
|
|
287
|
+
const name = columnName(column);
|
|
288
|
+
if (!name || omittedColumnNames.has(name)) continue;
|
|
289
|
+
selection[key] = column;
|
|
290
|
+
}
|
|
291
|
+
return selection;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function loadResourceForAccess(
|
|
295
|
+
reg: ShareableResourceRegistration,
|
|
296
|
+
resourceId: string,
|
|
297
|
+
): Promise<any | null> {
|
|
298
|
+
const db = reg.getDb() as any;
|
|
299
|
+
const omittedColumnNames = new Set<string>();
|
|
300
|
+
|
|
301
|
+
for (let attempt = 0; attempt < 12; attempt++) {
|
|
302
|
+
try {
|
|
303
|
+
const query =
|
|
304
|
+
omittedColumnNames.size === 0
|
|
305
|
+
? db.select()
|
|
306
|
+
: db.select(
|
|
307
|
+
selectAllExistingResourceColumns(
|
|
308
|
+
reg.resourceTable,
|
|
309
|
+
omittedColumnNames,
|
|
310
|
+
),
|
|
311
|
+
);
|
|
312
|
+
const [resource] = await query
|
|
313
|
+
.from(reg.resourceTable)
|
|
314
|
+
.where(eq(reg.resourceTable.id, resourceId));
|
|
315
|
+
return resource ?? null;
|
|
316
|
+
} catch (err) {
|
|
317
|
+
const missing = missingColumnName(err);
|
|
318
|
+
if (!missing || omittedColumnNames.has(missing)) throw err;
|
|
319
|
+
omittedColumnNames.add(missing);
|
|
320
|
+
console.warn(
|
|
321
|
+
`[sharing] ${reg.type} access lookup omitted missing column ${missing}`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
throw new Error(
|
|
327
|
+
`Could not load ${reg.type} ${resourceId}: too many missing resource columns`,
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
253
331
|
/**
|
|
254
332
|
* Return the effective role the current user has on a specific resource, or
|
|
255
333
|
* null if they have no access. Loads the resource and relevant share rows.
|
|
@@ -261,12 +339,8 @@ export async function resolveAccess(
|
|
|
261
339
|
): Promise<ResolvedAccess | null> {
|
|
262
340
|
const reg = requireShareableResource(resourceType);
|
|
263
341
|
const ctx = resolveRegisteredAccessContext(reg, rawCtx);
|
|
264
|
-
const db = reg.getDb() as any;
|
|
265
342
|
|
|
266
|
-
const
|
|
267
|
-
.select()
|
|
268
|
-
.from(reg.resourceTable)
|
|
269
|
-
.where(eq(reg.resourceTable.id, resourceId));
|
|
343
|
+
const resource = await loadResourceForAccess(reg, resourceId);
|
|
270
344
|
if (!resource) return null;
|
|
271
345
|
|
|
272
346
|
const { userEmail, orgId } = ctx;
|
|
@@ -637,6 +637,11 @@ const messages = {
|
|
|
637
637
|
s3SecretAccessKeyLabel: "مفتاح الوصول السري",
|
|
638
638
|
s3RegionLabel: "المنطقة",
|
|
639
639
|
s3PublicBaseUrlLabel: "عنوان URL الأساسي العام",
|
|
640
|
+
s3UrlInvalid:
|
|
641
|
+
"يجب أن يكون عنوان URL صالحًا (مثال: https://s3.us-east-1.amazonaws.com)",
|
|
642
|
+
s3BucketInvalid:
|
|
643
|
+
"يجب أن يتكون اسم الحاوية من 3 إلى 63 حرفًا صغيرًا أو رقمًا أو شرطة",
|
|
644
|
+
s3RegionInvalid: 'يجب أن تكون منطقة صالحة (مثال: us-east-1) أو "auto"',
|
|
640
645
|
apiSetup: "إعداد الذكاء الاصطناعي",
|
|
641
646
|
apiSetupDescription:
|
|
642
647
|
"صِل الذكاء الاصطناعي باستخدام أرصدة Builder.io المجانية أو مفاتيح LLM الخاصة بك.",
|
|
@@ -651,6 +656,8 @@ const messages = {
|
|
|
651
656
|
providerKeysSet: "تم تعيين {{count}}",
|
|
652
657
|
checkingProviderKeys: "جار فحص مفاتيح المزود…",
|
|
653
658
|
keySet: "تم التعيين",
|
|
659
|
+
keyCleared: "تم مسح بيانات اعتماد التخزين",
|
|
660
|
+
clearAllS3: "مسح بيانات الاعتماد",
|
|
654
661
|
replaceKey: "استبدال المفتاح…",
|
|
655
662
|
pasteProviderKey: "الصق مفتاح مزود أولًا.",
|
|
656
663
|
apiKeySaved: "تم حفظ مفتاح API",
|
|
@@ -662,6 +662,12 @@ Alle sichtbaren Änderungen für Clips-Nutzer werden hier dokumentiert. Du kanns
|
|
|
662
662
|
s3SecretAccessKeyLabel: "Geheimer Zugriffsschlüssel",
|
|
663
663
|
s3RegionLabel: "Übersetzt: Region",
|
|
664
664
|
s3PublicBaseUrlLabel: "Öffentliche Basis-URL",
|
|
665
|
+
s3UrlInvalid:
|
|
666
|
+
"Muss eine gültige URL sein (z. B. https://s3.us-east-1.amazonaws.com)",
|
|
667
|
+
s3BucketInvalid:
|
|
668
|
+
"Bucket-Name muss 3–63 Kleinbuchstaben, Zahlen oder Bindestriche enthalten",
|
|
669
|
+
s3RegionInvalid:
|
|
670
|
+
'Muss eine gültige Region sein (z. B. us-east-1) oder "auto"',
|
|
665
671
|
apiSetup: "KI-Einrichtung",
|
|
666
672
|
apiSetupDescription:
|
|
667
673
|
"Verbinde KI mit kostenlosen Builder.io-Credits oder deinen eigenen LLM-Schlüsseln.",
|
|
@@ -676,6 +682,8 @@ Alle sichtbaren Änderungen für Clips-Nutzer werden hier dokumentiert. Du kanns
|
|
|
676
682
|
providerKeysSet: "{{count}} gesetzt",
|
|
677
683
|
checkingProviderKeys: "Anbieter-Schlüssel werden geprüft…",
|
|
678
684
|
keySet: "Gesetzt",
|
|
685
|
+
keyCleared: "Speicher-Anmeldedaten gelöscht",
|
|
686
|
+
clearAllS3: "Anmeldedaten löschen",
|
|
679
687
|
replaceKey: "Schlüssel ersetzen…",
|
|
680
688
|
pasteProviderKey: "Füge zuerst einen Anbieter-Schlüssel ein.",
|
|
681
689
|
apiKeySaved: "API-Schlüssel gespeichert",
|
|
@@ -637,6 +637,11 @@ All notable user-facing changes to Clips are documented here. Open it any time f
|
|
|
637
637
|
s3SecretAccessKeyLabel: "Secret access key",
|
|
638
638
|
s3RegionLabel: "Region",
|
|
639
639
|
s3PublicBaseUrlLabel: "Public base URL",
|
|
640
|
+
s3UrlInvalid:
|
|
641
|
+
"Must be a valid URL (e.g. https://s3.us-east-1.amazonaws.com)",
|
|
642
|
+
s3BucketInvalid:
|
|
643
|
+
"Bucket name must be 3–63 lowercase letters, numbers, or hyphens",
|
|
644
|
+
s3RegionInvalid: 'Must be a valid region (e.g. us-east-1) or "auto"',
|
|
640
645
|
apiSetup: "AI setup",
|
|
641
646
|
apiSetupDescription:
|
|
642
647
|
"Connect AI with Builder.io free credits or your own LLM keys.",
|
|
@@ -651,6 +656,8 @@ All notable user-facing changes to Clips are documented here. Open it any time f
|
|
|
651
656
|
providerKeysSet: "{{count}} set",
|
|
652
657
|
checkingProviderKeys: "Checking provider keys…",
|
|
653
658
|
keySet: "Set",
|
|
659
|
+
keyCleared: "Storage credentials cleared",
|
|
660
|
+
clearAllS3: "Clear credentials",
|
|
654
661
|
replaceKey: "Replace key…",
|
|
655
662
|
pasteProviderKey: "Paste a provider key first.",
|
|
656
663
|
apiKeySaved: "API key saved",
|
|
@@ -654,6 +654,11 @@ Todos los cambios visibles para los usuarios de Clips se documentan aquí. Puede
|
|
|
654
654
|
s3SecretAccessKeyLabel: "Clave de acceso secreta",
|
|
655
655
|
s3RegionLabel: "Región",
|
|
656
656
|
s3PublicBaseUrlLabel: "URL base pública",
|
|
657
|
+
s3UrlInvalid:
|
|
658
|
+
"Debe ser una URL válida (p. ej. https://s3.us-east-1.amazonaws.com)",
|
|
659
|
+
s3BucketInvalid:
|
|
660
|
+
"El nombre del bucket debe tener 3–63 letras minúsculas, números o guiones",
|
|
661
|
+
s3RegionInvalid: 'Debe ser una región válida (p. ej. us-east-1) o "auto"',
|
|
657
662
|
apiSetup: "Configuración de IA",
|
|
658
663
|
apiSetupDescription:
|
|
659
664
|
"Conecta IA con créditos gratis de Builder.io o tus propias claves LLM.",
|
|
@@ -668,6 +673,8 @@ Todos los cambios visibles para los usuarios de Clips se documentan aquí. Puede
|
|
|
668
673
|
providerKeysSet: "{{count}} configuradas",
|
|
669
674
|
checkingProviderKeys: "Comprobando claves de proveedor…",
|
|
670
675
|
keySet: "Configurada",
|
|
676
|
+
keyCleared: "Credenciales de almacenamiento borradas",
|
|
677
|
+
clearAllS3: "Borrar credenciales",
|
|
671
678
|
replaceKey: "Reemplazar clave…",
|
|
672
679
|
pasteProviderKey: "Pega primero una clave de proveedor.",
|
|
673
680
|
apiKeySaved: "Clave de API guardada",
|
|
@@ -655,6 +655,11 @@ Tous les changements visibles par les utilisateurs de Clips sont documentés ici
|
|
|
655
655
|
s3SecretAccessKeyLabel: "Clé d’accès secrète",
|
|
656
656
|
s3RegionLabel: "Région",
|
|
657
657
|
s3PublicBaseUrlLabel: "URL de base publique",
|
|
658
|
+
s3UrlInvalid:
|
|
659
|
+
"Doit être une URL valide (ex. https://s3.us-east-1.amazonaws.com)",
|
|
660
|
+
s3BucketInvalid:
|
|
661
|
+
"Le nom du bucket doit contenir 3–63 lettres minuscules, chiffres ou tirets",
|
|
662
|
+
s3RegionInvalid: 'Doit être une région valide (ex. us-east-1) ou "auto"',
|
|
658
663
|
apiSetup: "Configuration IA",
|
|
659
664
|
apiSetupDescription:
|
|
660
665
|
"Connectez l’IA avec les crédits gratuits Builder.io ou vos propres clés LLM.",
|
|
@@ -669,6 +674,8 @@ Tous les changements visibles par les utilisateurs de Clips sont documentés ici
|
|
|
669
674
|
providerKeysSet: "{{count}} définies",
|
|
670
675
|
checkingProviderKeys: "Vérification des clés fournisseur…",
|
|
671
676
|
keySet: "Définie",
|
|
677
|
+
keyCleared: "Identifiants de stockage effacés",
|
|
678
|
+
clearAllS3: "Effacer les identifiants",
|
|
672
679
|
replaceKey: "Remplacer la clé…",
|
|
673
680
|
pasteProviderKey: "Collez d’abord une clé fournisseur.",
|
|
674
681
|
apiKeySaved: "Clé API enregistrée",
|
|
@@ -635,6 +635,10 @@ Clips में उपयोगकर्ताओं को दिखने व
|
|
|
635
635
|
s3SecretAccessKeyLabel: "गुप्त एक्सेस कुंजी",
|
|
636
636
|
s3RegionLabel: "क्षेत्र",
|
|
637
637
|
s3PublicBaseUrlLabel: "सार्वजनिक बेस URL",
|
|
638
|
+
s3UrlInvalid:
|
|
639
|
+
"एक मान्य URL होना चाहिए (उदा. https://s3.us-east-1.amazonaws.com)",
|
|
640
|
+
s3BucketInvalid: "बकेट नाम 3–63 लोअरकेस अक्षर, अंक या हाइफ़न होने चाहिए",
|
|
641
|
+
s3RegionInvalid: 'एक मान्य क्षेत्र (उदा. us-east-1) या "auto" होना चाहिए',
|
|
638
642
|
apiSetup: "AI सेटअप",
|
|
639
643
|
apiSetupDescription:
|
|
640
644
|
"Builder.io मुफ्त क्रेडिट या अपनी LLM keys के साथ AI कनेक्ट करें.",
|
|
@@ -649,6 +653,8 @@ Clips में उपयोगकर्ताओं को दिखने व
|
|
|
649
653
|
providerKeysSet: "{{count}} सेट",
|
|
650
654
|
checkingProviderKeys: "प्रोवाइडर कीज़ जाँची जा रही हैं…",
|
|
651
655
|
keySet: "सेट",
|
|
656
|
+
keyCleared: "स्टोरेज क्रेडेंशियल साफ़ किए गए",
|
|
657
|
+
clearAllS3: "क्रेडेंशियल साफ़ करें",
|
|
652
658
|
replaceKey: "की बदलें…",
|
|
653
659
|
pasteProviderKey: "पहले प्रोवाइडर की पेस्ट करें।",
|
|
654
660
|
apiKeySaved: "API की सहेजी गई",
|
|
@@ -649,6 +649,12 @@ Clips のユーザー向けの主な変更はここに記録されます。コ
|
|
|
649
649
|
s3SecretAccessKeyLabel: "シークレットアクセスキー",
|
|
650
650
|
s3RegionLabel: "リージョン",
|
|
651
651
|
s3PublicBaseUrlLabel: "公開ベース URL",
|
|
652
|
+
s3UrlInvalid:
|
|
653
|
+
"有効な URL を入力してください(例: https://s3.us-east-1.amazonaws.com)",
|
|
654
|
+
s3BucketInvalid:
|
|
655
|
+
"バケット名は 3〜63 文字の小文字、数字、またはハイフンで指定してください",
|
|
656
|
+
s3RegionInvalid:
|
|
657
|
+
'有効なリージョン(例: us-east-1)または "auto" を入力してください',
|
|
652
658
|
apiSetup: "AI 設定",
|
|
653
659
|
apiSetupDescription:
|
|
654
660
|
"Builder.io の無料クレジット、または自分の LLM キーで AI を接続します。",
|
|
@@ -663,6 +669,8 @@ Clips のユーザー向けの主な変更はここに記録されます。コ
|
|
|
663
669
|
providerKeysSet: "{{count}} 件設定済み",
|
|
664
670
|
checkingProviderKeys: "プロバイダーキーを確認中…",
|
|
665
671
|
keySet: "設定済み",
|
|
672
|
+
keyCleared: "ストレージ認証情報をクリアしました",
|
|
673
|
+
clearAllS3: "認証情報をクリア",
|
|
666
674
|
replaceKey: "キーを置換…",
|
|
667
675
|
pasteProviderKey: "先にプロバイダーキーを貼り付けてください。",
|
|
668
676
|
apiKeySaved: "API キーを保存しました",
|
|
@@ -641,6 +641,11 @@ Clips의 모든 사용자 대상 변경 사항은 여기에 기록됩니다. 명
|
|
|
641
641
|
s3SecretAccessKeyLabel: "비밀 액세스 키",
|
|
642
642
|
s3RegionLabel: "리전",
|
|
643
643
|
s3PublicBaseUrlLabel: "공개 기본 URL",
|
|
644
|
+
s3UrlInvalid:
|
|
645
|
+
"유효한 URL이어야 합니다 (예: https://s3.us-east-1.amazonaws.com)",
|
|
646
|
+
s3BucketInvalid:
|
|
647
|
+
"버킷 이름은 3–63자의 소문자, 숫자 또는 하이픈이어야 합니다",
|
|
648
|
+
s3RegionInvalid: '유효한 리전(예: us-east-1) 또는 "auto"이어야 합니다',
|
|
644
649
|
apiSetup: "AI 설정",
|
|
645
650
|
apiSetupDescription:
|
|
646
651
|
"Builder.io 무료 크레딧 또는 직접 보유한 LLM 키로 AI를 연결하세요.",
|
|
@@ -655,6 +660,8 @@ Clips의 모든 사용자 대상 변경 사항은 여기에 기록됩니다. 명
|
|
|
655
660
|
providerKeysSet: "{{count}}개 설정됨",
|
|
656
661
|
checkingProviderKeys: "제공자 키 확인 중…",
|
|
657
662
|
keySet: "설정됨",
|
|
663
|
+
keyCleared: "스토리지 자격 증명이 삭제되었습니다",
|
|
664
|
+
clearAllS3: "자격 증명 삭제",
|
|
658
665
|
replaceKey: "키 바꾸기…",
|
|
659
666
|
pasteProviderKey: "먼저 제공자 키를 붙여넣으세요.",
|
|
660
667
|
apiKeySaved: "API 키가 저장됨",
|
|
@@ -652,6 +652,11 @@ Todas as mudanças visíveis para usuários do Clips são documentadas aqui. Voc
|
|
|
652
652
|
s3SecretAccessKeyLabel: "Chave de acesso secreta",
|
|
653
653
|
s3RegionLabel: "Região",
|
|
654
654
|
s3PublicBaseUrlLabel: "URL base pública",
|
|
655
|
+
s3UrlInvalid:
|
|
656
|
+
"Deve ser uma URL válida (ex.: https://s3.us-east-1.amazonaws.com)",
|
|
657
|
+
s3BucketInvalid:
|
|
658
|
+
"O nome do bucket deve ter 3–63 letras minúsculas, números ou hifens",
|
|
659
|
+
s3RegionInvalid: 'Deve ser uma região válida (ex.: us-east-1) ou "auto"',
|
|
655
660
|
apiSetup: "Configuração de IA",
|
|
656
661
|
apiSetupDescription:
|
|
657
662
|
"Conecte IA com créditos grátis da Builder.io ou suas próprias chaves LLM.",
|
|
@@ -666,6 +671,8 @@ Todas as mudanças visíveis para usuários do Clips são documentadas aqui. Voc
|
|
|
666
671
|
providerKeysSet: "{{count}} configuradas",
|
|
667
672
|
checkingProviderKeys: "Verificando chaves de provedor…",
|
|
668
673
|
keySet: "Configurada",
|
|
674
|
+
keyCleared: "Credenciais de armazenamento limpas",
|
|
675
|
+
clearAllS3: "Limpar credenciais",
|
|
669
676
|
replaceKey: "Substituir chave…",
|
|
670
677
|
pasteProviderKey: "Cole primeiro uma chave de provedor.",
|
|
671
678
|
apiKeySaved: "Chave de API salva",
|
|
@@ -614,6 +614,9 @@ Clips 中所有面向用户的重要更改都会记录在这里。你可以随
|
|
|
614
614
|
s3SecretAccessKeyLabel: "秘密访问密钥",
|
|
615
615
|
s3RegionLabel: "区域",
|
|
616
616
|
s3PublicBaseUrlLabel: "公共基础 URL",
|
|
617
|
+
s3UrlInvalid: "必须是有效的 URL(例如 https://s3.us-east-1.amazonaws.com)",
|
|
618
|
+
s3BucketInvalid: "存储桶名称必须为 3–63 个小写字母、数字或连字符",
|
|
619
|
+
s3RegionInvalid: '必须是有效的区域(例如 us-east-1)或 "auto"',
|
|
617
620
|
apiSetup: "AI 设置",
|
|
618
621
|
apiSetupDescription: "使用 Builder.io 免费额度或你自己的 LLM 密钥连接 AI。",
|
|
619
622
|
builderEasySetup: "Builder.io 免费额度",
|
|
@@ -626,6 +629,8 @@ Clips 中所有面向用户的重要更改都会记录在这里。你可以随
|
|
|
626
629
|
providerKeysSet: "已设置 {{count}} 个",
|
|
627
630
|
checkingProviderKeys: "正在检查提供方密钥…",
|
|
628
631
|
keySet: "已设置",
|
|
632
|
+
keyCleared: "存储凭证已清除",
|
|
633
|
+
clearAllS3: "清除凭证",
|
|
629
634
|
replaceKey: "替换密钥…",
|
|
630
635
|
pasteProviderKey: "请先粘贴提供方密钥。",
|
|
631
636
|
apiKeySaved: "API 密钥已保存",
|
|
@@ -607,6 +607,9 @@ const messages = {
|
|
|
607
607
|
s3SecretAccessKeyLabel: "秘密存取金鑰",
|
|
608
608
|
s3RegionLabel: "區域",
|
|
609
609
|
s3PublicBaseUrlLabel: "公開基礎 URL",
|
|
610
|
+
s3UrlInvalid: "必須是有效的 URL(例如 https://s3.us-east-1.amazonaws.com)",
|
|
611
|
+
s3BucketInvalid: "儲存貯體名稱必須為 3–63 個小寫字母、數字或連字號",
|
|
612
|
+
s3RegionInvalid: '必須是有效的區域(例如 us-east-1)或 "auto"',
|
|
610
613
|
apiSetup: "AI 設定",
|
|
611
614
|
apiSetupDescription: "使用 Builder.io 免費額度或您自己的 LLM 金鑰連線 AI。",
|
|
612
615
|
builderEasySetup: "Builder.io 免費額度",
|
|
@@ -619,6 +622,8 @@ const messages = {
|
|
|
619
622
|
providerKeysSet: "已設定 {{count}} 個",
|
|
620
623
|
checkingProviderKeys: "正在檢查提供方金鑰…",
|
|
621
624
|
keySet: "已設定",
|
|
625
|
+
keyCleared: "儲存憑證已清除",
|
|
626
|
+
clearAllS3: "清除憑證",
|
|
622
627
|
replaceKey: "替換金鑰…",
|
|
623
628
|
pasteProviderKey: "請先貼上提供方金鑰。",
|
|
624
629
|
apiKeySaved: "API 金鑰已儲存",
|