veryfront 0.1.44 → 0.1.46

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/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -61,7 +61,7 @@ export function endRequestMetrics(requestContext) {
61
61
  cumulativeMetrics.totalNetworkMs += req.networkMs;
62
62
  cumulativeMetrics.requestsTracked++;
63
63
  recordContentNetworkFetch(req.networkMs, req.isPreviewMode ?? false);
64
- logger.info("REQUEST_SUMMARY", {
64
+ logger.debug("REQUEST_SUMMARY", {
65
65
  ...requestContext,
66
66
  durationMs,
67
67
  networkMs: req.networkMs,
@@ -400,13 +400,13 @@ export class ReadOperations {
400
400
  return null;
401
401
  }
402
402
  async fetchDraftContent(normalizedPath, apiPath, cacheKey, shouldCache) {
403
- logger.info("API_FETCH_START - fetching draft from API", {
403
+ logger.debug("API_FETCH_START - fetching draft from API", {
404
404
  path: normalizedPath,
405
405
  apiPath,
406
406
  cacheKey,
407
407
  });
408
408
  const content = await this.client.getFileContent(apiPath);
409
- logger.info("API_FETCH_DONE - got content from API", {
409
+ logger.debug("API_FETCH_DONE - got content from API", {
410
410
  path: normalizedPath,
411
411
  contentLength: content.length,
412
412
  preview: previewText(content).replace(/\n/g, "\\n"),
@@ -70,7 +70,7 @@ export class WebSocketManager {
70
70
  };
71
71
  this.ws.onmessage = (event) => {
72
72
  this.wsLastPong = Date.now();
73
- logger.info("WebSocket message received:", { data: event.data });
73
+ logger.debug("WebSocket message received:", { data: event.data });
74
74
  this.handlePokeMessage(event);
75
75
  };
76
76
  this.ws.onclose = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,kCAAkC,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAOnD,eAAO,MAAM,sBAAsB,0MAYzB,CAAC;AA4EX,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,SAAS,GAAG,YAAY,CAAC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC9D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAWD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB;0BAoI1B,OAAO,CAAC,OAAO,KAAG,OAAO,CAAC,YAAY,CAAC;0BAgNvC,OAAO,CAAC,OAAO,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;;;;;;;;0BA1RrD,MAAM,EAAE;;EAwUpC;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAwB7F"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,kCAAkC,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAOnD,eAAO,MAAM,sBAAsB,0MAYzB,CAAC;AA6EX,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,SAAS,GAAG,YAAY,CAAC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC9D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAmCD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB;0BA6K1B,OAAO,CAAC,OAAO,KAAG,OAAO,CAAC,YAAY,CAAC;0BA+NvC,OAAO,CAAC,OAAO,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;;;;;;;;0BAlVrD,MAAM,EAAE;;EAgYpC;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAwB7F"}
@@ -69,6 +69,30 @@ function extractUserToken(cookieHeader) {
69
69
  const match = cookieHeader.match(/(?:^|;\s*)authToken=([^;]+)/);
70
70
  return match?.[1] ? decodeURIComponent(match[1]) : undefined;
71
71
  }
72
+ function extractUserIdFromToken(token) {
73
+ try {
74
+ const payload = token.split(".")[1];
75
+ if (!payload)
76
+ return undefined;
77
+ // JWT payloads are base64url-encoded: normalize to standard base64 before decoding
78
+ let base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
79
+ const remainder = base64.length % 4;
80
+ if (remainder === 2)
81
+ base64 += "==";
82
+ else if (remainder === 3)
83
+ base64 += "=";
84
+ const decoded = JSON.parse(atob(base64));
85
+ return decoded?.userId;
86
+ }
87
+ catch {
88
+ return undefined;
89
+ }
90
+ }
91
+ function isProjectMember(users, userId) {
92
+ if (!users || !userId)
93
+ return false;
94
+ return users.some((u) => u.id === userId);
95
+ }
72
96
  export function createProxyHandler(options) {
73
97
  const { config, cache, logger } = options;
74
98
  const localProjects = config.localProjects ?? {};
@@ -145,20 +169,47 @@ export function createProxyHandler(options) {
145
169
  const returnPath = safePath + url.search;
146
170
  return `https://veryfront.com/sign-in?from=${encodeURIComponent(returnPath)}`;
147
171
  }
148
- async function resolveReleaseAndProtection(req, token, userToken, lookupKey, envMatcher, logContext) {
149
- const lookupResult = await lookupProjectByDomain(lookupKey, config.apiBaseUrl, token, logger);
150
- if (!lookupResult)
151
- return { projectId: undefined, releaseId: undefined };
152
- const matchingEnv = lookupResult.environments?.find(envMatcher);
153
- if (matchingEnv?.protected && !userToken) {
172
+ function checkProtectedAccess(req, matchingEnv, userToken, users, logContext) {
173
+ if (!matchingEnv?.protected)
174
+ return null;
175
+ if (!userToken) {
154
176
  const redirectUrl = makeAuthRedirectUrl(req);
155
177
  logger?.info("Protected environment requires authentication", {
156
178
  ...logContext,
157
179
  environmentName: matchingEnv.name,
158
180
  redirectUrl,
159
181
  });
160
- return { error: { status: 302, message: "Authentication required", redirectUrl } };
182
+ return { status: 302, message: "Authentication required", redirectUrl };
183
+ }
184
+ const userId = extractUserIdFromToken(userToken);
185
+ if (!userId) {
186
+ // Malformed token — treat as unauthenticated so user can re-sign-in
187
+ const redirectUrl = makeAuthRedirectUrl(req);
188
+ logger?.info("Could not extract userId from token", {
189
+ ...logContext,
190
+ environmentName: matchingEnv.name,
191
+ redirectUrl,
192
+ });
193
+ return { status: 302, message: "Authentication required", redirectUrl };
161
194
  }
195
+ if (!isProjectMember(users, userId)) {
196
+ logger?.info("User is not a member of the project", {
197
+ ...logContext,
198
+ environmentName: matchingEnv.name,
199
+ userId,
200
+ });
201
+ return { status: 403, message: "Access denied" };
202
+ }
203
+ return null;
204
+ }
205
+ async function resolveReleaseAndProtection(req, token, userToken, lookupKey, envMatcher, logContext) {
206
+ const lookupResult = await lookupProjectByDomain(lookupKey, config.apiBaseUrl, token, logger);
207
+ if (!lookupResult)
208
+ return { projectId: undefined, releaseId: undefined };
209
+ const matchingEnv = lookupResult.environments?.find(envMatcher);
210
+ const protectionError = checkProtectedAccess(req, matchingEnv, userToken, lookupResult.users, logContext);
211
+ if (protectionError)
212
+ return { error: protectionError };
162
213
  return {
163
214
  projectId: lookupResult.id,
164
215
  releaseId: matchingEnv?.active_release_id ?? undefined,
@@ -240,14 +291,9 @@ export function createProxyHandler(options) {
240
291
  const matchingEnv = lookupResult.environments?.find((env) => env.domains?.some((d) => d.toLowerCase() === normalizedHost));
241
292
  releaseId = matchingEnv?.active_release_id ?? undefined;
242
293
  environmentId = matchingEnv?.id;
243
- if (matchingEnv?.protected && !userToken) {
244
- const redirectUrl = makeAuthRedirectUrl(req);
245
- logger?.info("Protected environment requires authentication", {
246
- domain: host,
247
- environmentName: matchingEnv.name,
248
- redirectUrl,
249
- });
250
- return makeErrorContext(base, 302, "Authentication required", token, redirectUrl);
294
+ const protectionError = checkProtectedAccess(req, matchingEnv, userToken, lookupResult.users, { domain: host });
295
+ if (protectionError) {
296
+ return makeErrorContext(base, protectionError.status, protectionError.message, token, protectionError.redirectUrl);
251
297
  }
252
298
  logger?.info("Resolved custom domain to project", {
253
299
  domain: host,
@@ -275,17 +321,19 @@ export function createProxyHandler(options) {
275
321
  });
276
322
  }
277
323
  else if (projectSlug && scope === "preview" && token) {
278
- // For preview mode, we need projectId to fetch project metadata (e.g., layout config)
279
- // but we don't need releaseId since preview uses branch-based content
280
- const lookupResult = await lookupProjectByDomain(projectSlug, config.apiBaseUrl, token, logger);
281
- if (lookupResult) {
282
- projectId = lookupResult.id;
283
- // Find preview environment for env var resolution
284
- const previewEnv = lookupResult.environments?.find((env) => env.name.toLowerCase() === "preview");
285
- environmentId = previewEnv?.id;
324
+ // Preview uses branch-based content (no releaseId needed), but must
325
+ // still enforce the environment's `protected` flag like other scopes.
326
+ const resolved = await resolveReleaseAndProtection(req, token, userToken, projectSlug, (env) => env.name.toLowerCase() === "preview", { projectSlug });
327
+ if ("error" in resolved) {
328
+ return makeErrorContext(base, resolved.error.status, resolved.error.message, token, resolved.error.redirectUrl);
329
+ }
330
+ projectId = resolved.projectId;
331
+ environmentId = resolved.environmentId;
332
+ if (projectId) {
286
333
  logger?.info("Resolved preview project", {
287
334
  projectSlug,
288
335
  projectId,
336
+ environmentId,
289
337
  });
290
338
  }
291
339
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/src/server/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AA4B1D,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,OAAO,EAAE,cAAc,CAAC;IAExB,2BAA2B;IAC3B,MAAM,EAAE,eAAe,CAAC;IAExB,wCAAwC;IACxC,cAAc,EAAE,OAAO,CAAC;IAExB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAkDD,wBAAsB,SAAS,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAqG1B;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAa1B;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAyB1B"}
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/src/server/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AA4B1D,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,OAAO,EAAE,cAAc,CAAC;IAExB,2BAA2B;IAC3B,MAAM,EAAE,eAAe,CAAC;IAExB,wCAAwC;IACxC,cAAc,EAAE,OAAO,CAAC;IAExB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAmDD,wBAAsB,SAAS,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAqG1B;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAa1B;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAyB1B"}
@@ -5,7 +5,7 @@ import { enhanceAdapterWithFS } from "../platform/adapters/fs/integration.js";
5
5
  import { isExtendedFSAdapter } from "../platform/adapters/fs/wrapper.js";
6
6
  import { getEnv } from "../platform/compat/process.js";
7
7
  import { initializeEsbuild } from "../platform/compat/esbuild.js";
8
- import { logger } from "../utils/index.js";
8
+ import { logger, refreshLoggerConfig } from "../utils/index.js";
9
9
  import { isDebugEnabled } from "../utils/constants/env.js";
10
10
  import { getEnvSource, hasEnvLoaded, loadEnv, markEnvLoaded, supportsEnvFiles, } from "../utils/env-loader.js";
11
11
  import { ReloadNotifier } from "./reload-notifier.js";
@@ -26,6 +26,7 @@ async function ensureEnvLoaded(projectDir, adapter) {
26
26
  debug: isDebugEnabled(adapter.env),
27
27
  });
28
28
  refreshEnvironmentConfig();
29
+ refreshLoggerConfig();
29
30
  }
30
31
  catch (error) {
31
32
  bootstrapLog.warn("Failed to load .env files", {
@@ -5,7 +5,7 @@
5
5
  * @module utils
6
6
  */
7
7
  export { type GlobalWithBun, type GlobalWithDeno, type GlobalWithProcess, hasBunRuntime, hasDenoRuntime, hasNodeProcess, } from "./runtime-guards.js";
8
- export { agentLogger, bundlerLogger, logger, rendererLogger, serverLogger, } from "./logger/index.js";
8
+ export { agentLogger, bundlerLogger, logger, refreshLoggerConfig, rendererLogger, serverLogger, } from "./logger/index.js";
9
9
  export { BREAKPOINT_LG, BREAKPOINT_MD, BREAKPOINT_SM, BREAKPOINT_XL, BYTES_PER_KB, DEFAULT_ALLOWED_CDN_HOSTS, DEFAULT_BUILD_CONCURRENCY, DEFAULT_DASHBOARD_PORT, DEFAULT_LRU_MAX_ENTRIES, DEV_SERVER_ENDPOINTS, FORBIDDEN_PATH_PATTERNS, getDenoStdNodeBase, getReactImportMap, HASH_SEED_DJB2, HASH_SEED_FNV1A, HMR_CLIENT_RELOAD_DELAY_MS, HMR_CLOSE_MESSAGE_TOO_LARGE, HMR_CLOSE_NORMAL, HMR_CLOSE_RATE_LIMIT, HMR_MAX_MESSAGE_SIZE_BYTES, HMR_MAX_MESSAGES_PER_MINUTE, HMR_RATE_LIMIT_WINDOW_MS, HTTP_BAD_REQUEST, HTTP_CONTENT_TYPE_IMAGE_GIF, HTTP_CONTENT_TYPE_IMAGE_ICO, HTTP_CONTENT_TYPE_IMAGE_JPEG, HTTP_CONTENT_TYPE_IMAGE_PNG, HTTP_CONTENT_TYPE_IMAGE_SVG, HTTP_CONTENT_TYPE_IMAGE_WEBP, HTTP_CONTENT_TYPES, HTTP_MODULE_FETCH_TIMEOUT_MS, HTTP_NETWORK_CONNECT_TIMEOUT, HTTP_NOT_FOUND, HTTP_NOT_IMPLEMENTED, HTTP_OK, HTTP_REDIRECT_FOUND, HTTP_SERVER_ERROR, HTTP_STATUS_CLIENT_ERROR_MIN, HTTP_STATUS_REDIRECT_MIN, HTTP_STATUS_SERVER_ERROR_MIN, HTTP_STATUS_SUCCESS_MIN, HTTP_UNAVAILABLE, IMAGE_OPTIMIZATION, MAX_BATCH_SIZE, MAX_PATH_LENGTH, MAX_PATH_TRAVERSAL_DEPTH, MS_PER_SECOND, PREFETCH_DEFAULT_DELAY_MS, PREFETCH_DEFAULT_TIMEOUT_MS, PREFETCH_MAX_SIZE_BYTES, REACT_DEFAULT_VERSION, RESPONSIVE_IMAGE_WIDTH_LG, RESPONSIVE_IMAGE_WIDTHS, RSC_MANIFEST_CACHE_TTL_MS, TSX_LAYOUT_MAX_ENTRIES, Z_INDEX_DEV_INDICATOR, Z_INDEX_ERROR_OVERLAY, } from "./constants/index.js";
10
10
  export { VERSION } from "./version.js";
11
11
  export { type BundleCode as HashBundleCode, computeCodeHash, computeHash, fnv1aHash, shortHash, simpleHash, } from "./hash-utils.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,WAAW,EACX,aAAa,EACb,MAAM,EACN,cAAc,EACd,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,YAAY,EACZ,yBAAyB,EACzB,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,0BAA0B,EAC1B,2BAA2B,EAC3B,gBAAgB,EAChB,oBAAoB,EACpB,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,gBAAgB,EAChB,2BAA2B,EAC3B,2BAA2B,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,EAC3B,4BAA4B,EAC5B,kBAAkB,EAClB,4BAA4B,EAC5B,4BAA4B,EAC5B,cAAc,EACd,oBAAoB,EACpB,OAAO,EACP,mBAAmB,EACnB,iBAAiB,EACjB,4BAA4B,EAC5B,wBAAwB,EACxB,4BAA4B,EAC5B,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EACL,KAAK,UAAU,IAAI,cAAc,EACjC,eAAe,EACf,WAAW,EACX,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEpG,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,WAAW,EACX,aAAa,EACb,MAAM,EACN,mBAAmB,EACnB,cAAc,EACd,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,YAAY,EACZ,yBAAyB,EACzB,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,0BAA0B,EAC1B,2BAA2B,EAC3B,gBAAgB,EAChB,oBAAoB,EACpB,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,gBAAgB,EAChB,2BAA2B,EAC3B,2BAA2B,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,EAC3B,4BAA4B,EAC5B,kBAAkB,EAClB,4BAA4B,EAC5B,4BAA4B,EAC5B,cAAc,EACd,oBAAoB,EACpB,OAAO,EACP,mBAAmB,EACnB,iBAAiB,EACjB,4BAA4B,EAC5B,wBAAwB,EACxB,4BAA4B,EAC5B,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EACL,KAAK,UAAU,IAAI,cAAc,EACjC,eAAe,EACf,WAAW,EACX,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEpG,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
@@ -5,7 +5,7 @@
5
5
  * @module utils
6
6
  */
7
7
  export { hasBunRuntime, hasDenoRuntime, hasNodeProcess, } from "./runtime-guards.js";
8
- export { agentLogger, bundlerLogger, logger, rendererLogger, serverLogger, } from "./logger/index.js";
8
+ export { agentLogger, bundlerLogger, logger, refreshLoggerConfig, rendererLogger, serverLogger, } from "./logger/index.js";
9
9
  export { BREAKPOINT_LG, BREAKPOINT_MD, BREAKPOINT_SM, BREAKPOINT_XL, BYTES_PER_KB, DEFAULT_ALLOWED_CDN_HOSTS, DEFAULT_BUILD_CONCURRENCY, DEFAULT_DASHBOARD_PORT, DEFAULT_LRU_MAX_ENTRIES, DEV_SERVER_ENDPOINTS, FORBIDDEN_PATH_PATTERNS, getDenoStdNodeBase, getReactImportMap, HASH_SEED_DJB2, HASH_SEED_FNV1A, HMR_CLIENT_RELOAD_DELAY_MS, HMR_CLOSE_MESSAGE_TOO_LARGE, HMR_CLOSE_NORMAL, HMR_CLOSE_RATE_LIMIT, HMR_MAX_MESSAGE_SIZE_BYTES, HMR_MAX_MESSAGES_PER_MINUTE, HMR_RATE_LIMIT_WINDOW_MS, HTTP_BAD_REQUEST, HTTP_CONTENT_TYPE_IMAGE_GIF, HTTP_CONTENT_TYPE_IMAGE_ICO, HTTP_CONTENT_TYPE_IMAGE_JPEG, HTTP_CONTENT_TYPE_IMAGE_PNG, HTTP_CONTENT_TYPE_IMAGE_SVG, HTTP_CONTENT_TYPE_IMAGE_WEBP, HTTP_CONTENT_TYPES, HTTP_MODULE_FETCH_TIMEOUT_MS, HTTP_NETWORK_CONNECT_TIMEOUT, HTTP_NOT_FOUND, HTTP_NOT_IMPLEMENTED, HTTP_OK, HTTP_REDIRECT_FOUND, HTTP_SERVER_ERROR, HTTP_STATUS_CLIENT_ERROR_MIN, HTTP_STATUS_REDIRECT_MIN, HTTP_STATUS_SERVER_ERROR_MIN, HTTP_STATUS_SUCCESS_MIN, HTTP_UNAVAILABLE, IMAGE_OPTIMIZATION, MAX_BATCH_SIZE, MAX_PATH_LENGTH, MAX_PATH_TRAVERSAL_DEPTH, MS_PER_SECOND, PREFETCH_DEFAULT_DELAY_MS, PREFETCH_DEFAULT_TIMEOUT_MS, PREFETCH_MAX_SIZE_BYTES, REACT_DEFAULT_VERSION, RESPONSIVE_IMAGE_WIDTH_LG, RESPONSIVE_IMAGE_WIDTHS, RSC_MANIFEST_CACHE_TTL_MS, TSX_LAYOUT_MAX_ENTRIES, Z_INDEX_DEV_INDICATOR, Z_INDEX_ERROR_OVERLAY, } from "./constants/index.js";
10
10
  export { VERSION } from "./version.js";
11
11
  export { computeCodeHash, computeHash, fnv1aHash, shortHash, simpleHash, } from "./hash-utils.js";
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @module utils/logger
5
5
  */
6
- export { __registerRequestContextGetter, __registerTraceContextGetter, __resetLoggerConfigForTests, __resetTraceContextGetterForTests, agentLogger, bundlerLogger, cliLogger, createRequestLogger, getBaseLogger, getDefaultLevel, type LogEntry, type LogFormat, type Logger, logger, LogLevel, proxyLogger, rendererLogger, serverLogger, } from "./logger.js";
6
+ export { __registerRequestContextGetter, __registerTraceContextGetter, __resetLoggerConfigForTests, __resetTraceContextGetterForTests, agentLogger, bundlerLogger, cliLogger, createRequestLogger, getBaseLogger, getDefaultLevel, type LogEntry, type LogFormat, type Logger, logger, LogLevel, proxyLogger, refreshLoggerConfig, rendererLogger, serverLogger, } from "./logger.js";
7
7
  export { ANSI, colorize, formatContextText, formatErrorText, formatTimestamp, formatValue, isRecord, LEVEL_COLORS, LEVEL_GLYPHS, type LogLevelName, normalizeText, padTag, PREFIX_WIDTH, type SerializedError, serializeError, TAG_WIDTH, truncateText, } from "./core.js";
8
8
  export { getRequestContext, getRequestLogger, type RequestContext, requestContextStore, runWithRequestContext, runWithRequestContextAsync, } from "./request-context.js";
9
9
  export { type LogComponent, LogComponents } from "./components.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,2BAA2B,EAC3B,iCAAiC,EACjC,WAAW,EACX,aAAa,EACb,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,MAAM,EACX,MAAM,EACN,QAAQ,EACR,WAAW,EACX,cAAc,EACd,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,KAAK,YAAY,EACjB,aAAa,EACb,MAAM,EACN,YAAY,EACZ,KAAK,eAAe,EACpB,cAAc,EACd,SAAS,EACT,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,cAAc,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,2BAA2B,EAC3B,iCAAiC,EACjC,WAAW,EACX,aAAa,EACb,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,MAAM,EACX,MAAM,EACN,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,IAAI,EACJ,QAAQ,EACR,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,KAAK,YAAY,EACjB,aAAa,EACb,MAAM,EACN,YAAY,EACZ,KAAK,eAAe,EACpB,cAAc,EACd,SAAS,EACT,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,cAAc,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @module utils/logger
5
5
  */
6
- export { __registerRequestContextGetter, __registerTraceContextGetter, __resetLoggerConfigForTests, __resetTraceContextGetterForTests, agentLogger, bundlerLogger, cliLogger, createRequestLogger, getBaseLogger, getDefaultLevel, logger, LogLevel, proxyLogger, rendererLogger, serverLogger, } from "./logger.js";
6
+ export { __registerRequestContextGetter, __registerTraceContextGetter, __resetLoggerConfigForTests, __resetTraceContextGetterForTests, agentLogger, bundlerLogger, cliLogger, createRequestLogger, getBaseLogger, getDefaultLevel, logger, LogLevel, proxyLogger, refreshLoggerConfig, rendererLogger, serverLogger, } from "./logger.js";
7
7
  export { ANSI, colorize, formatContextText, formatErrorText, formatTimestamp, formatValue, isRecord, LEVEL_COLORS, LEVEL_GLYPHS, normalizeText, padTag, PREFIX_WIDTH, serializeError, TAG_WIDTH, truncateText, } from "./core.js";
8
8
  export { getRequestContext, getRequestLogger, requestContextStore, runWithRequestContext, runWithRequestContextAsync, } from "./request-context.js";
9
9
  export { LogComponents } from "./components.js";
@@ -59,11 +59,18 @@ export interface Logger {
59
59
  component(name: string): Logger;
60
60
  }
61
61
  /**
62
- * Reset the cached logger configuration.
63
- * This is only intended for testing purposes to ensure fresh config evaluation.
62
+ * Determine the log level based on environment variables.
63
+ * Exported for testing purposes.
64
64
  * @internal
65
65
  */
66
- export declare function __resetLoggerConfigForTests(): void;
66
+ export declare function getDefaultLevel(envLevel?: string | undefined, debugFlag?: string | undefined): LogLevel;
67
+ /**
68
+ * Re-read logger configuration from environment variables.
69
+ * Call after loading .env files so the logger picks up any overrides.
70
+ */
71
+ export declare function refreshLoggerConfig(): void;
72
+ /** @internal Alias kept for tests. */
73
+ export declare const __resetLoggerConfigForTests: typeof refreshLoggerConfig;
67
74
  declare class ConsoleLogger implements Logger {
68
75
  private prefix;
69
76
  private boundContext;
@@ -80,12 +87,6 @@ declare class ConsoleLogger implements Logger {
80
87
  error(message: string, ...args: unknown[]): void;
81
88
  time<T>(label: string, fn: () => Promise<T>): Promise<T>;
82
89
  }
83
- /**
84
- * Determine the log level based on environment variables.
85
- * Exported for testing purposes.
86
- * @internal
87
- */
88
- export declare function getDefaultLevel(envLevel?: string | undefined, debugFlag?: string | undefined): LogLevel;
89
90
  /**
90
91
  * Register the request context getter.
91
92
  * Called by request-context.ts during module initialization.
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/logger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/logger.ts"],"names":[],"mappings":"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"}
@@ -10,44 +10,30 @@ export var LogLevel;
10
10
  LogLevel[LogLevel["WARN"] = 2] = "WARN";
11
11
  LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
12
12
  })(LogLevel || (LogLevel = {}));
13
- let cachedConfig = null;
14
- let cachedEnvLevel;
15
- let cachedDebugFlag;
16
- let cachedEnvFormat;
17
- let cachedEnvMode;
13
+ // ---- Config helpers (must be declared before the eager init below) ----
14
+ const LOG_LEVEL_MAP = {
15
+ DEBUG: LogLevel.DEBUG,
16
+ INFO: LogLevel.INFO,
17
+ WARN: LogLevel.WARN,
18
+ ERROR: LogLevel.ERROR,
19
+ };
20
+ function parseLogLevel(levelString) {
21
+ if (!levelString)
22
+ return undefined;
23
+ return LOG_LEVEL_MAP[levelString.toUpperCase()];
24
+ }
18
25
  /**
19
- * Reset the cached logger configuration.
20
- * This is only intended for testing purposes to ensure fresh config evaluation.
26
+ * Determine the log level based on environment variables.
27
+ * Exported for testing purposes.
21
28
  * @internal
22
29
  */
23
- export function __resetLoggerConfigForTests() {
24
- cachedConfig = null;
25
- cachedEnvLevel = undefined;
26
- cachedDebugFlag = undefined;
27
- cachedEnvFormat = undefined;
28
- cachedEnvMode = undefined;
29
- }
30
- function resolveLoggerConfig() {
31
- const envLevel = getEnv("LOG_LEVEL");
32
- const debugFlag = getEnv("VERYFRONT_DEBUG");
33
- const envFormat = getEnv("LOG_FORMAT");
34
- const envMode = getEnv("NODE_ENV");
35
- if (cachedConfig &&
36
- envLevel === cachedEnvLevel &&
37
- debugFlag === cachedDebugFlag &&
38
- envFormat === cachedEnvFormat &&
39
- envMode === cachedEnvMode) {
40
- return cachedConfig;
41
- }
42
- cachedEnvLevel = envLevel;
43
- cachedDebugFlag = debugFlag;
44
- cachedEnvFormat = envFormat;
45
- cachedEnvMode = envMode;
46
- cachedConfig = {
47
- level: getDefaultLevel(envLevel, debugFlag),
48
- format: getDefaultFormat(envFormat, envMode),
49
- };
50
- return cachedConfig;
30
+ export function getDefaultLevel(envLevel = getEnv("LOG_LEVEL"), debugFlag = getEnv("VERYFRONT_DEBUG")) {
31
+ const parsedLevel = parseLogLevel(envLevel);
32
+ if (parsedLevel !== undefined)
33
+ return parsedLevel;
34
+ if (debugFlag === "1" || debugFlag === "true")
35
+ return LogLevel.DEBUG;
36
+ return LogLevel.INFO;
51
37
  }
52
38
  /**
53
39
  * Determine log format from environment.
@@ -58,6 +44,32 @@ function getDefaultFormat(envFormat = getEnv("LOG_FORMAT"), envMode = getEnv("NO
58
44
  return envFormat;
59
45
  return envMode === "production" ? "json" : "text";
60
46
  }
47
+ // ---- Eager config resolution ----
48
+ /**
49
+ * Eagerly resolved at module load time so the config is captured from
50
+ * host process env vars BEFORE any per-request project env overlay is
51
+ * active. The project overlay blocks access to host env (for security),
52
+ * which would cause the logger to fall back to "text" format during SSR.
53
+ */
54
+ let loggerConfig = {
55
+ level: getDefaultLevel(),
56
+ format: getDefaultFormat(),
57
+ };
58
+ /**
59
+ * Re-read logger configuration from environment variables.
60
+ * Call after loading .env files so the logger picks up any overrides.
61
+ */
62
+ export function refreshLoggerConfig() {
63
+ loggerConfig = {
64
+ level: getDefaultLevel(),
65
+ format: getDefaultFormat(),
66
+ };
67
+ }
68
+ /** @internal Alias kept for tests. */
69
+ export const __resetLoggerConfigForTests = refreshLoggerConfig;
70
+ function resolveLoggerConfig() {
71
+ return loggerConfig;
72
+ }
61
73
  /**
62
74
  * Extract context from variadic args.
63
75
  * First object argument becomes context, errors are handled specially.
@@ -238,30 +250,6 @@ class ConsoleLogger {
238
250
  }
239
251
  }
240
252
  }
241
- const LOG_LEVEL_MAP = {
242
- DEBUG: LogLevel.DEBUG,
243
- INFO: LogLevel.INFO,
244
- WARN: LogLevel.WARN,
245
- ERROR: LogLevel.ERROR,
246
- };
247
- function parseLogLevel(levelString) {
248
- if (!levelString)
249
- return undefined;
250
- return LOG_LEVEL_MAP[levelString.toUpperCase()];
251
- }
252
- /**
253
- * Determine the log level based on environment variables.
254
- * Exported for testing purposes.
255
- * @internal
256
- */
257
- export function getDefaultLevel(envLevel = getEnv("LOG_LEVEL"), debugFlag = getEnv("VERYFRONT_DEBUG")) {
258
- const parsedLevel = parseLogLevel(envLevel);
259
- if (parsedLevel !== undefined)
260
- return parsedLevel;
261
- if (debugFlag === "1" || debugFlag === "true")
262
- return LogLevel.DEBUG;
263
- return LogLevel.INFO;
264
- }
265
253
  function createLogger(prefix) {
266
254
  return new ConsoleLogger(prefix);
267
255
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -96,7 +96,7 @@ export function endRequestMetrics(
96
96
 
97
97
  recordContentNetworkFetch(req.networkMs, req.isPreviewMode ?? false);
98
98
 
99
- logger.info("REQUEST_SUMMARY", {
99
+ logger.debug("REQUEST_SUMMARY", {
100
100
  ...requestContext,
101
101
  durationMs,
102
102
  networkMs: req.networkMs,
@@ -622,7 +622,7 @@ export class ReadOperations {
622
622
  cacheKey: string,
623
623
  shouldCache: boolean,
624
624
  ): Promise<string> {
625
- logger.info("API_FETCH_START - fetching draft from API", {
625
+ logger.debug("API_FETCH_START - fetching draft from API", {
626
626
  path: normalizedPath,
627
627
  apiPath,
628
628
  cacheKey,
@@ -630,7 +630,7 @@ export class ReadOperations {
630
630
 
631
631
  const content = await this.client.getFileContent(apiPath);
632
632
 
633
- logger.info("API_FETCH_DONE - got content from API", {
633
+ logger.debug("API_FETCH_DONE - got content from API", {
634
634
  path: normalizedPath,
635
635
  contentLength: content.length,
636
636
  preview: previewText(content).replace(/\n/g, "\\n"),
@@ -116,7 +116,7 @@ export class WebSocketManager {
116
116
 
117
117
  this.ws.onmessage = (event) => {
118
118
  this.wsLastPong = Date.now();
119
- logger.info("WebSocket message received:", { data: event.data });
119
+ logger.debug("WebSocket message received:", { data: event.data });
120
120
  this.handlePokeMessage(event);
121
121
  };
122
122
 
@@ -26,6 +26,7 @@ interface DomainLookupResult {
26
26
  id: string;
27
27
  slug: string;
28
28
  name: string;
29
+ users?: Array<{ id: string }>;
29
30
  environments?: Array<{
30
31
  id: string;
31
32
  name: string;
@@ -150,6 +151,30 @@ function extractUserToken(cookieHeader: string): string | undefined {
150
151
  return match?.[1] ? decodeURIComponent(match[1]) : undefined;
151
152
  }
152
153
 
154
+ function extractUserIdFromToken(token: string): string | undefined {
155
+ try {
156
+ const payload = token.split(".")[1];
157
+ if (!payload) return undefined;
158
+ // JWT payloads are base64url-encoded: normalize to standard base64 before decoding
159
+ let base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
160
+ const remainder = base64.length % 4;
161
+ if (remainder === 2) base64 += "==";
162
+ else if (remainder === 3) base64 += "=";
163
+ const decoded = JSON.parse(atob(base64));
164
+ return decoded?.userId;
165
+ } catch {
166
+ return undefined;
167
+ }
168
+ }
169
+
170
+ function isProjectMember(
171
+ users: Array<{ id: string }> | undefined,
172
+ userId: string | undefined,
173
+ ): boolean {
174
+ if (!users || !userId) return false;
175
+ return users.some((u) => u.id === userId);
176
+ }
177
+
153
178
  export function createProxyHandler(options: ProxyHandlerOptions) {
154
179
  const { config, cache, logger } = options;
155
180
  const localProjects = config.localProjects ?? {};
@@ -249,6 +274,48 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
249
274
  return `https://veryfront.com/sign-in?from=${encodeURIComponent(returnPath)}`;
250
275
  }
251
276
 
277
+ function checkProtectedAccess(
278
+ req: dntShim.Request,
279
+ matchingEnv: NonNullable<DomainLookupResult["environments"]>[number] | undefined,
280
+ userToken: string | undefined,
281
+ users: DomainLookupResult["users"],
282
+ logContext: Record<string, unknown>,
283
+ ): { status: number; message: string; redirectUrl?: string } | null {
284
+ if (!matchingEnv?.protected) return null;
285
+
286
+ if (!userToken) {
287
+ const redirectUrl = makeAuthRedirectUrl(req);
288
+ logger?.info("Protected environment requires authentication", {
289
+ ...logContext,
290
+ environmentName: matchingEnv.name,
291
+ redirectUrl,
292
+ });
293
+ return { status: 302, message: "Authentication required", redirectUrl };
294
+ }
295
+
296
+ const userId = extractUserIdFromToken(userToken);
297
+ if (!userId) {
298
+ // Malformed token — treat as unauthenticated so user can re-sign-in
299
+ const redirectUrl = makeAuthRedirectUrl(req);
300
+ logger?.info("Could not extract userId from token", {
301
+ ...logContext,
302
+ environmentName: matchingEnv.name,
303
+ redirectUrl,
304
+ });
305
+ return { status: 302, message: "Authentication required", redirectUrl };
306
+ }
307
+ if (!isProjectMember(users, userId)) {
308
+ logger?.info("User is not a member of the project", {
309
+ ...logContext,
310
+ environmentName: matchingEnv.name,
311
+ userId,
312
+ });
313
+ return { status: 403, message: "Access denied" };
314
+ }
315
+
316
+ return null;
317
+ }
318
+
252
319
  async function resolveReleaseAndProtection(
253
320
  req: dntShim.Request,
254
321
  token: string,
@@ -265,15 +332,14 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
265
332
 
266
333
  const matchingEnv = lookupResult.environments?.find(envMatcher);
267
334
 
268
- if (matchingEnv?.protected && !userToken) {
269
- const redirectUrl = makeAuthRedirectUrl(req);
270
- logger?.info("Protected environment requires authentication", {
271
- ...logContext,
272
- environmentName: matchingEnv.name,
273
- redirectUrl,
274
- });
275
- return { error: { status: 302, message: "Authentication required", redirectUrl } };
276
- }
335
+ const protectionError = checkProtectedAccess(
336
+ req,
337
+ matchingEnv,
338
+ userToken,
339
+ lookupResult.users,
340
+ logContext,
341
+ );
342
+ if (protectionError) return { error: protectionError };
277
343
 
278
344
  return {
279
345
  projectId: lookupResult.id,
@@ -374,14 +440,21 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
374
440
  releaseId = matchingEnv?.active_release_id ?? undefined;
375
441
  environmentId = matchingEnv?.id;
376
442
 
377
- if (matchingEnv?.protected && !userToken) {
378
- const redirectUrl = makeAuthRedirectUrl(req);
379
- logger?.info("Protected environment requires authentication", {
380
- domain: host,
381
- environmentName: matchingEnv.name,
382
- redirectUrl,
383
- });
384
- return makeErrorContext(base, 302, "Authentication required", token, redirectUrl);
443
+ const protectionError = checkProtectedAccess(
444
+ req,
445
+ matchingEnv,
446
+ userToken,
447
+ lookupResult.users,
448
+ { domain: host },
449
+ );
450
+ if (protectionError) {
451
+ return makeErrorContext(
452
+ base,
453
+ protectionError.status,
454
+ protectionError.message,
455
+ token,
456
+ protectionError.redirectUrl,
457
+ );
385
458
  }
386
459
 
387
460
  logger?.info("Resolved custom domain to project", {
@@ -425,27 +498,35 @@ export function createProxyHandler(options: ProxyHandlerOptions) {
425
498
  targetEnvName: parsedDomain.environment,
426
499
  });
427
500
  } else if (projectSlug && scope === "preview" && token) {
428
- // For preview mode, we need projectId to fetch project metadata (e.g., layout config)
429
- // but we don't need releaseId since preview uses branch-based content
430
- const lookupResult = await lookupProjectByDomain(
431
- projectSlug,
432
- config.apiBaseUrl,
501
+ // Preview uses branch-based content (no releaseId needed), but must
502
+ // still enforce the environment's `protected` flag like other scopes.
503
+ const resolved = await resolveReleaseAndProtection(
504
+ req,
433
505
  token,
434
- logger,
506
+ userToken,
507
+ projectSlug,
508
+ (env) => env.name.toLowerCase() === "preview",
509
+ { projectSlug },
435
510
  );
436
511
 
437
- if (lookupResult) {
438
- projectId = lookupResult.id;
439
-
440
- // Find preview environment for env var resolution
441
- const previewEnv = lookupResult.environments?.find(
442
- (env) => env.name.toLowerCase() === "preview",
512
+ if ("error" in resolved) {
513
+ return makeErrorContext(
514
+ base,
515
+ resolved.error.status,
516
+ resolved.error.message,
517
+ token,
518
+ resolved.error.redirectUrl,
443
519
  );
444
- environmentId = previewEnv?.id;
520
+ }
521
+
522
+ projectId = resolved.projectId;
523
+ environmentId = resolved.environmentId;
445
524
 
525
+ if (projectId) {
446
526
  logger?.info("Resolved preview project", {
447
527
  projectSlug,
448
528
  projectId,
529
+ environmentId,
449
530
  });
450
531
  }
451
532
  }
@@ -11,7 +11,7 @@ import { enhanceAdapterWithFS } from "../platform/adapters/fs/integration.js";
11
11
  import { isExtendedFSAdapter } from "../platform/adapters/fs/wrapper.js";
12
12
  import { getEnv } from "../platform/compat/process.js";
13
13
  import { initializeEsbuild } from "../platform/compat/esbuild.js";
14
- import { logger } from "../utils/index.js";
14
+ import { logger, refreshLoggerConfig } from "../utils/index.js";
15
15
  import { isDebugEnabled } from "../utils/constants/env.js";
16
16
  import {
17
17
  getEnvSource,
@@ -59,6 +59,7 @@ async function ensureEnvLoaded(projectDir: string, adapter: RuntimeAdapter): Pro
59
59
  debug: isDebugEnabled(adapter.env),
60
60
  });
61
61
  refreshEnvironmentConfig();
62
+ refreshLoggerConfig();
62
63
  } catch (error) {
63
64
  bootstrapLog.warn("Failed to load .env files", {
64
65
  error: getErrorMessage(error),
@@ -18,6 +18,7 @@ export {
18
18
  agentLogger,
19
19
  bundlerLogger,
20
20
  logger,
21
+ refreshLoggerConfig,
21
22
  rendererLogger,
22
23
  serverLogger,
23
24
  } from "./logger/index.js";
@@ -21,6 +21,7 @@ export {
21
21
  logger,
22
22
  LogLevel,
23
23
  proxyLogger,
24
+ refreshLoggerConfig,
24
25
  rendererLogger,
25
26
  serverLogger,
26
27
  } from "./logger.js";
@@ -89,52 +89,33 @@ type LoggerConfig = {
89
89
  format: LogFormat;
90
90
  };
91
91
 
92
- let cachedConfig: LoggerConfig | null = null;
93
- let cachedEnvLevel: string | undefined;
94
- let cachedDebugFlag: string | undefined;
95
- let cachedEnvFormat: string | undefined;
96
- let cachedEnvMode: string | undefined;
92
+ // ---- Config helpers (must be declared before the eager init below) ----
93
+
94
+ const LOG_LEVEL_MAP: Record<string, LogLevel> = {
95
+ DEBUG: LogLevel.DEBUG,
96
+ INFO: LogLevel.INFO,
97
+ WARN: LogLevel.WARN,
98
+ ERROR: LogLevel.ERROR,
99
+ };
100
+
101
+ function parseLogLevel(levelString: string | undefined): LogLevel | undefined {
102
+ if (!levelString) return undefined;
103
+ return LOG_LEVEL_MAP[levelString.toUpperCase()];
104
+ }
97
105
 
98
106
  /**
99
- * Reset the cached logger configuration.
100
- * This is only intended for testing purposes to ensure fresh config evaluation.
107
+ * Determine the log level based on environment variables.
108
+ * Exported for testing purposes.
101
109
  * @internal
102
110
  */
103
- export function __resetLoggerConfigForTests(): void {
104
- cachedConfig = null;
105
- cachedEnvLevel = undefined;
106
- cachedDebugFlag = undefined;
107
- cachedEnvFormat = undefined;
108
- cachedEnvMode = undefined;
109
- }
110
-
111
- function resolveLoggerConfig(): LoggerConfig {
112
- const envLevel = getEnv("LOG_LEVEL");
113
- const debugFlag = getEnv("VERYFRONT_DEBUG");
114
- const envFormat = getEnv("LOG_FORMAT");
115
- const envMode = getEnv("NODE_ENV");
116
-
117
- if (
118
- cachedConfig &&
119
- envLevel === cachedEnvLevel &&
120
- debugFlag === cachedDebugFlag &&
121
- envFormat === cachedEnvFormat &&
122
- envMode === cachedEnvMode
123
- ) {
124
- return cachedConfig;
125
- }
126
-
127
- cachedEnvLevel = envLevel;
128
- cachedDebugFlag = debugFlag;
129
- cachedEnvFormat = envFormat;
130
- cachedEnvMode = envMode;
131
-
132
- cachedConfig = {
133
- level: getDefaultLevel(envLevel, debugFlag),
134
- format: getDefaultFormat(envFormat, envMode),
135
- };
136
-
137
- return cachedConfig;
111
+ export function getDefaultLevel(
112
+ envLevel: string | undefined = getEnv("LOG_LEVEL"),
113
+ debugFlag: string | undefined = getEnv("VERYFRONT_DEBUG"),
114
+ ): LogLevel {
115
+ const parsedLevel = parseLogLevel(envLevel);
116
+ if (parsedLevel !== undefined) return parsedLevel;
117
+ if (debugFlag === "1" || debugFlag === "true") return LogLevel.DEBUG;
118
+ return LogLevel.INFO;
138
119
  }
139
120
 
140
121
  /**
@@ -149,6 +130,37 @@ function getDefaultFormat(
149
130
  return envMode === "production" ? "json" : "text";
150
131
  }
151
132
 
133
+ // ---- Eager config resolution ----
134
+
135
+ /**
136
+ * Eagerly resolved at module load time so the config is captured from
137
+ * host process env vars BEFORE any per-request project env overlay is
138
+ * active. The project overlay blocks access to host env (for security),
139
+ * which would cause the logger to fall back to "text" format during SSR.
140
+ */
141
+ let loggerConfig: LoggerConfig = {
142
+ level: getDefaultLevel(),
143
+ format: getDefaultFormat(),
144
+ };
145
+
146
+ /**
147
+ * Re-read logger configuration from environment variables.
148
+ * Call after loading .env files so the logger picks up any overrides.
149
+ */
150
+ export function refreshLoggerConfig(): void {
151
+ loggerConfig = {
152
+ level: getDefaultLevel(),
153
+ format: getDefaultFormat(),
154
+ };
155
+ }
156
+
157
+ /** @internal Alias kept for tests. */
158
+ export const __resetLoggerConfigForTests = refreshLoggerConfig;
159
+
160
+ function resolveLoggerConfig(): LoggerConfig {
161
+ return loggerConfig;
162
+ }
163
+
152
164
  /**
153
165
  * Extract context from variadic args.
154
166
  * First object argument becomes context, errors are handled specially.
@@ -361,33 +373,6 @@ class ConsoleLogger implements Logger {
361
373
  }
362
374
  }
363
375
 
364
- const LOG_LEVEL_MAP: Record<string, LogLevel> = {
365
- DEBUG: LogLevel.DEBUG,
366
- INFO: LogLevel.INFO,
367
- WARN: LogLevel.WARN,
368
- ERROR: LogLevel.ERROR,
369
- };
370
-
371
- function parseLogLevel(levelString: string | undefined): LogLevel | undefined {
372
- if (!levelString) return undefined;
373
- return LOG_LEVEL_MAP[levelString.toUpperCase()];
374
- }
375
-
376
- /**
377
- * Determine the log level based on environment variables.
378
- * Exported for testing purposes.
379
- * @internal
380
- */
381
- export function getDefaultLevel(
382
- envLevel: string | undefined = getEnv("LOG_LEVEL"),
383
- debugFlag: string | undefined = getEnv("VERYFRONT_DEBUG"),
384
- ): LogLevel {
385
- const parsedLevel = parseLogLevel(envLevel);
386
- if (parsedLevel !== undefined) return parsedLevel;
387
- if (debugFlag === "1" || debugFlag === "true") return LogLevel.DEBUG;
388
- return LogLevel.INFO;
389
- }
390
-
391
376
  function createLogger(prefix: string): ConsoleLogger {
392
377
  return new ConsoleLogger(prefix);
393
378
  }