veryfront 0.0.72 → 0.0.74
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 +3 -0
- package/dist/ai/components.js +593 -52
- package/dist/ai/components.js.map +3 -3
- package/dist/ai/dev.js +121 -18
- package/dist/ai/dev.js.map +2 -2
- package/dist/ai/index.js +732 -236
- package/dist/ai/index.js.map +4 -4
- package/dist/ai/production.js +121 -18
- package/dist/ai/production.js.map +2 -2
- package/dist/ai/react.js +57 -37
- package/dist/ai/react.js.map +2 -2
- package/dist/ai/workflow.js +435 -63
- package/dist/ai/workflow.js.map +4 -4
- package/dist/components.js +3353 -206
- package/dist/components.js.map +4 -4
- package/dist/config.js +377 -40
- package/dist/config.js.map +3 -3
- package/dist/context.d.ts +44 -0
- package/dist/context.js +52 -0
- package/dist/context.js.map +7 -0
- package/dist/data.js +156 -37
- package/dist/data.js.map +3 -3
- package/dist/fonts.d.ts +24 -0
- package/dist/fonts.js +45 -0
- package/dist/fonts.js.map +7 -0
- package/dist/head.d.ts +21 -0
- package/dist/head.js +34 -0
- package/dist/head.js.map +7 -0
- package/dist/index.js +3463 -282
- package/dist/index.js.map +4 -4
- package/dist/oauth/handlers.js +1 -1
- package/dist/oauth/handlers.js.map +2 -2
- package/dist/oauth/index.js +1 -1
- package/dist/oauth/index.js.map +2 -2
- package/dist/oauth/providers.js +1 -1
- package/dist/oauth/providers.js.map +2 -2
- package/dist/router.d.ts +69 -0
- package/dist/router.js +61 -0
- package/dist/router.js.map +7 -0
- package/dist/templates/ai/app/api/chat/route.ts +106 -3
- package/package.json +19 -2
- package/dist/cli.js +0 -108105
package/dist/ai/index.js
CHANGED
|
@@ -79,19 +79,69 @@ function getEnvironmentVariable(name) {
|
|
|
79
79
|
}
|
|
80
80
|
return void 0;
|
|
81
81
|
}
|
|
82
|
+
function isProductionEnvironment() {
|
|
83
|
+
return getEnvironmentVariable("NODE_ENV") === "production";
|
|
84
|
+
}
|
|
82
85
|
|
|
83
86
|
// src/core/utils/logger/logger.ts
|
|
84
87
|
var cachedLogLevel;
|
|
88
|
+
var cachedLogFormat;
|
|
85
89
|
function resolveLogLevel(force = false) {
|
|
86
90
|
if (force || cachedLogLevel === void 0) {
|
|
87
91
|
cachedLogLevel = getDefaultLevel();
|
|
88
92
|
}
|
|
89
93
|
return cachedLogLevel;
|
|
90
94
|
}
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
function resolveLogFormat(force = false) {
|
|
96
|
+
if (force || cachedLogFormat === void 0) {
|
|
97
|
+
cachedLogFormat = getDefaultFormat();
|
|
98
|
+
}
|
|
99
|
+
return cachedLogFormat;
|
|
100
|
+
}
|
|
101
|
+
function getDefaultFormat() {
|
|
102
|
+
const envFormat = getEnvironmentVariable("LOG_FORMAT");
|
|
103
|
+
if (envFormat === "json" || envFormat === "text") {
|
|
104
|
+
return envFormat;
|
|
105
|
+
}
|
|
106
|
+
return isProductionEnvironment() ? "json" : "text";
|
|
107
|
+
}
|
|
108
|
+
function serializeError(err) {
|
|
109
|
+
if (err instanceof Error) {
|
|
110
|
+
return {
|
|
111
|
+
name: err.name,
|
|
112
|
+
message: err.message,
|
|
113
|
+
stack: err.stack
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (err !== void 0 && err !== null) {
|
|
117
|
+
return {
|
|
118
|
+
name: "UnknownError",
|
|
119
|
+
message: String(err)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
function extractContext(args) {
|
|
125
|
+
let context;
|
|
126
|
+
let error;
|
|
127
|
+
for (const arg of args) {
|
|
128
|
+
if (arg instanceof Error) {
|
|
129
|
+
error = serializeError(arg);
|
|
130
|
+
} else if (typeof arg === "object" && arg !== null && !Array.isArray(arg)) {
|
|
131
|
+
context = { ...context, ...arg };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { context, error };
|
|
135
|
+
}
|
|
136
|
+
var ConsoleLogger = class _ConsoleLogger {
|
|
137
|
+
constructor(prefix, level = resolveLogLevel(), format = resolveLogFormat(), boundContext) {
|
|
93
138
|
this.prefix = prefix;
|
|
94
139
|
this.level = level;
|
|
140
|
+
this.format = format;
|
|
141
|
+
this.boundContext = {};
|
|
142
|
+
if (boundContext) {
|
|
143
|
+
this.boundContext = boundContext;
|
|
144
|
+
}
|
|
95
145
|
}
|
|
96
146
|
setLevel(level) {
|
|
97
147
|
this.level = level;
|
|
@@ -99,36 +149,88 @@ var ConsoleLogger = class {
|
|
|
99
149
|
getLevel() {
|
|
100
150
|
return this.level;
|
|
101
151
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
152
|
+
setFormat(format) {
|
|
153
|
+
this.format = format;
|
|
154
|
+
}
|
|
155
|
+
getFormat() {
|
|
156
|
+
return this.format;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Create a child logger with additional bound context.
|
|
160
|
+
*/
|
|
161
|
+
child(context) {
|
|
162
|
+
return new _ConsoleLogger(this.prefix, this.level, this.format, {
|
|
163
|
+
...this.boundContext,
|
|
164
|
+
...context
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
formatJson(level, message, args) {
|
|
168
|
+
const { context, error } = extractContext(args);
|
|
169
|
+
const entry = {
|
|
170
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
171
|
+
level,
|
|
172
|
+
service: this.prefix.toLowerCase(),
|
|
173
|
+
message
|
|
174
|
+
};
|
|
175
|
+
const mergedContext = { ...this.boundContext, ...context };
|
|
176
|
+
if (Object.keys(mergedContext).length > 0) {
|
|
177
|
+
if ("requestId" in mergedContext) {
|
|
178
|
+
entry.requestId = String(mergedContext.requestId);
|
|
179
|
+
delete mergedContext.requestId;
|
|
180
|
+
}
|
|
181
|
+
if ("traceId" in mergedContext) {
|
|
182
|
+
entry.traceId = String(mergedContext.traceId);
|
|
183
|
+
delete mergedContext.traceId;
|
|
184
|
+
}
|
|
185
|
+
if ("projectSlug" in mergedContext) {
|
|
186
|
+
entry.projectSlug = String(mergedContext.projectSlug);
|
|
187
|
+
delete mergedContext.projectSlug;
|
|
188
|
+
}
|
|
189
|
+
if ("durationMs" in mergedContext) {
|
|
190
|
+
entry.durationMs = Number(mergedContext.durationMs);
|
|
191
|
+
delete mergedContext.durationMs;
|
|
192
|
+
}
|
|
193
|
+
if (Object.keys(mergedContext).length > 0) {
|
|
194
|
+
entry.context = mergedContext;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (error) {
|
|
198
|
+
entry.error = error;
|
|
105
199
|
}
|
|
200
|
+
return JSON.stringify(entry);
|
|
106
201
|
}
|
|
107
|
-
|
|
108
|
-
if (this.level
|
|
109
|
-
|
|
202
|
+
log(level, logLevel, consoleFn, message, args) {
|
|
203
|
+
if (this.level > logLevel)
|
|
204
|
+
return;
|
|
205
|
+
if (this.format === "json") {
|
|
206
|
+
consoleFn(this.formatJson(level, message, args));
|
|
207
|
+
} else {
|
|
208
|
+
const prefix = level === "info" ? "" : ` ${level.toUpperCase()}:`;
|
|
209
|
+
consoleFn(`[${this.prefix}]${prefix} ${message}`, ...args);
|
|
110
210
|
}
|
|
111
211
|
}
|
|
212
|
+
debug(message, ...args) {
|
|
213
|
+
this.log("debug", 0 /* DEBUG */, console.debug, message, args);
|
|
214
|
+
}
|
|
215
|
+
info(message, ...args) {
|
|
216
|
+
this.log("info", 1 /* INFO */, console.log, message, args);
|
|
217
|
+
}
|
|
112
218
|
warn(message, ...args) {
|
|
113
|
-
|
|
114
|
-
console.warn(`[${this.prefix}] WARN: ${message}`, ...args);
|
|
115
|
-
}
|
|
219
|
+
this.log("warn", 2 /* WARN */, console.warn, message, args);
|
|
116
220
|
}
|
|
117
221
|
error(message, ...args) {
|
|
118
|
-
|
|
119
|
-
console.error(`[${this.prefix}] ERROR: ${message}`, ...args);
|
|
120
|
-
}
|
|
222
|
+
this.log("error", 3 /* ERROR */, console.error, message, args);
|
|
121
223
|
}
|
|
122
224
|
async time(label, fn) {
|
|
123
225
|
const start = performance.now();
|
|
124
226
|
try {
|
|
125
227
|
const result = await fn();
|
|
126
|
-
const
|
|
127
|
-
this.debug(`${label} completed
|
|
228
|
+
const durationMs = performance.now() - start;
|
|
229
|
+
this.debug(`${label} completed`, { durationMs: Math.round(durationMs) });
|
|
128
230
|
return result;
|
|
129
231
|
} catch (error) {
|
|
130
|
-
const
|
|
131
|
-
this.error(`${label} failed
|
|
232
|
+
const durationMs = performance.now() - start;
|
|
233
|
+
this.error(`${label} failed`, { durationMs: Math.round(durationMs) }, error);
|
|
132
234
|
throw error;
|
|
133
235
|
}
|
|
134
236
|
}
|
|
@@ -171,6 +273,7 @@ var serverLogger = createLogger("SERVER");
|
|
|
171
273
|
var rendererLogger = createLogger("RENDERER");
|
|
172
274
|
var bundlerLogger = createLogger("BUNDLER");
|
|
173
275
|
var agentLogger = createLogger("AGENT");
|
|
276
|
+
var proxyLogger = createLogger("PROXY");
|
|
174
277
|
var logger = createLogger("VERYFRONT");
|
|
175
278
|
|
|
176
279
|
// src/ai/providers/base.ts
|
|
@@ -191,6 +294,29 @@ var OpenAIStreamChunkSchema = z.object({
|
|
|
191
294
|
finish_reason: z.string().nullable()
|
|
192
295
|
})).min(1)
|
|
193
296
|
});
|
|
297
|
+
var OpenAICompletionResponseSchema = z.object({
|
|
298
|
+
id: z.string(),
|
|
299
|
+
choices: z.array(z.object({
|
|
300
|
+
message: z.object({
|
|
301
|
+
role: z.string(),
|
|
302
|
+
content: z.string().nullable().optional(),
|
|
303
|
+
tool_calls: z.array(z.object({
|
|
304
|
+
id: z.string(),
|
|
305
|
+
type: z.literal("function"),
|
|
306
|
+
function: z.object({
|
|
307
|
+
name: z.string(),
|
|
308
|
+
arguments: z.string()
|
|
309
|
+
})
|
|
310
|
+
})).optional()
|
|
311
|
+
}),
|
|
312
|
+
finish_reason: z.string().nullable()
|
|
313
|
+
})).min(1),
|
|
314
|
+
usage: z.object({
|
|
315
|
+
prompt_tokens: z.number(),
|
|
316
|
+
completion_tokens: z.number(),
|
|
317
|
+
total_tokens: z.number()
|
|
318
|
+
}).optional()
|
|
319
|
+
});
|
|
194
320
|
var BaseProvider = class {
|
|
195
321
|
constructor(config) {
|
|
196
322
|
this.config = config;
|
|
@@ -230,7 +356,17 @@ var BaseProvider = class {
|
|
|
230
356
|
}));
|
|
231
357
|
}
|
|
232
358
|
const data = await response.json();
|
|
233
|
-
|
|
359
|
+
const parseResult = OpenAICompletionResponseSchema.safeParse(data);
|
|
360
|
+
if (!parseResult.success) {
|
|
361
|
+
agentLogger.warn(`${this.name}: Invalid response structure`, {
|
|
362
|
+
errors: parseResult.error.flatten()
|
|
363
|
+
});
|
|
364
|
+
throw toError(createError({
|
|
365
|
+
type: "agent",
|
|
366
|
+
message: `${this.name}: Invalid response structure from provider`
|
|
367
|
+
}));
|
|
368
|
+
}
|
|
369
|
+
return this.transformResponse(parseResult.data);
|
|
234
370
|
}
|
|
235
371
|
/**
|
|
236
372
|
* Stream a completion
|
|
@@ -455,6 +591,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
455
591
|
parameters: tool3.parameters
|
|
456
592
|
}
|
|
457
593
|
}));
|
|
594
|
+
body.parallel_tool_calls = false;
|
|
458
595
|
}
|
|
459
596
|
return body;
|
|
460
597
|
}
|
|
@@ -905,7 +1042,7 @@ var GoogleProvider = class extends BaseProvider {
|
|
|
905
1042
|
};
|
|
906
1043
|
|
|
907
1044
|
// src/platform/compat/runtime.ts
|
|
908
|
-
var isDeno = typeof Deno !== "undefined";
|
|
1045
|
+
var isDeno = typeof Deno !== "undefined" && typeof Deno.version === "object";
|
|
909
1046
|
var isNode = typeof globalThis.process !== "undefined" && globalThis.process?.versions?.node !== void 0;
|
|
910
1047
|
var isBun = typeof globalThis.Bun !== "undefined";
|
|
911
1048
|
var isCloudflare = typeof globalThis !== "undefined" && "caches" in globalThis && "WebSocketPair" in globalThis;
|
|
@@ -1932,6 +2069,9 @@ var veryfrontConfigSchema = z5.object({
|
|
|
1932
2069
|
}).partial().optional(),
|
|
1933
2070
|
router: z5.enum(["app", "pages"]).optional(),
|
|
1934
2071
|
defaultLayout: z5.string().optional(),
|
|
2072
|
+
layout: z5.string().optional(),
|
|
2073
|
+
provider: z5.string().optional(),
|
|
2074
|
+
app: z5.string().optional(),
|
|
1935
2075
|
theme: z5.object({ colors: z5.record(z5.string()).optional() }).partial().optional(),
|
|
1936
2076
|
build: z5.object({
|
|
1937
2077
|
outDir: z5.string().optional(),
|
|
@@ -2027,6 +2167,8 @@ var veryfrontConfigSchema = z5.object({
|
|
|
2027
2167
|
apiBaseUrl: z5.string().url(),
|
|
2028
2168
|
apiToken: z5.string(),
|
|
2029
2169
|
projectSlug: z5.string(),
|
|
2170
|
+
proxyMode: z5.boolean().optional(),
|
|
2171
|
+
productionMode: z5.boolean().optional(),
|
|
2030
2172
|
cache: z5.object({
|
|
2031
2173
|
enabled: z5.boolean().optional(),
|
|
2032
2174
|
ttl: z5.number().int().positive().optional(),
|
|
@@ -2088,6 +2230,9 @@ function findUnknownTopLevelKeys(input) {
|
|
|
2088
2230
|
"experimental",
|
|
2089
2231
|
"router",
|
|
2090
2232
|
"defaultLayout",
|
|
2233
|
+
"layout",
|
|
2234
|
+
"provider",
|
|
2235
|
+
"app",
|
|
2091
2236
|
"theme",
|
|
2092
2237
|
"build",
|
|
2093
2238
|
"cache",
|
|
@@ -2105,12 +2250,12 @@ function findUnknownTopLevelKeys(input) {
|
|
|
2105
2250
|
}
|
|
2106
2251
|
|
|
2107
2252
|
// src/core/config/loader.ts
|
|
2108
|
-
import { join } from "node:path";
|
|
2253
|
+
import { dirname, join } from "node:path";
|
|
2109
2254
|
|
|
2110
2255
|
// deno.json
|
|
2111
2256
|
var deno_default = {
|
|
2112
2257
|
name: "veryfront",
|
|
2113
|
-
version: "0.0.
|
|
2258
|
+
version: "0.0.74",
|
|
2114
2259
|
nodeModulesDir: "auto",
|
|
2115
2260
|
exclude: [
|
|
2116
2261
|
"npm/",
|
|
@@ -2195,12 +2340,12 @@ var deno_default = {
|
|
|
2195
2340
|
csstype: "https://esm.sh/csstype@3.2.3",
|
|
2196
2341
|
"@types/react": "https://esm.sh/@types/react@18.3.27?deps=csstype@3.2.3",
|
|
2197
2342
|
"@types/react-dom": "https://esm.sh/@types/react-dom@18.3.7?deps=csstype@3.2.3",
|
|
2198
|
-
react: "
|
|
2199
|
-
"react-dom": "
|
|
2200
|
-
"react-dom/server": "
|
|
2201
|
-
"react-dom/client": "
|
|
2202
|
-
"react/jsx-runtime": "
|
|
2203
|
-
"react/jsx-dev-runtime": "
|
|
2343
|
+
react: "npm:react@18.3.1",
|
|
2344
|
+
"react-dom": "npm:react-dom@18.3.1",
|
|
2345
|
+
"react-dom/server": "npm:react-dom@18.3.1/server.node",
|
|
2346
|
+
"react-dom/client": "npm:react-dom@18.3.1/client",
|
|
2347
|
+
"react/jsx-runtime": "npm:react@18.3.1/jsx-runtime",
|
|
2348
|
+
"react/jsx-dev-runtime": "npm:react@18.3.1/jsx-dev-runtime",
|
|
2204
2349
|
"@mdx-js/mdx": "npm:@mdx-js/mdx@3.0.0",
|
|
2205
2350
|
"@mdx-js/react": "npm:@mdx-js/react@3.0.0",
|
|
2206
2351
|
"unist-util-visit": "npm:unist-util-visit@5.0.0",
|
|
@@ -2210,27 +2355,36 @@ var deno_default = {
|
|
|
2210
2355
|
"remark-frontmatter": "npm:remark-frontmatter@5.0.0",
|
|
2211
2356
|
"rehype-highlight": "npm:rehype-highlight@7.0.2",
|
|
2212
2357
|
"rehype-slug": "npm:rehype-slug@6.0.0",
|
|
2213
|
-
esbuild: "
|
|
2214
|
-
"esbuild/mod.js": "
|
|
2358
|
+
esbuild: "npm:esbuild@0.20.2",
|
|
2359
|
+
"esbuild/mod.js": "npm:esbuild@0.20.2",
|
|
2215
2360
|
"es-module-lexer": "npm:es-module-lexer@1.5.0",
|
|
2216
|
-
zod: "npm:zod@3.
|
|
2361
|
+
zod: "npm:zod@3.25.76",
|
|
2217
2362
|
"mime-types": "npm:mime-types@2.1.35",
|
|
2218
2363
|
mdast: "npm:@types/mdast@4.0.3",
|
|
2219
2364
|
hast: "npm:@types/hast@3.0.3",
|
|
2220
2365
|
unist: "npm:@types/unist@3.0.2",
|
|
2221
2366
|
unified: "npm:unified@11.0.5",
|
|
2222
|
-
ai: "
|
|
2223
|
-
"ai/react": "
|
|
2224
|
-
"@ai-sdk/react": "
|
|
2367
|
+
ai: "npm:ai@5.0.76",
|
|
2368
|
+
"ai/react": "npm:@ai-sdk/react@2.0.1",
|
|
2369
|
+
"@ai-sdk/react": "npm:@ai-sdk/react@2.0.1",
|
|
2225
2370
|
"@ai-sdk/openai": "https://esm.sh/@ai-sdk/openai@2.0.1",
|
|
2226
2371
|
"@ai-sdk/anthropic": "https://esm.sh/@ai-sdk/anthropic@2.0.1",
|
|
2227
2372
|
unocss: "https://esm.sh/unocss@0.59.0",
|
|
2228
2373
|
"@unocss/core": "https://esm.sh/@unocss/core@0.59.0",
|
|
2229
2374
|
"@unocss/preset-wind": "https://esm.sh/@unocss/preset-wind@0.59.0",
|
|
2375
|
+
"next-themes": "npm:next-themes@0.3.0",
|
|
2230
2376
|
redis: "npm:redis",
|
|
2231
2377
|
pg: "npm:pg",
|
|
2232
2378
|
"@opentelemetry/api": "npm:@opentelemetry/api@1",
|
|
2233
|
-
"@opentelemetry/core": "npm:@opentelemetry/core@1"
|
|
2379
|
+
"@opentelemetry/core": "npm:@opentelemetry/core@1",
|
|
2380
|
+
"@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@1",
|
|
2381
|
+
"@opentelemetry/exporter-trace-otlp-http": "npm:@opentelemetry/exporter-trace-otlp-http@0.57",
|
|
2382
|
+
"@opentelemetry/resources": "npm:@opentelemetry/resources@1",
|
|
2383
|
+
"@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@1",
|
|
2384
|
+
"@babel/parser": "npm:@babel/parser@7.26.3",
|
|
2385
|
+
"@babel/traverse": "npm:@babel/traverse@7.26.3",
|
|
2386
|
+
"@babel/generator": "npm:@babel/generator@7.26.3",
|
|
2387
|
+
"@babel/types": "npm:@babel/types@7.26.3"
|
|
2234
2388
|
},
|
|
2235
2389
|
compilerOptions: {
|
|
2236
2390
|
jsx: "react-jsx",
|
|
@@ -2238,7 +2392,7 @@ var deno_default = {
|
|
|
2238
2392
|
strict: true,
|
|
2239
2393
|
noImplicitAny: true,
|
|
2240
2394
|
noUncheckedIndexedAccess: true,
|
|
2241
|
-
types: [],
|
|
2395
|
+
types: ["npm:@types/react@18"],
|
|
2242
2396
|
lib: [
|
|
2243
2397
|
"deno.window",
|
|
2244
2398
|
"dom",
|
|
@@ -2253,9 +2407,9 @@ var deno_default = {
|
|
|
2253
2407
|
build: "deno compile --allow-all --output ../../bin/veryfront src/cli/main.ts",
|
|
2254
2408
|
"build:npm": "deno run -A scripts/build-npm.ts",
|
|
2255
2409
|
release: "deno run -A scripts/release.ts",
|
|
2256
|
-
test: "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --unstable-worker-options --unstable-net",
|
|
2257
|
-
"test:unit": "DENO_JOBS=1 deno test --parallel --allow-all --v8-flags=--max-old-space-size=8192 --ignore=tests --unstable-worker-options --unstable-net",
|
|
2258
|
-
"test:integration": "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all tests --unstable-worker-options --unstable-net",
|
|
2410
|
+
test: "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --unstable-worker-options --unstable-net",
|
|
2411
|
+
"test:unit": "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --allow-all --v8-flags=--max-old-space-size=8192 --ignore=tests,src/ai/workflow/__tests__ --unstable-worker-options --unstable-net",
|
|
2412
|
+
"test:integration": "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --fail-fast --allow-all tests --unstable-worker-options --unstable-net",
|
|
2259
2413
|
"test:coverage": "rm -rf coverage && DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --coverage=coverage --unstable-worker-options --unstable-net || exit 1",
|
|
2260
2414
|
"test:coverage:unit": "rm -rf coverage && DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --coverage=coverage --ignore=tests --unstable-worker-options --unstable-net || exit 1",
|
|
2261
2415
|
"test:coverage:integration": "rm -rf coverage && DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --coverage=coverage tests --unstable-worker-options --unstable-net || exit 1",
|
|
@@ -2317,6 +2471,7 @@ var deno_default = {
|
|
|
2317
2471
|
|
|
2318
2472
|
// src/core/utils/version.ts
|
|
2319
2473
|
var VERSION = getEnv("VERYFRONT_VERSION") || (typeof deno_default.version === "string" ? deno_default.version : "0.0.0");
|
|
2474
|
+
var SERVER_START_TIME = Date.now();
|
|
2320
2475
|
|
|
2321
2476
|
// src/core/utils/constants/cdn.ts
|
|
2322
2477
|
var ESM_CDN_BASE = "https://esm.sh";
|
|
@@ -2432,6 +2587,166 @@ var DEV_SERVER_ENDPOINTS = {
|
|
|
2432
2587
|
ERROR_OVERLAY: INTERNAL_ENDPOINTS.ERROR_OVERLAY
|
|
2433
2588
|
};
|
|
2434
2589
|
|
|
2590
|
+
// src/platform/compat/fs.ts
|
|
2591
|
+
var NodeFileSystem = class {
|
|
2592
|
+
constructor() {
|
|
2593
|
+
this.fs = null;
|
|
2594
|
+
this.os = null;
|
|
2595
|
+
this.path = null;
|
|
2596
|
+
this.initialized = false;
|
|
2597
|
+
}
|
|
2598
|
+
async ensureInitialized() {
|
|
2599
|
+
if (this.initialized)
|
|
2600
|
+
return;
|
|
2601
|
+
if (!isNode) {
|
|
2602
|
+
throw toError(createError({
|
|
2603
|
+
type: "not_supported",
|
|
2604
|
+
message: "Node.js fs modules not available",
|
|
2605
|
+
feature: "Node.js"
|
|
2606
|
+
}));
|
|
2607
|
+
}
|
|
2608
|
+
const [fsModule, osModule, pathModule] = await Promise.all([
|
|
2609
|
+
import("node:fs/promises"),
|
|
2610
|
+
import("node:os"),
|
|
2611
|
+
import("node:path")
|
|
2612
|
+
]);
|
|
2613
|
+
this.fs = fsModule;
|
|
2614
|
+
this.os = osModule;
|
|
2615
|
+
this.path = pathModule;
|
|
2616
|
+
this.initialized = true;
|
|
2617
|
+
}
|
|
2618
|
+
async readTextFile(path) {
|
|
2619
|
+
await this.ensureInitialized();
|
|
2620
|
+
return await this.fs.readFile(path, { encoding: "utf8" });
|
|
2621
|
+
}
|
|
2622
|
+
async readFile(path) {
|
|
2623
|
+
await this.ensureInitialized();
|
|
2624
|
+
return await this.fs.readFile(path);
|
|
2625
|
+
}
|
|
2626
|
+
async writeTextFile(path, data) {
|
|
2627
|
+
await this.ensureInitialized();
|
|
2628
|
+
await this.fs.writeFile(path, data, { encoding: "utf8" });
|
|
2629
|
+
}
|
|
2630
|
+
async writeFile(path, data) {
|
|
2631
|
+
await this.ensureInitialized();
|
|
2632
|
+
await this.fs.writeFile(path, data);
|
|
2633
|
+
}
|
|
2634
|
+
async exists(path) {
|
|
2635
|
+
await this.ensureInitialized();
|
|
2636
|
+
try {
|
|
2637
|
+
await this.fs.access(path);
|
|
2638
|
+
return true;
|
|
2639
|
+
} catch (error) {
|
|
2640
|
+
if (error.code === "ENOENT") {
|
|
2641
|
+
return false;
|
|
2642
|
+
}
|
|
2643
|
+
throw error;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
async stat(path) {
|
|
2647
|
+
await this.ensureInitialized();
|
|
2648
|
+
const stat = await this.fs.stat(path);
|
|
2649
|
+
return {
|
|
2650
|
+
isFile: stat.isFile(),
|
|
2651
|
+
isDirectory: stat.isDirectory(),
|
|
2652
|
+
isSymlink: stat.isSymbolicLink(),
|
|
2653
|
+
size: stat.size,
|
|
2654
|
+
mtime: stat.mtime
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2657
|
+
async mkdir(path, options) {
|
|
2658
|
+
await this.ensureInitialized();
|
|
2659
|
+
await this.fs.mkdir(path, { recursive: options?.recursive ?? false });
|
|
2660
|
+
}
|
|
2661
|
+
async *readDir(path) {
|
|
2662
|
+
await this.ensureInitialized();
|
|
2663
|
+
const entries = await this.fs.readdir(path, { withFileTypes: true });
|
|
2664
|
+
for (const entry of entries) {
|
|
2665
|
+
yield {
|
|
2666
|
+
name: entry.name,
|
|
2667
|
+
isFile: entry.isFile(),
|
|
2668
|
+
isDirectory: entry.isDirectory()
|
|
2669
|
+
};
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
async remove(path, options) {
|
|
2673
|
+
await this.ensureInitialized();
|
|
2674
|
+
await this.fs.rm(path, {
|
|
2675
|
+
recursive: options?.recursive ?? false,
|
|
2676
|
+
force: options?.recursive ?? false
|
|
2677
|
+
});
|
|
2678
|
+
}
|
|
2679
|
+
async makeTempDir(options) {
|
|
2680
|
+
await this.ensureInitialized();
|
|
2681
|
+
const tempDir = this.path.join(
|
|
2682
|
+
this.os.tmpdir(),
|
|
2683
|
+
`${options?.prefix ?? "tmp-"}${Math.random().toString(36).substring(2, 8)}`
|
|
2684
|
+
);
|
|
2685
|
+
await this.fs.mkdir(tempDir, { recursive: true });
|
|
2686
|
+
return tempDir;
|
|
2687
|
+
}
|
|
2688
|
+
};
|
|
2689
|
+
var DenoFileSystem = class {
|
|
2690
|
+
async readTextFile(path) {
|
|
2691
|
+
return await Deno.readTextFile(path);
|
|
2692
|
+
}
|
|
2693
|
+
async readFile(path) {
|
|
2694
|
+
return await Deno.readFile(path);
|
|
2695
|
+
}
|
|
2696
|
+
async writeTextFile(path, data) {
|
|
2697
|
+
await Deno.writeTextFile(path, data);
|
|
2698
|
+
}
|
|
2699
|
+
async writeFile(path, data) {
|
|
2700
|
+
await Deno.writeFile(path, data);
|
|
2701
|
+
}
|
|
2702
|
+
async exists(path) {
|
|
2703
|
+
try {
|
|
2704
|
+
await Deno.stat(path);
|
|
2705
|
+
return true;
|
|
2706
|
+
} catch (error) {
|
|
2707
|
+
if (error instanceof Deno.errors.NotFound) {
|
|
2708
|
+
return false;
|
|
2709
|
+
}
|
|
2710
|
+
throw error;
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
async stat(path) {
|
|
2714
|
+
const stat = await Deno.stat(path);
|
|
2715
|
+
return {
|
|
2716
|
+
isFile: stat.isFile,
|
|
2717
|
+
isDirectory: stat.isDirectory,
|
|
2718
|
+
isSymlink: stat.isSymlink,
|
|
2719
|
+
size: stat.size,
|
|
2720
|
+
mtime: stat.mtime
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
async mkdir(path, options) {
|
|
2724
|
+
await Deno.mkdir(path, { recursive: options?.recursive ?? false });
|
|
2725
|
+
}
|
|
2726
|
+
async *readDir(path) {
|
|
2727
|
+
for await (const entry of Deno.readDir(path)) {
|
|
2728
|
+
yield {
|
|
2729
|
+
name: entry.name,
|
|
2730
|
+
isFile: entry.isFile,
|
|
2731
|
+
isDirectory: entry.isDirectory
|
|
2732
|
+
};
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
async remove(path, options) {
|
|
2736
|
+
await Deno.remove(path, { recursive: options?.recursive ?? false });
|
|
2737
|
+
}
|
|
2738
|
+
async makeTempDir(options) {
|
|
2739
|
+
return await Deno.makeTempDir({ prefix: options?.prefix });
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
function createFileSystem() {
|
|
2743
|
+
if (isDeno) {
|
|
2744
|
+
return new DenoFileSystem();
|
|
2745
|
+
} else {
|
|
2746
|
+
return new NodeFileSystem();
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2435
2750
|
// src/core/config/loader.ts
|
|
2436
2751
|
function getDefaultImportMapForConfig() {
|
|
2437
2752
|
return { imports: getReactImportMap(REACT_DEFAULT_VERSION) };
|
|
@@ -2568,7 +2883,62 @@ var ConfigValidationError = class extends Error {
|
|
|
2568
2883
|
this.name = "ConfigValidationError";
|
|
2569
2884
|
}
|
|
2570
2885
|
};
|
|
2571
|
-
|
|
2886
|
+
function isVirtualFilesystem(adapter) {
|
|
2887
|
+
const wrappedAdapter = adapter?.fs?.fsAdapter;
|
|
2888
|
+
const adapterName = wrappedAdapter?.constructor?.name;
|
|
2889
|
+
return adapterName === "VeryfrontFSAdapter";
|
|
2890
|
+
}
|
|
2891
|
+
async function loadConfigFromVirtualFS(configPath, projectDir, adapter) {
|
|
2892
|
+
const fs2 = createFileSystem();
|
|
2893
|
+
const content = await adapter.fs.readFile(configPath);
|
|
2894
|
+
const source = typeof content === "string" ? content : new TextDecoder().decode(content);
|
|
2895
|
+
serverLogger.debug(`[CONFIG] Loading config from virtual FS: ${configPath}`);
|
|
2896
|
+
const isTsx = configPath.endsWith(".tsx");
|
|
2897
|
+
const loader = isTsx ? "tsx" : configPath.endsWith(".ts") ? "ts" : "js";
|
|
2898
|
+
const { build } = await import("esbuild");
|
|
2899
|
+
const result = await build({
|
|
2900
|
+
bundle: false,
|
|
2901
|
+
// Config files shouldn't need bundling
|
|
2902
|
+
write: false,
|
|
2903
|
+
format: "esm",
|
|
2904
|
+
platform: "neutral",
|
|
2905
|
+
target: "es2022",
|
|
2906
|
+
stdin: {
|
|
2907
|
+
contents: source,
|
|
2908
|
+
loader,
|
|
2909
|
+
resolveDir: dirname(configPath),
|
|
2910
|
+
sourcefile: configPath
|
|
2911
|
+
}
|
|
2912
|
+
});
|
|
2913
|
+
if (result.errors && result.errors.length > 0) {
|
|
2914
|
+
const first = result.errors[0]?.text || "unknown error";
|
|
2915
|
+
throw new ConfigValidationError(`Failed to transpile config: ${first}`);
|
|
2916
|
+
}
|
|
2917
|
+
const js = result.outputFiles?.[0]?.text ?? "export default {}";
|
|
2918
|
+
const tempDir = await fs2.makeTempDir({ prefix: "vf-config-" });
|
|
2919
|
+
const tempFile = join(tempDir, "config.mjs");
|
|
2920
|
+
try {
|
|
2921
|
+
await fs2.writeTextFile(tempFile, js);
|
|
2922
|
+
const configModule = await import(`file://${tempFile}?v=${Date.now()}`);
|
|
2923
|
+
const userConfig = configModule.default || configModule;
|
|
2924
|
+
if (userConfig === null || typeof userConfig !== "object" || Array.isArray(userConfig)) {
|
|
2925
|
+
throw new ConfigValidationError(
|
|
2926
|
+
`Expected object, received ${userConfig === null ? "null" : typeof userConfig}`
|
|
2927
|
+
);
|
|
2928
|
+
}
|
|
2929
|
+
validateCorsConfig(userConfig);
|
|
2930
|
+
validateConfigShape(userConfig);
|
|
2931
|
+
const merged = mergeConfigs(userConfig);
|
|
2932
|
+
configCacheByProject.set(projectDir, { revision: cacheRevision, config: merged });
|
|
2933
|
+
return merged;
|
|
2934
|
+
} finally {
|
|
2935
|
+
await fs2.remove(tempDir, { recursive: true });
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
async function loadAndMergeConfig(configPath, projectDir, adapter) {
|
|
2939
|
+
if (isVirtualFilesystem(adapter)) {
|
|
2940
|
+
return loadConfigFromVirtualFS(configPath, projectDir, adapter);
|
|
2941
|
+
}
|
|
2572
2942
|
try {
|
|
2573
2943
|
const configUrl = `file://${configPath}?t=${Date.now()}-${crypto.randomUUID()}`;
|
|
2574
2944
|
const configModule = await import(configUrl);
|
|
@@ -2604,7 +2974,7 @@ async function getConfig(projectDir, adapter) {
|
|
|
2604
2974
|
if (!exists)
|
|
2605
2975
|
continue;
|
|
2606
2976
|
try {
|
|
2607
|
-
const merged = await loadAndMergeConfig(configPath, projectDir);
|
|
2977
|
+
const merged = await loadAndMergeConfig(configPath, projectDir, adapter);
|
|
2608
2978
|
if (merged)
|
|
2609
2979
|
return merged;
|
|
2610
2980
|
} catch (error) {
|
|
@@ -2777,166 +3147,6 @@ function createMockAdapter() {
|
|
|
2777
3147
|
};
|
|
2778
3148
|
}
|
|
2779
3149
|
|
|
2780
|
-
// src/platform/compat/fs.ts
|
|
2781
|
-
var NodeFileSystem = class {
|
|
2782
|
-
constructor() {
|
|
2783
|
-
this.fs = null;
|
|
2784
|
-
this.os = null;
|
|
2785
|
-
this.path = null;
|
|
2786
|
-
this.initialized = false;
|
|
2787
|
-
}
|
|
2788
|
-
async ensureInitialized() {
|
|
2789
|
-
if (this.initialized)
|
|
2790
|
-
return;
|
|
2791
|
-
if (!isNode) {
|
|
2792
|
-
throw toError(createError({
|
|
2793
|
-
type: "not_supported",
|
|
2794
|
-
message: "Node.js fs modules not available",
|
|
2795
|
-
feature: "Node.js"
|
|
2796
|
-
}));
|
|
2797
|
-
}
|
|
2798
|
-
const [fsModule, osModule, pathModule] = await Promise.all([
|
|
2799
|
-
import("node:fs/promises"),
|
|
2800
|
-
import("node:os"),
|
|
2801
|
-
import("node:path")
|
|
2802
|
-
]);
|
|
2803
|
-
this.fs = fsModule;
|
|
2804
|
-
this.os = osModule;
|
|
2805
|
-
this.path = pathModule;
|
|
2806
|
-
this.initialized = true;
|
|
2807
|
-
}
|
|
2808
|
-
async readTextFile(path) {
|
|
2809
|
-
await this.ensureInitialized();
|
|
2810
|
-
return await this.fs.readFile(path, { encoding: "utf8" });
|
|
2811
|
-
}
|
|
2812
|
-
async readFile(path) {
|
|
2813
|
-
await this.ensureInitialized();
|
|
2814
|
-
return await this.fs.readFile(path);
|
|
2815
|
-
}
|
|
2816
|
-
async writeTextFile(path, data) {
|
|
2817
|
-
await this.ensureInitialized();
|
|
2818
|
-
await this.fs.writeFile(path, data, { encoding: "utf8" });
|
|
2819
|
-
}
|
|
2820
|
-
async writeFile(path, data) {
|
|
2821
|
-
await this.ensureInitialized();
|
|
2822
|
-
await this.fs.writeFile(path, data);
|
|
2823
|
-
}
|
|
2824
|
-
async exists(path) {
|
|
2825
|
-
await this.ensureInitialized();
|
|
2826
|
-
try {
|
|
2827
|
-
await this.fs.access(path);
|
|
2828
|
-
return true;
|
|
2829
|
-
} catch (error) {
|
|
2830
|
-
if (error.code === "ENOENT") {
|
|
2831
|
-
return false;
|
|
2832
|
-
}
|
|
2833
|
-
throw error;
|
|
2834
|
-
}
|
|
2835
|
-
}
|
|
2836
|
-
async stat(path) {
|
|
2837
|
-
await this.ensureInitialized();
|
|
2838
|
-
const stat = await this.fs.stat(path);
|
|
2839
|
-
return {
|
|
2840
|
-
isFile: stat.isFile(),
|
|
2841
|
-
isDirectory: stat.isDirectory(),
|
|
2842
|
-
isSymlink: stat.isSymbolicLink(),
|
|
2843
|
-
size: stat.size,
|
|
2844
|
-
mtime: stat.mtime
|
|
2845
|
-
};
|
|
2846
|
-
}
|
|
2847
|
-
async mkdir(path, options) {
|
|
2848
|
-
await this.ensureInitialized();
|
|
2849
|
-
await this.fs.mkdir(path, { recursive: options?.recursive ?? false });
|
|
2850
|
-
}
|
|
2851
|
-
async *readDir(path) {
|
|
2852
|
-
await this.ensureInitialized();
|
|
2853
|
-
const entries = await this.fs.readdir(path, { withFileTypes: true });
|
|
2854
|
-
for (const entry of entries) {
|
|
2855
|
-
yield {
|
|
2856
|
-
name: entry.name,
|
|
2857
|
-
isFile: entry.isFile(),
|
|
2858
|
-
isDirectory: entry.isDirectory()
|
|
2859
|
-
};
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
async remove(path, options) {
|
|
2863
|
-
await this.ensureInitialized();
|
|
2864
|
-
await this.fs.rm(path, {
|
|
2865
|
-
recursive: options?.recursive ?? false,
|
|
2866
|
-
force: options?.recursive ?? false
|
|
2867
|
-
});
|
|
2868
|
-
}
|
|
2869
|
-
async makeTempDir(options) {
|
|
2870
|
-
await this.ensureInitialized();
|
|
2871
|
-
const tempDir = this.path.join(
|
|
2872
|
-
this.os.tmpdir(),
|
|
2873
|
-
`${options?.prefix ?? "tmp-"}${Math.random().toString(36).substring(2, 8)}`
|
|
2874
|
-
);
|
|
2875
|
-
await this.fs.mkdir(tempDir, { recursive: true });
|
|
2876
|
-
return tempDir;
|
|
2877
|
-
}
|
|
2878
|
-
};
|
|
2879
|
-
var DenoFileSystem = class {
|
|
2880
|
-
async readTextFile(path) {
|
|
2881
|
-
return await Deno.readTextFile(path);
|
|
2882
|
-
}
|
|
2883
|
-
async readFile(path) {
|
|
2884
|
-
return await Deno.readFile(path);
|
|
2885
|
-
}
|
|
2886
|
-
async writeTextFile(path, data) {
|
|
2887
|
-
await Deno.writeTextFile(path, data);
|
|
2888
|
-
}
|
|
2889
|
-
async writeFile(path, data) {
|
|
2890
|
-
await Deno.writeFile(path, data);
|
|
2891
|
-
}
|
|
2892
|
-
async exists(path) {
|
|
2893
|
-
try {
|
|
2894
|
-
await Deno.stat(path);
|
|
2895
|
-
return true;
|
|
2896
|
-
} catch (error) {
|
|
2897
|
-
if (error instanceof Deno.errors.NotFound) {
|
|
2898
|
-
return false;
|
|
2899
|
-
}
|
|
2900
|
-
throw error;
|
|
2901
|
-
}
|
|
2902
|
-
}
|
|
2903
|
-
async stat(path) {
|
|
2904
|
-
const stat = await Deno.stat(path);
|
|
2905
|
-
return {
|
|
2906
|
-
isFile: stat.isFile,
|
|
2907
|
-
isDirectory: stat.isDirectory,
|
|
2908
|
-
isSymlink: stat.isSymlink,
|
|
2909
|
-
size: stat.size,
|
|
2910
|
-
mtime: stat.mtime
|
|
2911
|
-
};
|
|
2912
|
-
}
|
|
2913
|
-
async mkdir(path, options) {
|
|
2914
|
-
await Deno.mkdir(path, { recursive: options?.recursive ?? false });
|
|
2915
|
-
}
|
|
2916
|
-
async *readDir(path) {
|
|
2917
|
-
for await (const entry of Deno.readDir(path)) {
|
|
2918
|
-
yield {
|
|
2919
|
-
name: entry.name,
|
|
2920
|
-
isFile: entry.isFile,
|
|
2921
|
-
isDirectory: entry.isDirectory
|
|
2922
|
-
};
|
|
2923
|
-
}
|
|
2924
|
-
}
|
|
2925
|
-
async remove(path, options) {
|
|
2926
|
-
await Deno.remove(path, { recursive: options?.recursive ?? false });
|
|
2927
|
-
}
|
|
2928
|
-
async makeTempDir(options) {
|
|
2929
|
-
return await Deno.makeTempDir({ prefix: options?.prefix });
|
|
2930
|
-
}
|
|
2931
|
-
};
|
|
2932
|
-
function createFileSystem() {
|
|
2933
|
-
if (isDeno) {
|
|
2934
|
-
return new DenoFileSystem();
|
|
2935
|
-
} else {
|
|
2936
|
-
return new NodeFileSystem();
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
|
|
2940
3150
|
// src/platform/compat/path-helper.ts
|
|
2941
3151
|
import nodePath from "node:path";
|
|
2942
3152
|
var pathMod = null;
|
|
@@ -2952,7 +3162,7 @@ function getPathMod() {
|
|
|
2952
3162
|
return pathMod;
|
|
2953
3163
|
return nodePath;
|
|
2954
3164
|
}
|
|
2955
|
-
var
|
|
3165
|
+
var dirname2 = (path) => getPathMod().dirname(path);
|
|
2956
3166
|
var join2 = (...paths) => getPathMod().join(...paths);
|
|
2957
3167
|
var resolve = (...paths) => getPathMod().resolve(...paths);
|
|
2958
3168
|
var extname = (path) => getPathMod().extname(path);
|
|
@@ -2999,7 +3209,7 @@ function createFsAdapterPlugin(fsAdapter) {
|
|
|
2999
3209
|
build.onResolve(
|
|
3000
3210
|
{ filter: /^\.\.?\// },
|
|
3001
3211
|
async (args) => {
|
|
3002
|
-
const importerDir = args.importer ?
|
|
3212
|
+
const importerDir = args.importer ? dirname2(args.importer) : args.resolveDir;
|
|
3003
3213
|
const basePath = resolve(importerDir, args.path);
|
|
3004
3214
|
const resolvedPath = await resolveWithExtensions(basePath);
|
|
3005
3215
|
if (resolvedPath) {
|
|
@@ -3026,7 +3236,7 @@ function createFsAdapterPlugin(fsAdapter) {
|
|
|
3026
3236
|
contents: content,
|
|
3027
3237
|
loader,
|
|
3028
3238
|
// Set resolveDir for nested imports from this file
|
|
3029
|
-
resolveDir:
|
|
3239
|
+
resolveDir: dirname2(args.path)
|
|
3030
3240
|
};
|
|
3031
3241
|
} catch (error) {
|
|
3032
3242
|
return {
|
|
@@ -3061,7 +3271,7 @@ async function importModule(file, context) {
|
|
|
3061
3271
|
const isJsx = filePath.endsWith(".jsx");
|
|
3062
3272
|
const loader = isTsx ? "tsx" : isJsx ? "jsx" : filePath.endsWith(".ts") ? "ts" : "js";
|
|
3063
3273
|
const { build } = await import("esbuild");
|
|
3064
|
-
const fileDir =
|
|
3274
|
+
const fileDir = dirname2(filePath);
|
|
3065
3275
|
const relativeImports = [];
|
|
3066
3276
|
if (isDeno) {
|
|
3067
3277
|
const relativeImportPattern = /from\s+["'](\.\.[^"']+)["']/g;
|
|
@@ -3812,6 +4022,9 @@ var InMemoryBundleManifestStore = class {
|
|
|
3812
4022
|
};
|
|
3813
4023
|
var manifestStore = new InMemoryBundleManifestStore();
|
|
3814
4024
|
|
|
4025
|
+
// src/core/utils/perf-timer.ts
|
|
4026
|
+
var enabled = typeof process !== "undefined" ? process.env?.VERYFRONT_PERF === "1" : typeof Deno !== "undefined" ? Deno.env.get("VERYFRONT_PERF") === "1" : false;
|
|
4027
|
+
|
|
3815
4028
|
// src/observability/tracing/config.ts
|
|
3816
4029
|
var DEFAULT_CONFIG2 = {
|
|
3817
4030
|
enabled: false,
|
|
@@ -4108,7 +4321,27 @@ async function withSpan(name, fn, options = {}) {
|
|
|
4108
4321
|
);
|
|
4109
4322
|
}
|
|
4110
4323
|
|
|
4111
|
-
// src/ai/
|
|
4324
|
+
// src/ai/config/defaults.ts
|
|
4325
|
+
var AGENT_DEFAULTS = {
|
|
4326
|
+
/** Maximum tokens for completion */
|
|
4327
|
+
maxTokens: 4096,
|
|
4328
|
+
/** Default temperature for generation */
|
|
4329
|
+
temperature: 0.7,
|
|
4330
|
+
/** Maximum agent loop steps */
|
|
4331
|
+
maxSteps: 20,
|
|
4332
|
+
/** Default memory type */
|
|
4333
|
+
memoryType: "conversation",
|
|
4334
|
+
/** Default memory max tokens */
|
|
4335
|
+
memoryMaxTokens: 4e3
|
|
4336
|
+
};
|
|
4337
|
+
var STREAMING_DEFAULTS = {
|
|
4338
|
+
/** Maximum buffer size for streaming (1MB) */
|
|
4339
|
+
maxBufferSize: 1024 * 1024,
|
|
4340
|
+
/** Chunk size for stream processing */
|
|
4341
|
+
chunkSize: 16384
|
|
4342
|
+
};
|
|
4343
|
+
|
|
4344
|
+
// src/ai/agent/streaming/stream-events.ts
|
|
4112
4345
|
import { z as z6 } from "zod";
|
|
4113
4346
|
var AgentStreamEventSchema = z6.discriminatedUnion("type", [
|
|
4114
4347
|
z6.object({
|
|
@@ -4148,8 +4381,8 @@ var AgentStreamEventSchema = z6.discriminatedUnion("type", [
|
|
|
4148
4381
|
})
|
|
4149
4382
|
})
|
|
4150
4383
|
]);
|
|
4151
|
-
|
|
4152
|
-
|
|
4384
|
+
|
|
4385
|
+
// src/ai/agent/message-converter.ts
|
|
4153
4386
|
function convertMessageToProvider(msg) {
|
|
4154
4387
|
const content = getTextFromParts(msg.parts);
|
|
4155
4388
|
const providerMsg = {
|
|
@@ -4179,6 +4412,11 @@ function convertMessageToProvider(msg) {
|
|
|
4179
4412
|
}
|
|
4180
4413
|
return providerMsg;
|
|
4181
4414
|
}
|
|
4415
|
+
|
|
4416
|
+
// src/ai/agent/runtime.ts
|
|
4417
|
+
var DEFAULT_MAX_TOKENS = AGENT_DEFAULTS.maxTokens;
|
|
4418
|
+
var DEFAULT_TEMPERATURE = AGENT_DEFAULTS.temperature;
|
|
4419
|
+
var MAX_STREAM_BUFFER_SIZE = STREAMING_DEFAULTS.maxBufferSize;
|
|
4182
4420
|
var AgentRuntime = class {
|
|
4183
4421
|
constructor(id, config) {
|
|
4184
4422
|
this.status = "idle";
|
|
@@ -4609,6 +4847,10 @@ var AgentRuntime = class {
|
|
|
4609
4847
|
if (done)
|
|
4610
4848
|
break;
|
|
4611
4849
|
partial += decoder.decode(value, { stream: true });
|
|
4850
|
+
if (partial.length > MAX_STREAM_BUFFER_SIZE) {
|
|
4851
|
+
serverLogger.warn("[AGENT] Stream buffer exceeded max size, truncating");
|
|
4852
|
+
partial = partial.slice(-MAX_STREAM_BUFFER_SIZE / 2);
|
|
4853
|
+
}
|
|
4612
4854
|
const segments = partial.split("\n");
|
|
4613
4855
|
partial = segments.pop() ?? "";
|
|
4614
4856
|
const lines = segments.filter((line) => line.trim());
|
|
@@ -5460,7 +5702,6 @@ import {
|
|
|
5460
5702
|
createIdGenerator,
|
|
5461
5703
|
embed,
|
|
5462
5704
|
embedMany,
|
|
5463
|
-
experimental_createMCPClient,
|
|
5464
5705
|
experimental_generateImage,
|
|
5465
5706
|
experimental_generateSpeech,
|
|
5466
5707
|
experimental_transcribe,
|
|
@@ -6935,9 +7176,16 @@ var DAGExecutor = class {
|
|
|
6935
7176
|
context,
|
|
6936
7177
|
nodeStates
|
|
6937
7178
|
);
|
|
7179
|
+
case "loop":
|
|
7180
|
+
return await this.executeLoopNode(
|
|
7181
|
+
node,
|
|
7182
|
+
config,
|
|
7183
|
+
context,
|
|
7184
|
+
nodeStates
|
|
7185
|
+
);
|
|
6938
7186
|
default:
|
|
6939
7187
|
throw new Error(
|
|
6940
|
-
`Unknown node type "${config.type}" for node "${node.id}". Valid types are: step, parallel, map, branch, wait, subWorkflow`
|
|
7188
|
+
`Unknown node type "${config.type}" for node "${node.id}". Valid types are: step, parallel, map, branch, wait, subWorkflow, loop`
|
|
6941
7189
|
);
|
|
6942
7190
|
}
|
|
6943
7191
|
}
|
|
@@ -7095,6 +7343,155 @@ var DAGExecutor = class {
|
|
|
7095
7343
|
waiting: result.waiting
|
|
7096
7344
|
};
|
|
7097
7345
|
}
|
|
7346
|
+
/**
|
|
7347
|
+
* Execute a loop node
|
|
7348
|
+
*/
|
|
7349
|
+
async executeLoopNode(node, config, context, nodeStates) {
|
|
7350
|
+
const startTime = Date.now();
|
|
7351
|
+
const previousResults = [];
|
|
7352
|
+
let iteration = 0;
|
|
7353
|
+
let exitReason = "condition";
|
|
7354
|
+
let lastError;
|
|
7355
|
+
const existingLoopState = context[`${node.id}_loop_state`];
|
|
7356
|
+
if (existingLoopState) {
|
|
7357
|
+
iteration = existingLoopState.iteration;
|
|
7358
|
+
previousResults.push(...existingLoopState.previousResults);
|
|
7359
|
+
}
|
|
7360
|
+
while (iteration < config.maxIterations) {
|
|
7361
|
+
const loopContext = {
|
|
7362
|
+
iteration,
|
|
7363
|
+
totalIterations: iteration,
|
|
7364
|
+
previousResults: [...previousResults],
|
|
7365
|
+
isFirstIteration: iteration === 0,
|
|
7366
|
+
isLastAllowedIteration: iteration === config.maxIterations - 1
|
|
7367
|
+
};
|
|
7368
|
+
const shouldContinue = await config.while(context, loopContext);
|
|
7369
|
+
if (!shouldContinue) {
|
|
7370
|
+
exitReason = "condition";
|
|
7371
|
+
break;
|
|
7372
|
+
}
|
|
7373
|
+
const steps = typeof config.steps === "function" ? config.steps(context, loopContext) : config.steps;
|
|
7374
|
+
const result = await this.execute(steps, {
|
|
7375
|
+
id: `${node.id}_iter_${iteration}`,
|
|
7376
|
+
workflowId: "",
|
|
7377
|
+
status: "running",
|
|
7378
|
+
input: context.input,
|
|
7379
|
+
nodeStates: {},
|
|
7380
|
+
currentNodes: [],
|
|
7381
|
+
context: { ...context, _loop: loopContext },
|
|
7382
|
+
checkpoints: [],
|
|
7383
|
+
pendingApprovals: [],
|
|
7384
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
7385
|
+
});
|
|
7386
|
+
if (result.waiting) {
|
|
7387
|
+
Object.assign(nodeStates, result.nodeStates);
|
|
7388
|
+
const state2 = {
|
|
7389
|
+
nodeId: node.id,
|
|
7390
|
+
status: "running",
|
|
7391
|
+
output: {
|
|
7392
|
+
iteration,
|
|
7393
|
+
waiting: true,
|
|
7394
|
+
previousResults
|
|
7395
|
+
},
|
|
7396
|
+
attempt: 1,
|
|
7397
|
+
startedAt: new Date(startTime)
|
|
7398
|
+
};
|
|
7399
|
+
return {
|
|
7400
|
+
state: state2,
|
|
7401
|
+
contextUpdates: {
|
|
7402
|
+
...result.context,
|
|
7403
|
+
[`${node.id}_loop_state`]: { iteration, previousResults }
|
|
7404
|
+
},
|
|
7405
|
+
waiting: true
|
|
7406
|
+
};
|
|
7407
|
+
}
|
|
7408
|
+
if (result.error) {
|
|
7409
|
+
lastError = result.error;
|
|
7410
|
+
exitReason = "error";
|
|
7411
|
+
break;
|
|
7412
|
+
}
|
|
7413
|
+
previousResults.push(result.context);
|
|
7414
|
+
Object.assign(context, result.context);
|
|
7415
|
+
Object.assign(nodeStates, result.nodeStates);
|
|
7416
|
+
if (config.delay && iteration < config.maxIterations - 1) {
|
|
7417
|
+
const delayMs = typeof config.delay === "number" ? config.delay : this.parseDuration(config.delay);
|
|
7418
|
+
await this.sleep(delayMs);
|
|
7419
|
+
}
|
|
7420
|
+
iteration++;
|
|
7421
|
+
}
|
|
7422
|
+
if (iteration >= config.maxIterations && exitReason !== "condition") {
|
|
7423
|
+
exitReason = "maxIterations";
|
|
7424
|
+
}
|
|
7425
|
+
const finalLoopContext = {
|
|
7426
|
+
iteration,
|
|
7427
|
+
totalIterations: iteration,
|
|
7428
|
+
previousResults,
|
|
7429
|
+
isFirstIteration: false,
|
|
7430
|
+
isLastAllowedIteration: true
|
|
7431
|
+
};
|
|
7432
|
+
let completionUpdates = {};
|
|
7433
|
+
if (exitReason === "maxIterations" && config.onMaxIterations) {
|
|
7434
|
+
completionUpdates = await config.onMaxIterations(context, finalLoopContext);
|
|
7435
|
+
} else if (exitReason === "condition" && config.onComplete) {
|
|
7436
|
+
completionUpdates = await config.onComplete(context, finalLoopContext);
|
|
7437
|
+
}
|
|
7438
|
+
const output = {
|
|
7439
|
+
exitReason,
|
|
7440
|
+
iterations: iteration,
|
|
7441
|
+
previousResults,
|
|
7442
|
+
...completionUpdates
|
|
7443
|
+
};
|
|
7444
|
+
const state = {
|
|
7445
|
+
nodeId: node.id,
|
|
7446
|
+
status: exitReason === "error" ? "failed" : "completed",
|
|
7447
|
+
output,
|
|
7448
|
+
error: lastError,
|
|
7449
|
+
attempt: 1,
|
|
7450
|
+
startedAt: new Date(startTime),
|
|
7451
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
7452
|
+
};
|
|
7453
|
+
this.config.onNodeComplete?.(node.id, state);
|
|
7454
|
+
return {
|
|
7455
|
+
state,
|
|
7456
|
+
contextUpdates: {
|
|
7457
|
+
[node.id]: output,
|
|
7458
|
+
...completionUpdates
|
|
7459
|
+
},
|
|
7460
|
+
waiting: false
|
|
7461
|
+
};
|
|
7462
|
+
}
|
|
7463
|
+
/**
|
|
7464
|
+
* Parse duration string to milliseconds
|
|
7465
|
+
*/
|
|
7466
|
+
parseDuration(duration) {
|
|
7467
|
+
if (typeof duration === "number")
|
|
7468
|
+
return duration;
|
|
7469
|
+
const match = duration.match(/^(\d+)(ms|s|m|h|d)$/);
|
|
7470
|
+
if (!match)
|
|
7471
|
+
return 0;
|
|
7472
|
+
const value = parseInt(match[1], 10);
|
|
7473
|
+
const unit = match[2];
|
|
7474
|
+
switch (unit) {
|
|
7475
|
+
case "ms":
|
|
7476
|
+
return value;
|
|
7477
|
+
case "s":
|
|
7478
|
+
return value * 1e3;
|
|
7479
|
+
case "m":
|
|
7480
|
+
return value * 60 * 1e3;
|
|
7481
|
+
case "h":
|
|
7482
|
+
return value * 60 * 60 * 1e3;
|
|
7483
|
+
case "d":
|
|
7484
|
+
return value * 24 * 60 * 60 * 1e3;
|
|
7485
|
+
default:
|
|
7486
|
+
return 0;
|
|
7487
|
+
}
|
|
7488
|
+
}
|
|
7489
|
+
/**
|
|
7490
|
+
* Sleep for specified milliseconds
|
|
7491
|
+
*/
|
|
7492
|
+
sleep(ms) {
|
|
7493
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
7494
|
+
}
|
|
7098
7495
|
/**
|
|
7099
7496
|
* Execute a step node
|
|
7100
7497
|
*/
|
|
@@ -7489,6 +7886,12 @@ var CheckpointManager = class {
|
|
|
7489
7886
|
};
|
|
7490
7887
|
|
|
7491
7888
|
// src/ai/workflow/executor/step-executor.ts
|
|
7889
|
+
var DEFAULT_RETRY = {
|
|
7890
|
+
maxAttempts: 1,
|
|
7891
|
+
backoff: "exponential",
|
|
7892
|
+
initialDelay: 1e3,
|
|
7893
|
+
maxDelay: 3e4
|
|
7894
|
+
};
|
|
7492
7895
|
var DEFAULT_STEP_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
7493
7896
|
var StepExecutor = class {
|
|
7494
7897
|
constructor(config = {}) {
|
|
@@ -7498,7 +7901,7 @@ var StepExecutor = class {
|
|
|
7498
7901
|
};
|
|
7499
7902
|
}
|
|
7500
7903
|
/**
|
|
7501
|
-
* Execute a step node
|
|
7904
|
+
* Execute a step node with retry support
|
|
7502
7905
|
*/
|
|
7503
7906
|
async execute(node, context) {
|
|
7504
7907
|
const startTime = Date.now();
|
|
@@ -7508,30 +7911,96 @@ var StepExecutor = class {
|
|
|
7508
7911
|
`StepExecutor can only execute 'step' nodes, but node "${node.id}" has type '${config.type}'. This is likely a bug in the DAG executor routing.`
|
|
7509
7912
|
);
|
|
7510
7913
|
}
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7914
|
+
const retryConfig = { ...DEFAULT_RETRY, ...config.retry };
|
|
7915
|
+
const maxAttempts = retryConfig.maxAttempts ?? 1;
|
|
7916
|
+
let lastError;
|
|
7917
|
+
let attempt = 0;
|
|
7918
|
+
while (attempt < maxAttempts) {
|
|
7919
|
+
attempt++;
|
|
7920
|
+
try {
|
|
7921
|
+
const resolvedInput = await this.resolveInput(config.input, context);
|
|
7922
|
+
this.config.onStepStart?.(node.id, resolvedInput);
|
|
7923
|
+
const timeout = config.timeout ? parseDuration(config.timeout) : this.config.defaultTimeout;
|
|
7924
|
+
const output = await this.executeWithTimeout(
|
|
7925
|
+
() => this.executeStep(config, resolvedInput, context),
|
|
7926
|
+
timeout,
|
|
7927
|
+
node.id
|
|
7928
|
+
);
|
|
7929
|
+
this.config.onStepComplete?.(node.id, output);
|
|
7930
|
+
return {
|
|
7931
|
+
success: true,
|
|
7932
|
+
output,
|
|
7933
|
+
executionTime: Date.now() - startTime
|
|
7934
|
+
};
|
|
7935
|
+
} catch (error) {
|
|
7936
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
7937
|
+
const shouldRetry = attempt < maxAttempts && this.isRetryableError(lastError, retryConfig);
|
|
7938
|
+
if (shouldRetry) {
|
|
7939
|
+
const delay2 = this.calculateRetryDelay(attempt, retryConfig);
|
|
7940
|
+
await this.sleep(delay2);
|
|
7941
|
+
continue;
|
|
7942
|
+
}
|
|
7943
|
+
this.config.onStepError?.(node.id, lastError);
|
|
7944
|
+
return {
|
|
7945
|
+
success: false,
|
|
7946
|
+
error: lastError.message,
|
|
7947
|
+
executionTime: Date.now() - startTime
|
|
7948
|
+
};
|
|
7949
|
+
}
|
|
7950
|
+
}
|
|
7951
|
+
return {
|
|
7952
|
+
success: false,
|
|
7953
|
+
error: lastError?.message ?? "Unknown error",
|
|
7954
|
+
executionTime: Date.now() - startTime
|
|
7955
|
+
};
|
|
7956
|
+
}
|
|
7957
|
+
/**
|
|
7958
|
+
* Check if error is retryable
|
|
7959
|
+
*/
|
|
7960
|
+
isRetryableError(error, config) {
|
|
7961
|
+
if (config.retryIf) {
|
|
7962
|
+
return config.retryIf(error);
|
|
7963
|
+
}
|
|
7964
|
+
const retryablePatterns = [
|
|
7965
|
+
/timeout/i,
|
|
7966
|
+
/ECONNRESET/i,
|
|
7967
|
+
/ECONNREFUSED/i,
|
|
7968
|
+
/ETIMEDOUT/i,
|
|
7969
|
+
/rate limit/i,
|
|
7970
|
+
/429/,
|
|
7971
|
+
/503/,
|
|
7972
|
+
/502/
|
|
7973
|
+
];
|
|
7974
|
+
return retryablePatterns.some((pattern) => pattern.test(error.message));
|
|
7975
|
+
}
|
|
7976
|
+
/**
|
|
7977
|
+
* Calculate retry delay based on backoff strategy
|
|
7978
|
+
*/
|
|
7979
|
+
calculateRetryDelay(attempt, config) {
|
|
7980
|
+
const initialDelay = config.initialDelay ?? 1e3;
|
|
7981
|
+
const maxDelay = config.maxDelay ?? 3e4;
|
|
7982
|
+
let delay2;
|
|
7983
|
+
switch (config.backoff) {
|
|
7984
|
+
case "exponential":
|
|
7985
|
+
delay2 = initialDelay * Math.pow(2, attempt - 1);
|
|
7986
|
+
break;
|
|
7987
|
+
case "linear":
|
|
7988
|
+
delay2 = initialDelay * attempt;
|
|
7989
|
+
break;
|
|
7990
|
+
case "fixed":
|
|
7991
|
+
default:
|
|
7992
|
+
delay2 = initialDelay;
|
|
7993
|
+
break;
|
|
7534
7994
|
}
|
|
7995
|
+
const jitter = delay2 * 0.1 * (Math.random() * 2 - 1);
|
|
7996
|
+
delay2 = Math.min(delay2 + jitter, maxDelay);
|
|
7997
|
+
return Math.floor(delay2);
|
|
7998
|
+
}
|
|
7999
|
+
/**
|
|
8000
|
+
* Sleep for specified milliseconds
|
|
8001
|
+
*/
|
|
8002
|
+
sleep(ms) {
|
|
8003
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
7535
8004
|
}
|
|
7536
8005
|
/**
|
|
7537
8006
|
* Resolve step input from context
|
|
@@ -8341,7 +8810,35 @@ var WorkflowClient = class {
|
|
|
8341
8810
|
this.executor = new WorkflowExecutor({
|
|
8342
8811
|
backend: this.backend,
|
|
8343
8812
|
debug: this.debug,
|
|
8344
|
-
...config.executor
|
|
8813
|
+
...config.executor,
|
|
8814
|
+
onWaiting: async (run, nodeId) => {
|
|
8815
|
+
const nodeState = run.nodeStates[nodeId];
|
|
8816
|
+
if (!nodeState?.input) {
|
|
8817
|
+
if (this.debug) {
|
|
8818
|
+
console.log(`[WorkflowClient] No wait config found for node: ${nodeId}`);
|
|
8819
|
+
}
|
|
8820
|
+
return;
|
|
8821
|
+
}
|
|
8822
|
+
const input = nodeState.input;
|
|
8823
|
+
if (input.type !== "approval") {
|
|
8824
|
+
return;
|
|
8825
|
+
}
|
|
8826
|
+
const waitConfig = {
|
|
8827
|
+
type: "wait",
|
|
8828
|
+
waitType: "approval",
|
|
8829
|
+
message: input.message,
|
|
8830
|
+
payload: input.payload
|
|
8831
|
+
};
|
|
8832
|
+
try {
|
|
8833
|
+
await this.approvalManager.createApproval(run, nodeId, waitConfig, run.context);
|
|
8834
|
+
if (this.debug) {
|
|
8835
|
+
console.log(`[WorkflowClient] Created approval for node: ${nodeId}`);
|
|
8836
|
+
}
|
|
8837
|
+
} catch (error) {
|
|
8838
|
+
console.error(`[WorkflowClient] Failed to create approval:`, error);
|
|
8839
|
+
}
|
|
8840
|
+
config.executor?.onWaiting?.(run, nodeId);
|
|
8841
|
+
}
|
|
8345
8842
|
});
|
|
8346
8843
|
this.approvalManager = new ApprovalManager({
|
|
8347
8844
|
backend: this.backend,
|
|
@@ -8546,7 +9043,6 @@ export {
|
|
|
8546
9043
|
dynamicTool,
|
|
8547
9044
|
embed,
|
|
8548
9045
|
embedMany,
|
|
8549
|
-
experimental_createMCPClient,
|
|
8550
9046
|
experimental_generateImage,
|
|
8551
9047
|
experimental_generateSpeech,
|
|
8552
9048
|
experimental_transcribe,
|