veryfront 0.0.73 → 0.0.75
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 +3 -3
- package/dist/ai/components.js.map +2 -2
- package/dist/ai/dev.js +121 -18
- package/dist/ai/dev.js.map +2 -2
- package/dist/ai/index.js +733 -232
- 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 +8 -7
- package/dist/ai/react.js.map +2 -2
- package/dist/ai/workflow.js +439 -63
- package/dist/ai/workflow.js.map +4 -4
- package/dist/components.js +3959 -241
- package/dist/components.js.map +4 -4
- package/dist/config.js +379 -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 +160 -37
- package/dist/data.js.map +3 -3
- package/dist/fonts.d.ts +24 -0
- package/dist/fonts.js +68 -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 +4080 -315
- package/dist/index.js.map +4 -4
- package/dist/oauth/handlers.js.map +1 -1
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/providers.js.map +1 -1
- package/dist/router.d.ts +69 -0
- package/dist/router.js +57 -0
- package/dist/router.js.map +7 -0
- package/package.json +19 -2
- package/dist/cli.js +0 -107694
package/dist/ai/index.js
CHANGED
|
@@ -79,56 +79,158 @@ 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
|
+
if (boundContext) {
|
|
142
|
+
this.boundContext = boundContext;
|
|
143
|
+
}
|
|
95
144
|
}
|
|
145
|
+
boundContext = {};
|
|
96
146
|
setLevel(level) {
|
|
97
147
|
this.level = level;
|
|
98
148
|
}
|
|
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
|
config;
|
|
196
322
|
constructor(config) {
|
|
@@ -231,7 +357,17 @@ var BaseProvider = class {
|
|
|
231
357
|
}));
|
|
232
358
|
}
|
|
233
359
|
const data = await response.json();
|
|
234
|
-
|
|
360
|
+
const parseResult = OpenAICompletionResponseSchema.safeParse(data);
|
|
361
|
+
if (!parseResult.success) {
|
|
362
|
+
agentLogger.warn(`${this.name}: Invalid response structure`, {
|
|
363
|
+
errors: parseResult.error.flatten()
|
|
364
|
+
});
|
|
365
|
+
throw toError(createError({
|
|
366
|
+
type: "agent",
|
|
367
|
+
message: `${this.name}: Invalid response structure from provider`
|
|
368
|
+
}));
|
|
369
|
+
}
|
|
370
|
+
return this.transformResponse(parseResult.data);
|
|
235
371
|
}
|
|
236
372
|
/**
|
|
237
373
|
* Stream a completion
|
|
@@ -1931,6 +2067,9 @@ var veryfrontConfigSchema = z5.object({
|
|
|
1931
2067
|
}).partial().optional(),
|
|
1932
2068
|
router: z5.enum(["app", "pages"]).optional(),
|
|
1933
2069
|
defaultLayout: z5.string().optional(),
|
|
2070
|
+
layout: z5.string().optional(),
|
|
2071
|
+
provider: z5.string().optional(),
|
|
2072
|
+
app: z5.string().optional(),
|
|
1934
2073
|
theme: z5.object({ colors: z5.record(z5.string()).optional() }).partial().optional(),
|
|
1935
2074
|
build: z5.object({
|
|
1936
2075
|
outDir: z5.string().optional(),
|
|
@@ -2026,6 +2165,8 @@ var veryfrontConfigSchema = z5.object({
|
|
|
2026
2165
|
apiBaseUrl: z5.string().url(),
|
|
2027
2166
|
apiToken: z5.string(),
|
|
2028
2167
|
projectSlug: z5.string(),
|
|
2168
|
+
proxyMode: z5.boolean().optional(),
|
|
2169
|
+
productionMode: z5.boolean().optional(),
|
|
2029
2170
|
cache: z5.object({
|
|
2030
2171
|
enabled: z5.boolean().optional(),
|
|
2031
2172
|
ttl: z5.number().int().positive().optional(),
|
|
@@ -2087,6 +2228,9 @@ function findUnknownTopLevelKeys(input) {
|
|
|
2087
2228
|
"experimental",
|
|
2088
2229
|
"router",
|
|
2089
2230
|
"defaultLayout",
|
|
2231
|
+
"layout",
|
|
2232
|
+
"provider",
|
|
2233
|
+
"app",
|
|
2090
2234
|
"theme",
|
|
2091
2235
|
"build",
|
|
2092
2236
|
"cache",
|
|
@@ -2104,12 +2248,12 @@ function findUnknownTopLevelKeys(input) {
|
|
|
2104
2248
|
}
|
|
2105
2249
|
|
|
2106
2250
|
// src/core/config/loader.ts
|
|
2107
|
-
import { join } from "node:path";
|
|
2251
|
+
import { dirname, join } from "node:path";
|
|
2108
2252
|
|
|
2109
2253
|
// deno.json
|
|
2110
2254
|
var deno_default = {
|
|
2111
2255
|
name: "veryfront",
|
|
2112
|
-
version: "0.0.
|
|
2256
|
+
version: "0.0.75",
|
|
2113
2257
|
nodeModulesDir: "auto",
|
|
2114
2258
|
exclude: [
|
|
2115
2259
|
"npm/",
|
|
@@ -2141,7 +2285,11 @@ var deno_default = {
|
|
|
2141
2285
|
"./oauth": "./src/core/oauth/index.ts",
|
|
2142
2286
|
"./oauth/providers": "./src/core/oauth/providers/index.ts",
|
|
2143
2287
|
"./oauth/handlers": "./src/core/oauth/handlers/index.ts",
|
|
2144
|
-
"./oauth/token-store": "./src/core/oauth/token-store/index.ts"
|
|
2288
|
+
"./oauth/token-store": "./src/core/oauth/token-store/index.ts",
|
|
2289
|
+
"./head": "./src/exports/head.ts",
|
|
2290
|
+
"./router": "./src/exports/router.ts",
|
|
2291
|
+
"./context": "./src/exports/context.ts",
|
|
2292
|
+
"./fonts": "./src/exports/fonts.ts"
|
|
2145
2293
|
},
|
|
2146
2294
|
imports: {
|
|
2147
2295
|
"@veryfront": "./src/index.ts",
|
|
@@ -2194,12 +2342,12 @@ var deno_default = {
|
|
|
2194
2342
|
csstype: "https://esm.sh/csstype@3.2.3",
|
|
2195
2343
|
"@types/react": "https://esm.sh/@types/react@18.3.27?deps=csstype@3.2.3",
|
|
2196
2344
|
"@types/react-dom": "https://esm.sh/@types/react-dom@18.3.7?deps=csstype@3.2.3",
|
|
2197
|
-
react: "
|
|
2198
|
-
"react-dom": "
|
|
2199
|
-
"react-dom/server": "
|
|
2200
|
-
"react-dom/client": "
|
|
2201
|
-
"react/jsx-runtime": "
|
|
2202
|
-
"react/jsx-dev-runtime": "
|
|
2345
|
+
react: "npm:react@18.3.1",
|
|
2346
|
+
"react-dom": "npm:react-dom@18.3.1",
|
|
2347
|
+
"react-dom/server": "npm:react-dom@18.3.1/server",
|
|
2348
|
+
"react-dom/client": "npm:react-dom@18.3.1/client",
|
|
2349
|
+
"react/jsx-runtime": "npm:react@18.3.1/jsx-runtime",
|
|
2350
|
+
"react/jsx-dev-runtime": "npm:react@18.3.1/jsx-dev-runtime",
|
|
2203
2351
|
"@mdx-js/mdx": "npm:@mdx-js/mdx@3.0.0",
|
|
2204
2352
|
"@mdx-js/react": "npm:@mdx-js/react@3.0.0",
|
|
2205
2353
|
"unist-util-visit": "npm:unist-util-visit@5.0.0",
|
|
@@ -2209,27 +2357,36 @@ var deno_default = {
|
|
|
2209
2357
|
"remark-frontmatter": "npm:remark-frontmatter@5.0.0",
|
|
2210
2358
|
"rehype-highlight": "npm:rehype-highlight@7.0.2",
|
|
2211
2359
|
"rehype-slug": "npm:rehype-slug@6.0.0",
|
|
2212
|
-
esbuild: "
|
|
2213
|
-
"esbuild/mod.js": "
|
|
2360
|
+
esbuild: "npm:esbuild@0.20.2",
|
|
2361
|
+
"esbuild/mod.js": "npm:esbuild@0.20.2",
|
|
2214
2362
|
"es-module-lexer": "npm:es-module-lexer@1.5.0",
|
|
2215
|
-
zod: "npm:zod@3.
|
|
2363
|
+
zod: "npm:zod@3.25.76",
|
|
2216
2364
|
"mime-types": "npm:mime-types@2.1.35",
|
|
2217
2365
|
mdast: "npm:@types/mdast@4.0.3",
|
|
2218
2366
|
hast: "npm:@types/hast@3.0.3",
|
|
2219
2367
|
unist: "npm:@types/unist@3.0.2",
|
|
2220
2368
|
unified: "npm:unified@11.0.5",
|
|
2221
|
-
ai: "
|
|
2222
|
-
"ai/react": "
|
|
2223
|
-
"@ai-sdk/react": "
|
|
2369
|
+
ai: "npm:ai@5.0.76",
|
|
2370
|
+
"ai/react": "npm:@ai-sdk/react@2.0.1",
|
|
2371
|
+
"@ai-sdk/react": "npm:@ai-sdk/react@2.0.1",
|
|
2224
2372
|
"@ai-sdk/openai": "https://esm.sh/@ai-sdk/openai@2.0.1",
|
|
2225
2373
|
"@ai-sdk/anthropic": "https://esm.sh/@ai-sdk/anthropic@2.0.1",
|
|
2226
2374
|
unocss: "https://esm.sh/unocss@0.59.0",
|
|
2227
2375
|
"@unocss/core": "https://esm.sh/@unocss/core@0.59.0",
|
|
2228
2376
|
"@unocss/preset-wind": "https://esm.sh/@unocss/preset-wind@0.59.0",
|
|
2377
|
+
"next-themes": "npm:next-themes@0.4",
|
|
2229
2378
|
redis: "npm:redis",
|
|
2230
2379
|
pg: "npm:pg",
|
|
2231
2380
|
"@opentelemetry/api": "npm:@opentelemetry/api@1",
|
|
2232
|
-
"@opentelemetry/core": "npm:@opentelemetry/core@1"
|
|
2381
|
+
"@opentelemetry/core": "npm:@opentelemetry/core@1",
|
|
2382
|
+
"@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@1",
|
|
2383
|
+
"@opentelemetry/exporter-trace-otlp-http": "npm:@opentelemetry/exporter-trace-otlp-http@0.57",
|
|
2384
|
+
"@opentelemetry/resources": "npm:@opentelemetry/resources@1",
|
|
2385
|
+
"@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@1",
|
|
2386
|
+
"@babel/parser": "npm:@babel/parser@7.26.3",
|
|
2387
|
+
"@babel/traverse": "npm:@babel/traverse@7.26.3",
|
|
2388
|
+
"@babel/generator": "npm:@babel/generator@7.26.3",
|
|
2389
|
+
"@babel/types": "npm:@babel/types@7.26.3"
|
|
2233
2390
|
},
|
|
2234
2391
|
compilerOptions: {
|
|
2235
2392
|
jsx: "react-jsx",
|
|
@@ -2237,7 +2394,7 @@ var deno_default = {
|
|
|
2237
2394
|
strict: true,
|
|
2238
2395
|
noImplicitAny: true,
|
|
2239
2396
|
noUncheckedIndexedAccess: true,
|
|
2240
|
-
types: [],
|
|
2397
|
+
types: ["npm:@types/react@18"],
|
|
2241
2398
|
lib: [
|
|
2242
2399
|
"deno.window",
|
|
2243
2400
|
"dom",
|
|
@@ -2252,9 +2409,9 @@ var deno_default = {
|
|
|
2252
2409
|
build: "deno compile --allow-all --output ../../bin/veryfront src/cli/main.ts",
|
|
2253
2410
|
"build:npm": "deno run -A scripts/build-npm.ts",
|
|
2254
2411
|
release: "deno run -A scripts/release.ts",
|
|
2255
|
-
test: "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --unstable-worker-options --unstable-net",
|
|
2256
|
-
"test:unit": "DENO_JOBS=1 deno test --parallel --allow-all --v8-flags=--max-old-space-size=8192 --ignore=tests --unstable-worker-options --unstable-net",
|
|
2257
|
-
"test:integration": "DENO_JOBS=1 deno test --parallel --fail-fast --allow-all tests --unstable-worker-options --unstable-net",
|
|
2412
|
+
test: "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --unstable-worker-options --unstable-net",
|
|
2413
|
+
"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",
|
|
2414
|
+
"test:integration": "VF_DISABLE_LRU_INTERVAL=1 DENO_JOBS=1 deno test --parallel --fail-fast --allow-all tests --unstable-worker-options --unstable-net",
|
|
2258
2415
|
"test:coverage": "rm -rf coverage && DENO_JOBS=1 deno test --parallel --fail-fast --allow-all --coverage=coverage --unstable-worker-options --unstable-net || exit 1",
|
|
2259
2416
|
"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",
|
|
2260
2417
|
"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",
|
|
@@ -2316,6 +2473,7 @@ var deno_default = {
|
|
|
2316
2473
|
|
|
2317
2474
|
// src/core/utils/version.ts
|
|
2318
2475
|
var VERSION = getEnv("VERYFRONT_VERSION") || (typeof deno_default.version === "string" ? deno_default.version : "0.0.0");
|
|
2476
|
+
var SERVER_START_TIME = Date.now();
|
|
2319
2477
|
|
|
2320
2478
|
// src/core/utils/constants/cdn.ts
|
|
2321
2479
|
var ESM_CDN_BASE = "https://esm.sh";
|
|
@@ -2431,6 +2589,164 @@ var DEV_SERVER_ENDPOINTS = {
|
|
|
2431
2589
|
ERROR_OVERLAY: INTERNAL_ENDPOINTS.ERROR_OVERLAY
|
|
2432
2590
|
};
|
|
2433
2591
|
|
|
2592
|
+
// src/platform/compat/fs.ts
|
|
2593
|
+
var NodeFileSystem = class {
|
|
2594
|
+
fs = null;
|
|
2595
|
+
os = null;
|
|
2596
|
+
path = null;
|
|
2597
|
+
initialized = false;
|
|
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
|
+
|
|
2434
2750
|
// src/core/config/loader.ts
|
|
2435
2751
|
function getDefaultImportMapForConfig() {
|
|
2436
2752
|
return { imports: getReactImportMap(REACT_DEFAULT_VERSION) };
|
|
@@ -2567,7 +2883,62 @@ var ConfigValidationError = class extends Error {
|
|
|
2567
2883
|
this.name = "ConfigValidationError";
|
|
2568
2884
|
}
|
|
2569
2885
|
};
|
|
2570
|
-
|
|
2886
|
+
function isVirtualFilesystem(adapter) {
|
|
2887
|
+
const wrappedAdapter = adapter?.fs?.fsAdapter;
|
|
2888
|
+
const adapterName = wrappedAdapter?.constructor?.name;
|
|
2889
|
+
return adapterName === "VeryfrontFSAdapter" || adapterName === "MultiProjectFSAdapter";
|
|
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
|
+
}
|
|
2571
2942
|
try {
|
|
2572
2943
|
const configUrl = `file://${configPath}?t=${Date.now()}-${crypto.randomUUID()}`;
|
|
2573
2944
|
const configModule = await import(configUrl);
|
|
@@ -2603,7 +2974,7 @@ async function getConfig(projectDir, adapter) {
|
|
|
2603
2974
|
if (!exists)
|
|
2604
2975
|
continue;
|
|
2605
2976
|
try {
|
|
2606
|
-
const merged = await loadAndMergeConfig(configPath, projectDir);
|
|
2977
|
+
const merged = await loadAndMergeConfig(configPath, projectDir, adapter);
|
|
2607
2978
|
if (merged)
|
|
2608
2979
|
return merged;
|
|
2609
2980
|
} catch (error) {
|
|
@@ -2776,164 +3147,6 @@ function createMockAdapter() {
|
|
|
2776
3147
|
};
|
|
2777
3148
|
}
|
|
2778
3149
|
|
|
2779
|
-
// src/platform/compat/fs.ts
|
|
2780
|
-
var NodeFileSystem = class {
|
|
2781
|
-
fs = null;
|
|
2782
|
-
os = null;
|
|
2783
|
-
path = null;
|
|
2784
|
-
initialized = false;
|
|
2785
|
-
async ensureInitialized() {
|
|
2786
|
-
if (this.initialized)
|
|
2787
|
-
return;
|
|
2788
|
-
if (!isNode) {
|
|
2789
|
-
throw toError(createError({
|
|
2790
|
-
type: "not_supported",
|
|
2791
|
-
message: "Node.js fs modules not available",
|
|
2792
|
-
feature: "Node.js"
|
|
2793
|
-
}));
|
|
2794
|
-
}
|
|
2795
|
-
const [fsModule, osModule, pathModule] = await Promise.all([
|
|
2796
|
-
import("node:fs/promises"),
|
|
2797
|
-
import("node:os"),
|
|
2798
|
-
import("node:path")
|
|
2799
|
-
]);
|
|
2800
|
-
this.fs = fsModule;
|
|
2801
|
-
this.os = osModule;
|
|
2802
|
-
this.path = pathModule;
|
|
2803
|
-
this.initialized = true;
|
|
2804
|
-
}
|
|
2805
|
-
async readTextFile(path) {
|
|
2806
|
-
await this.ensureInitialized();
|
|
2807
|
-
return await this.fs.readFile(path, { encoding: "utf8" });
|
|
2808
|
-
}
|
|
2809
|
-
async readFile(path) {
|
|
2810
|
-
await this.ensureInitialized();
|
|
2811
|
-
return await this.fs.readFile(path);
|
|
2812
|
-
}
|
|
2813
|
-
async writeTextFile(path, data) {
|
|
2814
|
-
await this.ensureInitialized();
|
|
2815
|
-
await this.fs.writeFile(path, data, { encoding: "utf8" });
|
|
2816
|
-
}
|
|
2817
|
-
async writeFile(path, data) {
|
|
2818
|
-
await this.ensureInitialized();
|
|
2819
|
-
await this.fs.writeFile(path, data);
|
|
2820
|
-
}
|
|
2821
|
-
async exists(path) {
|
|
2822
|
-
await this.ensureInitialized();
|
|
2823
|
-
try {
|
|
2824
|
-
await this.fs.access(path);
|
|
2825
|
-
return true;
|
|
2826
|
-
} catch (error) {
|
|
2827
|
-
if (error.code === "ENOENT") {
|
|
2828
|
-
return false;
|
|
2829
|
-
}
|
|
2830
|
-
throw error;
|
|
2831
|
-
}
|
|
2832
|
-
}
|
|
2833
|
-
async stat(path) {
|
|
2834
|
-
await this.ensureInitialized();
|
|
2835
|
-
const stat = await this.fs.stat(path);
|
|
2836
|
-
return {
|
|
2837
|
-
isFile: stat.isFile(),
|
|
2838
|
-
isDirectory: stat.isDirectory(),
|
|
2839
|
-
isSymlink: stat.isSymbolicLink(),
|
|
2840
|
-
size: stat.size,
|
|
2841
|
-
mtime: stat.mtime
|
|
2842
|
-
};
|
|
2843
|
-
}
|
|
2844
|
-
async mkdir(path, options) {
|
|
2845
|
-
await this.ensureInitialized();
|
|
2846
|
-
await this.fs.mkdir(path, { recursive: options?.recursive ?? false });
|
|
2847
|
-
}
|
|
2848
|
-
async *readDir(path) {
|
|
2849
|
-
await this.ensureInitialized();
|
|
2850
|
-
const entries = await this.fs.readdir(path, { withFileTypes: true });
|
|
2851
|
-
for (const entry of entries) {
|
|
2852
|
-
yield {
|
|
2853
|
-
name: entry.name,
|
|
2854
|
-
isFile: entry.isFile(),
|
|
2855
|
-
isDirectory: entry.isDirectory()
|
|
2856
|
-
};
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
async remove(path, options) {
|
|
2860
|
-
await this.ensureInitialized();
|
|
2861
|
-
await this.fs.rm(path, {
|
|
2862
|
-
recursive: options?.recursive ?? false,
|
|
2863
|
-
force: options?.recursive ?? false
|
|
2864
|
-
});
|
|
2865
|
-
}
|
|
2866
|
-
async makeTempDir(options) {
|
|
2867
|
-
await this.ensureInitialized();
|
|
2868
|
-
const tempDir = this.path.join(
|
|
2869
|
-
this.os.tmpdir(),
|
|
2870
|
-
`${options?.prefix ?? "tmp-"}${Math.random().toString(36).substring(2, 8)}`
|
|
2871
|
-
);
|
|
2872
|
-
await this.fs.mkdir(tempDir, { recursive: true });
|
|
2873
|
-
return tempDir;
|
|
2874
|
-
}
|
|
2875
|
-
};
|
|
2876
|
-
var DenoFileSystem = class {
|
|
2877
|
-
async readTextFile(path) {
|
|
2878
|
-
return await Deno.readTextFile(path);
|
|
2879
|
-
}
|
|
2880
|
-
async readFile(path) {
|
|
2881
|
-
return await Deno.readFile(path);
|
|
2882
|
-
}
|
|
2883
|
-
async writeTextFile(path, data) {
|
|
2884
|
-
await Deno.writeTextFile(path, data);
|
|
2885
|
-
}
|
|
2886
|
-
async writeFile(path, data) {
|
|
2887
|
-
await Deno.writeFile(path, data);
|
|
2888
|
-
}
|
|
2889
|
-
async exists(path) {
|
|
2890
|
-
try {
|
|
2891
|
-
await Deno.stat(path);
|
|
2892
|
-
return true;
|
|
2893
|
-
} catch (error) {
|
|
2894
|
-
if (error instanceof Deno.errors.NotFound) {
|
|
2895
|
-
return false;
|
|
2896
|
-
}
|
|
2897
|
-
throw error;
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
|
-
async stat(path) {
|
|
2901
|
-
const stat = await Deno.stat(path);
|
|
2902
|
-
return {
|
|
2903
|
-
isFile: stat.isFile,
|
|
2904
|
-
isDirectory: stat.isDirectory,
|
|
2905
|
-
isSymlink: stat.isSymlink,
|
|
2906
|
-
size: stat.size,
|
|
2907
|
-
mtime: stat.mtime
|
|
2908
|
-
};
|
|
2909
|
-
}
|
|
2910
|
-
async mkdir(path, options) {
|
|
2911
|
-
await Deno.mkdir(path, { recursive: options?.recursive ?? false });
|
|
2912
|
-
}
|
|
2913
|
-
async *readDir(path) {
|
|
2914
|
-
for await (const entry of Deno.readDir(path)) {
|
|
2915
|
-
yield {
|
|
2916
|
-
name: entry.name,
|
|
2917
|
-
isFile: entry.isFile,
|
|
2918
|
-
isDirectory: entry.isDirectory
|
|
2919
|
-
};
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
async remove(path, options) {
|
|
2923
|
-
await Deno.remove(path, { recursive: options?.recursive ?? false });
|
|
2924
|
-
}
|
|
2925
|
-
async makeTempDir(options) {
|
|
2926
|
-
return await Deno.makeTempDir({ prefix: options?.prefix });
|
|
2927
|
-
}
|
|
2928
|
-
};
|
|
2929
|
-
function createFileSystem() {
|
|
2930
|
-
if (isDeno) {
|
|
2931
|
-
return new DenoFileSystem();
|
|
2932
|
-
} else {
|
|
2933
|
-
return new NodeFileSystem();
|
|
2934
|
-
}
|
|
2935
|
-
}
|
|
2936
|
-
|
|
2937
3150
|
// src/platform/compat/path-helper.ts
|
|
2938
3151
|
import nodePath from "node:path";
|
|
2939
3152
|
var pathMod = null;
|
|
@@ -2949,7 +3162,7 @@ function getPathMod() {
|
|
|
2949
3162
|
return pathMod;
|
|
2950
3163
|
return nodePath;
|
|
2951
3164
|
}
|
|
2952
|
-
var
|
|
3165
|
+
var dirname2 = (path) => getPathMod().dirname(path);
|
|
2953
3166
|
var join2 = (...paths) => getPathMod().join(...paths);
|
|
2954
3167
|
var resolve = (...paths) => getPathMod().resolve(...paths);
|
|
2955
3168
|
var extname = (path) => getPathMod().extname(path);
|
|
@@ -2996,7 +3209,7 @@ function createFsAdapterPlugin(fsAdapter) {
|
|
|
2996
3209
|
build.onResolve(
|
|
2997
3210
|
{ filter: /^\.\.?\// },
|
|
2998
3211
|
async (args) => {
|
|
2999
|
-
const importerDir = args.importer ?
|
|
3212
|
+
const importerDir = args.importer ? dirname2(args.importer) : args.resolveDir;
|
|
3000
3213
|
const basePath = resolve(importerDir, args.path);
|
|
3001
3214
|
const resolvedPath = await resolveWithExtensions(basePath);
|
|
3002
3215
|
if (resolvedPath) {
|
|
@@ -3023,7 +3236,7 @@ function createFsAdapterPlugin(fsAdapter) {
|
|
|
3023
3236
|
contents: content,
|
|
3024
3237
|
loader,
|
|
3025
3238
|
// Set resolveDir for nested imports from this file
|
|
3026
|
-
resolveDir:
|
|
3239
|
+
resolveDir: dirname2(args.path)
|
|
3027
3240
|
};
|
|
3028
3241
|
} catch (error) {
|
|
3029
3242
|
return {
|
|
@@ -3058,7 +3271,7 @@ async function importModule(file, context) {
|
|
|
3058
3271
|
const isJsx = filePath.endsWith(".jsx");
|
|
3059
3272
|
const loader = isTsx ? "tsx" : isJsx ? "jsx" : filePath.endsWith(".ts") ? "ts" : "js";
|
|
3060
3273
|
const { build } = await import("esbuild");
|
|
3061
|
-
const fileDir =
|
|
3274
|
+
const fileDir = dirname2(filePath);
|
|
3062
3275
|
const relativeImports = [];
|
|
3063
3276
|
if (isDeno) {
|
|
3064
3277
|
const relativeImportPattern = /from\s+["'](\.\.[^"']+)["']/g;
|
|
@@ -3812,6 +4025,9 @@ var InMemoryBundleManifestStore = class {
|
|
|
3812
4025
|
};
|
|
3813
4026
|
var manifestStore = new InMemoryBundleManifestStore();
|
|
3814
4027
|
|
|
4028
|
+
// src/core/utils/perf-timer.ts
|
|
4029
|
+
var enabled = typeof process !== "undefined" ? process.env?.VERYFRONT_PERF === "1" : typeof Deno !== "undefined" ? Deno.env.get("VERYFRONT_PERF") === "1" : false;
|
|
4030
|
+
|
|
3815
4031
|
// src/observability/tracing/config.ts
|
|
3816
4032
|
var DEFAULT_CONFIG2 = {
|
|
3817
4033
|
enabled: false,
|
|
@@ -4106,7 +4322,27 @@ async function withSpan(name, fn, options = {}) {
|
|
|
4106
4322
|
);
|
|
4107
4323
|
}
|
|
4108
4324
|
|
|
4109
|
-
// src/ai/
|
|
4325
|
+
// src/ai/config/defaults.ts
|
|
4326
|
+
var AGENT_DEFAULTS = {
|
|
4327
|
+
/** Maximum tokens for completion */
|
|
4328
|
+
maxTokens: 4096,
|
|
4329
|
+
/** Default temperature for generation */
|
|
4330
|
+
temperature: 0.7,
|
|
4331
|
+
/** Maximum agent loop steps */
|
|
4332
|
+
maxSteps: 20,
|
|
4333
|
+
/** Default memory type */
|
|
4334
|
+
memoryType: "conversation",
|
|
4335
|
+
/** Default memory max tokens */
|
|
4336
|
+
memoryMaxTokens: 4e3
|
|
4337
|
+
};
|
|
4338
|
+
var STREAMING_DEFAULTS = {
|
|
4339
|
+
/** Maximum buffer size for streaming (1MB) */
|
|
4340
|
+
maxBufferSize: 1024 * 1024,
|
|
4341
|
+
/** Chunk size for stream processing */
|
|
4342
|
+
chunkSize: 16384
|
|
4343
|
+
};
|
|
4344
|
+
|
|
4345
|
+
// src/ai/agent/streaming/stream-events.ts
|
|
4110
4346
|
import { z as z6 } from "zod";
|
|
4111
4347
|
var AgentStreamEventSchema = z6.discriminatedUnion("type", [
|
|
4112
4348
|
z6.object({
|
|
@@ -4146,8 +4382,8 @@ var AgentStreamEventSchema = z6.discriminatedUnion("type", [
|
|
|
4146
4382
|
})
|
|
4147
4383
|
})
|
|
4148
4384
|
]);
|
|
4149
|
-
|
|
4150
|
-
|
|
4385
|
+
|
|
4386
|
+
// src/ai/agent/message-converter.ts
|
|
4151
4387
|
function convertMessageToProvider(msg) {
|
|
4152
4388
|
const content = getTextFromParts(msg.parts);
|
|
4153
4389
|
const providerMsg = {
|
|
@@ -4177,6 +4413,11 @@ function convertMessageToProvider(msg) {
|
|
|
4177
4413
|
}
|
|
4178
4414
|
return providerMsg;
|
|
4179
4415
|
}
|
|
4416
|
+
|
|
4417
|
+
// src/ai/agent/runtime.ts
|
|
4418
|
+
var DEFAULT_MAX_TOKENS = AGENT_DEFAULTS.maxTokens;
|
|
4419
|
+
var DEFAULT_TEMPERATURE = AGENT_DEFAULTS.temperature;
|
|
4420
|
+
var MAX_STREAM_BUFFER_SIZE = STREAMING_DEFAULTS.maxBufferSize;
|
|
4180
4421
|
var AgentRuntime = class {
|
|
4181
4422
|
id;
|
|
4182
4423
|
config;
|
|
@@ -4610,6 +4851,10 @@ var AgentRuntime = class {
|
|
|
4610
4851
|
if (done)
|
|
4611
4852
|
break;
|
|
4612
4853
|
partial += decoder.decode(value, { stream: true });
|
|
4854
|
+
if (partial.length > MAX_STREAM_BUFFER_SIZE) {
|
|
4855
|
+
serverLogger.warn("[AGENT] Stream buffer exceeded max size, truncating");
|
|
4856
|
+
partial = partial.slice(-MAX_STREAM_BUFFER_SIZE / 2);
|
|
4857
|
+
}
|
|
4613
4858
|
const segments = partial.split("\n");
|
|
4614
4859
|
partial = segments.pop() ?? "";
|
|
4615
4860
|
const lines = segments.filter((line) => line.trim());
|
|
@@ -6944,9 +7189,16 @@ var DAGExecutor = class {
|
|
|
6944
7189
|
context,
|
|
6945
7190
|
nodeStates
|
|
6946
7191
|
);
|
|
7192
|
+
case "loop":
|
|
7193
|
+
return await this.executeLoopNode(
|
|
7194
|
+
node,
|
|
7195
|
+
config,
|
|
7196
|
+
context,
|
|
7197
|
+
nodeStates
|
|
7198
|
+
);
|
|
6947
7199
|
default:
|
|
6948
7200
|
throw new Error(
|
|
6949
|
-
`Unknown node type "${config.type}" for node "${node.id}". Valid types are: step, parallel, map, branch, wait, subWorkflow`
|
|
7201
|
+
`Unknown node type "${config.type}" for node "${node.id}". Valid types are: step, parallel, map, branch, wait, subWorkflow, loop`
|
|
6950
7202
|
);
|
|
6951
7203
|
}
|
|
6952
7204
|
}
|
|
@@ -7104,6 +7356,155 @@ var DAGExecutor = class {
|
|
|
7104
7356
|
waiting: result.waiting
|
|
7105
7357
|
};
|
|
7106
7358
|
}
|
|
7359
|
+
/**
|
|
7360
|
+
* Execute a loop node
|
|
7361
|
+
*/
|
|
7362
|
+
async executeLoopNode(node, config, context, nodeStates) {
|
|
7363
|
+
const startTime = Date.now();
|
|
7364
|
+
const previousResults = [];
|
|
7365
|
+
let iteration = 0;
|
|
7366
|
+
let exitReason = "condition";
|
|
7367
|
+
let lastError;
|
|
7368
|
+
const existingLoopState = context[`${node.id}_loop_state`];
|
|
7369
|
+
if (existingLoopState) {
|
|
7370
|
+
iteration = existingLoopState.iteration;
|
|
7371
|
+
previousResults.push(...existingLoopState.previousResults);
|
|
7372
|
+
}
|
|
7373
|
+
while (iteration < config.maxIterations) {
|
|
7374
|
+
const loopContext = {
|
|
7375
|
+
iteration,
|
|
7376
|
+
totalIterations: iteration,
|
|
7377
|
+
previousResults: [...previousResults],
|
|
7378
|
+
isFirstIteration: iteration === 0,
|
|
7379
|
+
isLastAllowedIteration: iteration === config.maxIterations - 1
|
|
7380
|
+
};
|
|
7381
|
+
const shouldContinue = await config.while(context, loopContext);
|
|
7382
|
+
if (!shouldContinue) {
|
|
7383
|
+
exitReason = "condition";
|
|
7384
|
+
break;
|
|
7385
|
+
}
|
|
7386
|
+
const steps = typeof config.steps === "function" ? config.steps(context, loopContext) : config.steps;
|
|
7387
|
+
const result = await this.execute(steps, {
|
|
7388
|
+
id: `${node.id}_iter_${iteration}`,
|
|
7389
|
+
workflowId: "",
|
|
7390
|
+
status: "running",
|
|
7391
|
+
input: context.input,
|
|
7392
|
+
nodeStates: {},
|
|
7393
|
+
currentNodes: [],
|
|
7394
|
+
context: { ...context, _loop: loopContext },
|
|
7395
|
+
checkpoints: [],
|
|
7396
|
+
pendingApprovals: [],
|
|
7397
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
7398
|
+
});
|
|
7399
|
+
if (result.waiting) {
|
|
7400
|
+
Object.assign(nodeStates, result.nodeStates);
|
|
7401
|
+
const state2 = {
|
|
7402
|
+
nodeId: node.id,
|
|
7403
|
+
status: "running",
|
|
7404
|
+
output: {
|
|
7405
|
+
iteration,
|
|
7406
|
+
waiting: true,
|
|
7407
|
+
previousResults
|
|
7408
|
+
},
|
|
7409
|
+
attempt: 1,
|
|
7410
|
+
startedAt: new Date(startTime)
|
|
7411
|
+
};
|
|
7412
|
+
return {
|
|
7413
|
+
state: state2,
|
|
7414
|
+
contextUpdates: {
|
|
7415
|
+
...result.context,
|
|
7416
|
+
[`${node.id}_loop_state`]: { iteration, previousResults }
|
|
7417
|
+
},
|
|
7418
|
+
waiting: true
|
|
7419
|
+
};
|
|
7420
|
+
}
|
|
7421
|
+
if (result.error) {
|
|
7422
|
+
lastError = result.error;
|
|
7423
|
+
exitReason = "error";
|
|
7424
|
+
break;
|
|
7425
|
+
}
|
|
7426
|
+
previousResults.push(result.context);
|
|
7427
|
+
Object.assign(context, result.context);
|
|
7428
|
+
Object.assign(nodeStates, result.nodeStates);
|
|
7429
|
+
if (config.delay && iteration < config.maxIterations - 1) {
|
|
7430
|
+
const delayMs = typeof config.delay === "number" ? config.delay : this.parseDuration(config.delay);
|
|
7431
|
+
await this.sleep(delayMs);
|
|
7432
|
+
}
|
|
7433
|
+
iteration++;
|
|
7434
|
+
}
|
|
7435
|
+
if (iteration >= config.maxIterations && exitReason !== "condition") {
|
|
7436
|
+
exitReason = "maxIterations";
|
|
7437
|
+
}
|
|
7438
|
+
const finalLoopContext = {
|
|
7439
|
+
iteration,
|
|
7440
|
+
totalIterations: iteration,
|
|
7441
|
+
previousResults,
|
|
7442
|
+
isFirstIteration: false,
|
|
7443
|
+
isLastAllowedIteration: true
|
|
7444
|
+
};
|
|
7445
|
+
let completionUpdates = {};
|
|
7446
|
+
if (exitReason === "maxIterations" && config.onMaxIterations) {
|
|
7447
|
+
completionUpdates = await config.onMaxIterations(context, finalLoopContext);
|
|
7448
|
+
} else if (exitReason === "condition" && config.onComplete) {
|
|
7449
|
+
completionUpdates = await config.onComplete(context, finalLoopContext);
|
|
7450
|
+
}
|
|
7451
|
+
const output = {
|
|
7452
|
+
exitReason,
|
|
7453
|
+
iterations: iteration,
|
|
7454
|
+
previousResults,
|
|
7455
|
+
...completionUpdates
|
|
7456
|
+
};
|
|
7457
|
+
const state = {
|
|
7458
|
+
nodeId: node.id,
|
|
7459
|
+
status: exitReason === "error" ? "failed" : "completed",
|
|
7460
|
+
output,
|
|
7461
|
+
error: lastError,
|
|
7462
|
+
attempt: 1,
|
|
7463
|
+
startedAt: new Date(startTime),
|
|
7464
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
7465
|
+
};
|
|
7466
|
+
this.config.onNodeComplete?.(node.id, state);
|
|
7467
|
+
return {
|
|
7468
|
+
state,
|
|
7469
|
+
contextUpdates: {
|
|
7470
|
+
[node.id]: output,
|
|
7471
|
+
...completionUpdates
|
|
7472
|
+
},
|
|
7473
|
+
waiting: false
|
|
7474
|
+
};
|
|
7475
|
+
}
|
|
7476
|
+
/**
|
|
7477
|
+
* Parse duration string to milliseconds
|
|
7478
|
+
*/
|
|
7479
|
+
parseDuration(duration) {
|
|
7480
|
+
if (typeof duration === "number")
|
|
7481
|
+
return duration;
|
|
7482
|
+
const match = duration.match(/^(\d+)(ms|s|m|h|d)$/);
|
|
7483
|
+
if (!match)
|
|
7484
|
+
return 0;
|
|
7485
|
+
const value = parseInt(match[1], 10);
|
|
7486
|
+
const unit = match[2];
|
|
7487
|
+
switch (unit) {
|
|
7488
|
+
case "ms":
|
|
7489
|
+
return value;
|
|
7490
|
+
case "s":
|
|
7491
|
+
return value * 1e3;
|
|
7492
|
+
case "m":
|
|
7493
|
+
return value * 60 * 1e3;
|
|
7494
|
+
case "h":
|
|
7495
|
+
return value * 60 * 60 * 1e3;
|
|
7496
|
+
case "d":
|
|
7497
|
+
return value * 24 * 60 * 60 * 1e3;
|
|
7498
|
+
default:
|
|
7499
|
+
return 0;
|
|
7500
|
+
}
|
|
7501
|
+
}
|
|
7502
|
+
/**
|
|
7503
|
+
* Sleep for specified milliseconds
|
|
7504
|
+
*/
|
|
7505
|
+
sleep(ms) {
|
|
7506
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
7507
|
+
}
|
|
7107
7508
|
/**
|
|
7108
7509
|
* Execute a step node
|
|
7109
7510
|
*/
|
|
@@ -7499,6 +7900,12 @@ var CheckpointManager = class {
|
|
|
7499
7900
|
};
|
|
7500
7901
|
|
|
7501
7902
|
// src/ai/workflow/executor/step-executor.ts
|
|
7903
|
+
var DEFAULT_RETRY = {
|
|
7904
|
+
maxAttempts: 1,
|
|
7905
|
+
backoff: "exponential",
|
|
7906
|
+
initialDelay: 1e3,
|
|
7907
|
+
maxDelay: 3e4
|
|
7908
|
+
};
|
|
7502
7909
|
var DEFAULT_STEP_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
7503
7910
|
var StepExecutor = class {
|
|
7504
7911
|
config;
|
|
@@ -7509,7 +7916,7 @@ var StepExecutor = class {
|
|
|
7509
7916
|
};
|
|
7510
7917
|
}
|
|
7511
7918
|
/**
|
|
7512
|
-
* Execute a step node
|
|
7919
|
+
* Execute a step node with retry support
|
|
7513
7920
|
*/
|
|
7514
7921
|
async execute(node, context) {
|
|
7515
7922
|
const startTime = Date.now();
|
|
@@ -7519,30 +7926,96 @@ var StepExecutor = class {
|
|
|
7519
7926
|
`StepExecutor can only execute 'step' nodes, but node "${node.id}" has type '${config.type}'. This is likely a bug in the DAG executor routing.`
|
|
7520
7927
|
);
|
|
7521
7928
|
}
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7929
|
+
const retryConfig = { ...DEFAULT_RETRY, ...config.retry };
|
|
7930
|
+
const maxAttempts = retryConfig.maxAttempts ?? 1;
|
|
7931
|
+
let lastError;
|
|
7932
|
+
let attempt = 0;
|
|
7933
|
+
while (attempt < maxAttempts) {
|
|
7934
|
+
attempt++;
|
|
7935
|
+
try {
|
|
7936
|
+
const resolvedInput = await this.resolveInput(config.input, context);
|
|
7937
|
+
this.config.onStepStart?.(node.id, resolvedInput);
|
|
7938
|
+
const timeout = config.timeout ? parseDuration(config.timeout) : this.config.defaultTimeout;
|
|
7939
|
+
const output = await this.executeWithTimeout(
|
|
7940
|
+
() => this.executeStep(config, resolvedInput, context),
|
|
7941
|
+
timeout,
|
|
7942
|
+
node.id
|
|
7943
|
+
);
|
|
7944
|
+
this.config.onStepComplete?.(node.id, output);
|
|
7945
|
+
return {
|
|
7946
|
+
success: true,
|
|
7947
|
+
output,
|
|
7948
|
+
executionTime: Date.now() - startTime
|
|
7949
|
+
};
|
|
7950
|
+
} catch (error) {
|
|
7951
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
7952
|
+
const shouldRetry = attempt < maxAttempts && this.isRetryableError(lastError, retryConfig);
|
|
7953
|
+
if (shouldRetry) {
|
|
7954
|
+
const delay2 = this.calculateRetryDelay(attempt, retryConfig);
|
|
7955
|
+
await this.sleep(delay2);
|
|
7956
|
+
continue;
|
|
7957
|
+
}
|
|
7958
|
+
this.config.onStepError?.(node.id, lastError);
|
|
7959
|
+
return {
|
|
7960
|
+
success: false,
|
|
7961
|
+
error: lastError.message,
|
|
7962
|
+
executionTime: Date.now() - startTime
|
|
7963
|
+
};
|
|
7964
|
+
}
|
|
7545
7965
|
}
|
|
7966
|
+
return {
|
|
7967
|
+
success: false,
|
|
7968
|
+
error: lastError?.message ?? "Unknown error",
|
|
7969
|
+
executionTime: Date.now() - startTime
|
|
7970
|
+
};
|
|
7971
|
+
}
|
|
7972
|
+
/**
|
|
7973
|
+
* Check if error is retryable
|
|
7974
|
+
*/
|
|
7975
|
+
isRetryableError(error, config) {
|
|
7976
|
+
if (config.retryIf) {
|
|
7977
|
+
return config.retryIf(error);
|
|
7978
|
+
}
|
|
7979
|
+
const retryablePatterns = [
|
|
7980
|
+
/timeout/i,
|
|
7981
|
+
/ECONNRESET/i,
|
|
7982
|
+
/ECONNREFUSED/i,
|
|
7983
|
+
/ETIMEDOUT/i,
|
|
7984
|
+
/rate limit/i,
|
|
7985
|
+
/429/,
|
|
7986
|
+
/503/,
|
|
7987
|
+
/502/
|
|
7988
|
+
];
|
|
7989
|
+
return retryablePatterns.some((pattern) => pattern.test(error.message));
|
|
7990
|
+
}
|
|
7991
|
+
/**
|
|
7992
|
+
* Calculate retry delay based on backoff strategy
|
|
7993
|
+
*/
|
|
7994
|
+
calculateRetryDelay(attempt, config) {
|
|
7995
|
+
const initialDelay = config.initialDelay ?? 1e3;
|
|
7996
|
+
const maxDelay = config.maxDelay ?? 3e4;
|
|
7997
|
+
let delay2;
|
|
7998
|
+
switch (config.backoff) {
|
|
7999
|
+
case "exponential":
|
|
8000
|
+
delay2 = initialDelay * Math.pow(2, attempt - 1);
|
|
8001
|
+
break;
|
|
8002
|
+
case "linear":
|
|
8003
|
+
delay2 = initialDelay * attempt;
|
|
8004
|
+
break;
|
|
8005
|
+
case "fixed":
|
|
8006
|
+
default:
|
|
8007
|
+
delay2 = initialDelay;
|
|
8008
|
+
break;
|
|
8009
|
+
}
|
|
8010
|
+
const jitter = delay2 * 0.1 * (Math.random() * 2 - 1);
|
|
8011
|
+
delay2 = Math.min(delay2 + jitter, maxDelay);
|
|
8012
|
+
return Math.floor(delay2);
|
|
8013
|
+
}
|
|
8014
|
+
/**
|
|
8015
|
+
* Sleep for specified milliseconds
|
|
8016
|
+
*/
|
|
8017
|
+
sleep(ms) {
|
|
8018
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
7546
8019
|
}
|
|
7547
8020
|
/**
|
|
7548
8021
|
* Resolve step input from context
|
|
@@ -8361,7 +8834,35 @@ var WorkflowClient = class {
|
|
|
8361
8834
|
this.executor = new WorkflowExecutor({
|
|
8362
8835
|
backend: this.backend,
|
|
8363
8836
|
debug: this.debug,
|
|
8364
|
-
...config.executor
|
|
8837
|
+
...config.executor,
|
|
8838
|
+
onWaiting: async (run, nodeId) => {
|
|
8839
|
+
const nodeState = run.nodeStates[nodeId];
|
|
8840
|
+
if (!nodeState?.input) {
|
|
8841
|
+
if (this.debug) {
|
|
8842
|
+
console.log(`[WorkflowClient] No wait config found for node: ${nodeId}`);
|
|
8843
|
+
}
|
|
8844
|
+
return;
|
|
8845
|
+
}
|
|
8846
|
+
const input = nodeState.input;
|
|
8847
|
+
if (input.type !== "approval") {
|
|
8848
|
+
return;
|
|
8849
|
+
}
|
|
8850
|
+
const waitConfig = {
|
|
8851
|
+
type: "wait",
|
|
8852
|
+
waitType: "approval",
|
|
8853
|
+
message: input.message,
|
|
8854
|
+
payload: input.payload
|
|
8855
|
+
};
|
|
8856
|
+
try {
|
|
8857
|
+
await this.approvalManager.createApproval(run, nodeId, waitConfig, run.context);
|
|
8858
|
+
if (this.debug) {
|
|
8859
|
+
console.log(`[WorkflowClient] Created approval for node: ${nodeId}`);
|
|
8860
|
+
}
|
|
8861
|
+
} catch (error) {
|
|
8862
|
+
console.error(`[WorkflowClient] Failed to create approval:`, error);
|
|
8863
|
+
}
|
|
8864
|
+
config.executor?.onWaiting?.(run, nodeId);
|
|
8865
|
+
}
|
|
8365
8866
|
});
|
|
8366
8867
|
this.approvalManager = new ApprovalManager({
|
|
8367
8868
|
backend: this.backend,
|