veryfront 0.0.82 → 0.0.84

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.
Files changed (126) hide show
  1. package/README.md +18 -17
  2. package/esm/deno.js +1 -1
  3. package/esm/proxy/cache/index.d.ts +41 -0
  4. package/esm/proxy/cache/index.d.ts.map +1 -0
  5. package/esm/proxy/cache/index.js +75 -0
  6. package/esm/proxy/cache/memory-cache.d.ts +18 -0
  7. package/esm/proxy/cache/memory-cache.d.ts.map +1 -0
  8. package/esm/proxy/cache/memory-cache.js +100 -0
  9. package/esm/proxy/cache/redis-cache.d.ts +27 -0
  10. package/esm/proxy/cache/redis-cache.d.ts.map +1 -0
  11. package/esm/proxy/cache/redis-cache.js +183 -0
  12. package/esm/proxy/cache/resilient-cache.d.ts +44 -0
  13. package/esm/proxy/cache/resilient-cache.d.ts.map +1 -0
  14. package/esm/proxy/cache/resilient-cache.js +178 -0
  15. package/esm/proxy/cache/types.d.ts +65 -0
  16. package/esm/proxy/cache/types.d.ts.map +1 -0
  17. package/esm/proxy/cache/types.js +7 -0
  18. package/esm/proxy/handler.d.ts +81 -0
  19. package/esm/proxy/handler.d.ts.map +1 -0
  20. package/esm/proxy/handler.js +417 -0
  21. package/esm/proxy/logger.d.ts +29 -0
  22. package/esm/proxy/logger.d.ts.map +1 -0
  23. package/esm/proxy/logger.js +258 -0
  24. package/esm/proxy/oauth-client.d.ts +15 -0
  25. package/esm/proxy/oauth-client.d.ts.map +1 -0
  26. package/esm/proxy/oauth-client.js +52 -0
  27. package/esm/proxy/token-manager.d.ts +59 -0
  28. package/esm/proxy/token-manager.d.ts.map +1 -0
  29. package/esm/proxy/token-manager.js +125 -0
  30. package/esm/proxy/tracing.d.ts +39 -0
  31. package/esm/proxy/tracing.d.ts.map +1 -0
  32. package/esm/proxy/tracing.js +194 -0
  33. package/esm/src/cache/backend.d.ts +2 -0
  34. package/esm/src/cache/backend.d.ts.map +1 -1
  35. package/esm/src/cache/backend.js +2 -0
  36. package/esm/src/cache/cache-key-builder.d.ts +0 -4
  37. package/esm/src/cache/cache-key-builder.d.ts.map +1 -1
  38. package/esm/src/cache/cache-key-builder.js +0 -6
  39. package/esm/src/cache/multi-tier.d.ts +0 -29
  40. package/esm/src/cache/multi-tier.d.ts.map +1 -1
  41. package/esm/src/cache/multi-tier.js +0 -26
  42. package/esm/src/cli/app/actions.d.ts +26 -0
  43. package/esm/src/cli/app/actions.d.ts.map +1 -0
  44. package/esm/src/cli/app/actions.js +152 -0
  45. package/esm/src/cli/app/components/inline-input.d.ts +35 -0
  46. package/esm/src/cli/app/components/inline-input.d.ts.map +1 -0
  47. package/esm/src/cli/app/components/inline-input.js +220 -0
  48. package/esm/src/cli/app/components/list-select.d.ts +69 -0
  49. package/esm/src/cli/app/components/list-select.d.ts.map +1 -0
  50. package/esm/src/cli/app/components/list-select.js +137 -0
  51. package/esm/src/cli/app/index.d.ts +45 -0
  52. package/esm/src/cli/app/index.d.ts.map +1 -0
  53. package/esm/src/cli/app/index.js +1252 -0
  54. package/esm/src/cli/app/state.d.ts +122 -0
  55. package/esm/src/cli/app/state.d.ts.map +1 -0
  56. package/esm/src/cli/app/state.js +232 -0
  57. package/esm/src/cli/app/views/dashboard.d.ts +19 -0
  58. package/esm/src/cli/app/views/dashboard.d.ts.map +1 -0
  59. package/esm/src/cli/app/views/dashboard.js +178 -0
  60. package/esm/src/cli/commands/dev.js +2 -2
  61. package/esm/src/cli/commands/new.js +1 -1
  62. package/esm/src/cli/index/command-router.d.ts.map +1 -1
  63. package/esm/src/cli/index/command-router.js +9 -39
  64. package/esm/src/cli/index/start-handler.d.ts +3 -0
  65. package/esm/src/cli/index/start-handler.d.ts.map +1 -0
  66. package/esm/src/cli/index/start-handler.js +145 -0
  67. package/esm/src/cli/mcp/index.d.ts +11 -0
  68. package/esm/src/cli/mcp/index.d.ts.map +1 -0
  69. package/esm/src/cli/mcp/index.js +10 -0
  70. package/esm/src/cli/ui/tui.js +1 -1
  71. package/esm/src/middleware/builtin/security/redis-rate-limit.d.ts +2 -0
  72. package/esm/src/middleware/builtin/security/redis-rate-limit.d.ts.map +1 -1
  73. package/esm/src/middleware/builtin/security/redis-rate-limit.js +23 -9
  74. package/esm/src/modules/react-loader/ssr-module-loader/cache/redis.d.ts +10 -0
  75. package/esm/src/modules/react-loader/ssr-module-loader/cache/redis.d.ts.map +1 -1
  76. package/esm/src/modules/react-loader/ssr-module-loader/cache/redis.js +30 -42
  77. package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
  78. package/esm/src/modules/react-loader/ssr-module-loader/loader.js +34 -13
  79. package/esm/src/platform/adapters/fs/cache/file-cache.d.ts.map +1 -1
  80. package/esm/src/platform/adapters/fs/cache/file-cache.js +9 -3
  81. package/esm/src/server/context/cache-invalidation.d.ts.map +1 -1
  82. package/esm/src/server/context/cache-invalidation.js +4 -0
  83. package/esm/src/server/handlers/dev/dashboard/api.js +4 -0
  84. package/esm/src/server/handlers/dev/projects/ui-handler.d.ts.map +1 -1
  85. package/esm/src/server/handlers/dev/projects/ui-handler.js +6 -0
  86. package/esm/src/transforms/esm/http-cache.d.ts.map +1 -1
  87. package/esm/src/transforms/esm/http-cache.js +139 -64
  88. package/esm/src/utils/index.d.ts +1 -1
  89. package/esm/src/utils/index.d.ts.map +1 -1
  90. package/esm/src/utils/index.js +1 -1
  91. package/package.json +2 -1
  92. package/src/deno.js +1 -1
  93. package/src/proxy/cache/index.ts +93 -0
  94. package/src/proxy/cache/memory-cache.ts +120 -0
  95. package/src/proxy/cache/redis-cache.ts +203 -0
  96. package/src/proxy/cache/resilient-cache.ts +205 -0
  97. package/src/proxy/cache/types.ts +72 -0
  98. package/src/proxy/handler.ts +593 -0
  99. package/src/proxy/logger.ts +329 -0
  100. package/src/proxy/oauth-client.ts +91 -0
  101. package/src/proxy/token-manager.ts +174 -0
  102. package/src/proxy/tracing.ts +237 -0
  103. package/src/src/cache/backend.ts +3 -0
  104. package/src/src/cache/cache-key-builder.ts +0 -9
  105. package/src/src/cache/multi-tier.ts +0 -41
  106. package/src/src/cli/app/actions.ts +190 -0
  107. package/src/src/cli/app/components/inline-input.ts +255 -0
  108. package/src/src/cli/app/components/list-select.ts +215 -0
  109. package/src/src/cli/app/index.ts +1471 -0
  110. package/src/src/cli/app/state.ts +385 -0
  111. package/src/src/cli/app/views/dashboard.ts +212 -0
  112. package/src/src/cli/commands/dev.ts +2 -2
  113. package/src/src/cli/commands/new.ts +1 -1
  114. package/src/src/cli/index/command-router.ts +9 -40
  115. package/src/src/cli/index/start-handler.ts +195 -0
  116. package/src/src/cli/mcp/index.ts +11 -0
  117. package/src/src/cli/ui/tui.ts +1 -1
  118. package/src/src/middleware/builtin/security/redis-rate-limit.ts +24 -11
  119. package/src/src/modules/react-loader/ssr-module-loader/cache/redis.ts +36 -50
  120. package/src/src/modules/react-loader/ssr-module-loader/loader.ts +38 -14
  121. package/src/src/platform/adapters/fs/cache/file-cache.ts +9 -3
  122. package/src/src/server/context/cache-invalidation.ts +4 -0
  123. package/src/src/server/handlers/dev/dashboard/api.ts +2 -0
  124. package/src/src/server/handlers/dev/projects/ui-handler.ts +6 -0
  125. package/src/src/transforms/esm/http-cache.ts +148 -73
  126. package/src/src/utils/index.ts +0 -1
@@ -0,0 +1,417 @@
1
+ /**
2
+ * Proxy Handler - Core Logic
3
+ *
4
+ * Extracted proxy logic that can be used in:
5
+ * - Split mode: Standalone proxy server (proxy/main.ts)
6
+ * - Combined mode: Request interceptor in renderer process
7
+ *
8
+ * Handles:
9
+ * - Domain parsing (subdomain to project slug)
10
+ * - OAuth token management
11
+ * - Local project detection
12
+ * - User auth token extraction from cookies
13
+ */
14
+ import * as dntShim from "../_dnt.shims.js";
15
+ import { TokenManager } from "./token-manager.js";
16
+ import { parseProjectDomain } from "../src/server/utils/domain-parser.js";
17
+ import { createFileSystem } from "../src/platform/compat/fs.js";
18
+ import { cwd } from "../src/platform/compat/process.js";
19
+ import { join } from "../src/platform/compat/path/index.js";
20
+ import { injectContext, ProxySpanNames, withSpan } from "./tracing.js";
21
+ import { computeContentSourceId } from "../src/cache/keys.js";
22
+ /**
23
+ * Look up project info by custom domain.
24
+ * Uses GET /projects/{domain} to resolve project slug when request comes via custom domain.
25
+ */
26
+ async function lookupProjectByDomain(domain, apiBaseUrl, token, logger) {
27
+ return await withSpan(ProxySpanNames.PROXY_DOMAIN_LOOKUP, async () => {
28
+ const domainWithoutPort = domain.replace(/:\d+$/, "");
29
+ const url = `${apiBaseUrl}/projects/${encodeURIComponent(domainWithoutPort)}`;
30
+ const urlObj = new URL(url);
31
+ logger?.debug("Looking up project by domain", { domain, url });
32
+ const headers = new dntShim.Headers({
33
+ Authorization: `Bearer ${token}`,
34
+ Accept: "application/json",
35
+ });
36
+ injectContext(headers);
37
+ try {
38
+ const response = await withSpan(ProxySpanNames.HTTP_CLIENT_FETCH, () => dntShim.fetch(url, { headers }), {
39
+ "http.method": "GET",
40
+ "http.url": url,
41
+ "http.host": urlObj.host,
42
+ "proxy.domain_lookup": domain,
43
+ });
44
+ if (!response.ok) {
45
+ // Consume response body to prevent resource leak
46
+ await response.body?.cancel();
47
+ if (response.status !== 404) {
48
+ logger?.error("Domain lookup API error", undefined, {
49
+ domain,
50
+ status: response.status,
51
+ statusText: response.statusText,
52
+ });
53
+ }
54
+ return null;
55
+ }
56
+ const result = await response.json();
57
+ logger?.debug("Domain lookup successful", {
58
+ domain,
59
+ projectSlug: result.slug,
60
+ environments: result.environments?.map((e) => e.name),
61
+ });
62
+ return result;
63
+ }
64
+ catch (error) {
65
+ logger?.error("Domain lookup failed", error, { domain });
66
+ return null;
67
+ }
68
+ }, { "proxy.domain": domain });
69
+ }
70
+ /**
71
+ * Determine the OAuth scope based on the parsed domain environment.
72
+ */
73
+ function getScope(environment) {
74
+ return environment === "preview" ? "preview" : "production";
75
+ }
76
+ /**
77
+ * Extract user auth token from cookie header.
78
+ */
79
+ function extractUserToken(cookieHeader) {
80
+ const authTokenMatch = cookieHeader.match(/(?:^|;\s*)authToken=([^;]+)/);
81
+ return authTokenMatch?.[1] ? decodeURIComponent(authTokenMatch[1]) : undefined;
82
+ }
83
+ /**
84
+ * Create a proxy handler that processes requests and returns context.
85
+ *
86
+ * This is the core proxy logic, usable in both split and combined modes.
87
+ */
88
+ export function createProxyHandler(options) {
89
+ const { config, cache, logger } = options;
90
+ const localProjects = config.localProjects ?? {};
91
+ // Dynamic project discovery - check if project exists in common directories
92
+ const fs = createFileSystem();
93
+ async function findLocalProject(slug) {
94
+ // First check the static map
95
+ if (localProjects[slug]) {
96
+ return localProjects[slug];
97
+ }
98
+ // Dynamically check common project directories - parallelized for performance
99
+ const projectDirs = ["projects", "data/projects", "examples"];
100
+ const basePath = cwd();
101
+ // Check all directories in parallel
102
+ const candidatePaths = projectDirs.map((dir) => join(basePath, dir, slug));
103
+ const existsResults = await Promise.all(candidatePaths.map(async (projectPath) => {
104
+ try {
105
+ const exists = await fs.exists(projectPath);
106
+ return exists ? projectPath : null;
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }));
112
+ // For each existing path, check app/pages/components in parallel
113
+ for (const projectPath of existsResults) {
114
+ if (!projectPath)
115
+ continue;
116
+ try {
117
+ const [hasApp, hasPages, hasComponents] = await Promise.all([
118
+ fs.exists(join(projectPath, "app")),
119
+ fs.exists(join(projectPath, "pages")),
120
+ fs.exists(join(projectPath, "components")),
121
+ ]);
122
+ if (hasApp || hasPages || hasComponents) {
123
+ // Cache for future requests
124
+ localProjects[slug] = projectPath;
125
+ logger?.debug("Dynamically discovered local project", {
126
+ slug,
127
+ projectPath,
128
+ });
129
+ return projectPath;
130
+ }
131
+ }
132
+ catch {
133
+ // Directory check failed, continue
134
+ }
135
+ }
136
+ return undefined;
137
+ }
138
+ // Create token manager
139
+ const tokenManager = new TokenManager({
140
+ apiBaseUrl: config.apiBaseUrl,
141
+ clientId: config.clientId,
142
+ clientSecret: config.clientSecret,
143
+ previewClientId: config.previewClientId,
144
+ previewClientSecret: config.previewClientSecret,
145
+ }, { cache });
146
+ /**
147
+ * Validate configuration and return missing credentials.
148
+ */
149
+ function validateConfig() {
150
+ const missing = [];
151
+ if (!config.clientId) {
152
+ missing.push("API_CLIENT_ID_VERYFRONT_RENDERER_PROXY");
153
+ }
154
+ if (!config.clientSecret) {
155
+ missing.push("API_CLIENT_SECRET_VERYFRONT_RENDERER_PROXY");
156
+ }
157
+ return missing;
158
+ }
159
+ async function processRequest(req) {
160
+ const host = req.headers.get("host") || "";
161
+ const parsedDomain = parseProjectDomain(host);
162
+ const scope = getScope(parsedDomain.environment);
163
+ let projectSlug = parsedDomain.slug || undefined;
164
+ let projectId;
165
+ let releaseId;
166
+ const isCustomDomain = !projectSlug && !parsedDomain.isVeryfrontDomain;
167
+ // Handle veryfront domain without project slug (e.g., veryfront.me:8080)
168
+ // Return a no-project context so the projects page can be served
169
+ if (!projectSlug && parsedDomain.isVeryfrontDomain && !isCustomDomain) {
170
+ return {
171
+ token: undefined,
172
+ projectSlug: undefined,
173
+ projectId: undefined,
174
+ environment: "preview",
175
+ contentSourceId: "no-project",
176
+ localPath: undefined,
177
+ host,
178
+ parsedDomain,
179
+ isLocalProject: false,
180
+ };
181
+ }
182
+ const localPath = projectSlug ? await findLocalProject(projectSlug) : undefined;
183
+ const isLocalProject = !!localPath;
184
+ logger?.debug("Processing request", {
185
+ host,
186
+ projectSlug,
187
+ environment: scope,
188
+ isLocalProject,
189
+ isCustomDomain,
190
+ });
191
+ const makeErrorContext = (status, message, token, redirectUrl) => ({
192
+ token,
193
+ projectSlug: undefined,
194
+ projectId: undefined,
195
+ environment: scope,
196
+ contentSourceId: "error",
197
+ localPath: undefined,
198
+ host,
199
+ parsedDomain,
200
+ isLocalProject: false,
201
+ error: { status, message, redirectUrl },
202
+ });
203
+ let token;
204
+ // Extract user auth token from cookies (used for preview scope and protected env check)
205
+ const cookieHeader = req.headers.get("cookie") || "";
206
+ const userToken = extractUserToken(cookieHeader);
207
+ if (isLocalProject) {
208
+ logger?.debug("Local project, skipping token fetch", { localPath });
209
+ }
210
+ else {
211
+ if (scope === "preview" && userToken) {
212
+ token = userToken;
213
+ logger?.debug("Using user auth token for preview");
214
+ }
215
+ if (!token && config.clientId && config.clientSecret) {
216
+ const customDomain = !projectSlug ? host : undefined;
217
+ if (projectSlug || customDomain) {
218
+ try {
219
+ token = await tokenManager.getToken(scope, projectSlug, customDomain);
220
+ }
221
+ catch (error) {
222
+ logger?.error("Token fetch failed", error, {
223
+ projectSlug,
224
+ customDomain,
225
+ });
226
+ }
227
+ }
228
+ }
229
+ if (!token && config.apiToken) {
230
+ token = config.apiToken;
231
+ logger?.debug("Using static API token fallback");
232
+ }
233
+ if (isCustomDomain && !projectSlug) {
234
+ // Custom domain: lookup project by domain
235
+ if (!token) {
236
+ logger?.error("Cannot process custom domain without token", undefined, { domain: host });
237
+ return makeErrorContext(502, `Failed to authenticate for domain: ${host}`, token);
238
+ }
239
+ const lookupResult = await lookupProjectByDomain(host, config.apiBaseUrl, token, logger);
240
+ if (lookupResult) {
241
+ projectSlug = lookupResult.slug;
242
+ projectId = lookupResult.id;
243
+ // Find matching environment for this domain and extract active release
244
+ const normalizedHost = host.toLowerCase().replace(/:\d+$/, "");
245
+ const matchingEnv = lookupResult.environments?.find((env) => env.domains?.some((d) => d.toLowerCase() === normalizedHost));
246
+ if (matchingEnv?.active_release_id) {
247
+ releaseId = matchingEnv.active_release_id;
248
+ }
249
+ // Check if environment is protected and user is not authenticated
250
+ if (matchingEnv?.protected && !userToken) {
251
+ const originalUrl = req.url;
252
+ const redirectUrl = `https://veryfront.com/sign-in?from=${encodeURIComponent(originalUrl)}`;
253
+ logger?.info("Protected environment requires authentication", {
254
+ domain: host,
255
+ environmentName: matchingEnv.name,
256
+ redirectUrl,
257
+ });
258
+ return makeErrorContext(302, "Authentication required", token, redirectUrl);
259
+ }
260
+ logger?.info("Resolved custom domain to project", {
261
+ domain: host,
262
+ projectSlug,
263
+ projectId,
264
+ releaseId,
265
+ environmentName: matchingEnv?.name,
266
+ });
267
+ }
268
+ else {
269
+ logger?.error("Custom domain not found", undefined, { domain: host });
270
+ return makeErrorContext(404, `No project configured for domain: ${host}`, token);
271
+ }
272
+ }
273
+ else if (projectSlug && scope === "production" && token &&
274
+ parsedDomain.environment) {
275
+ // Veryfront domain in non-preview mode: lookup project by slug to get releaseId
276
+ // This handles production, staging, and other non-preview environments
277
+ const lookupResult = await lookupProjectByDomain(projectSlug, config.apiBaseUrl, token, logger);
278
+ if (lookupResult) {
279
+ projectId = lookupResult.id;
280
+ // Find environment matching the parsed domain's environment (e.g., "staging", "production")
281
+ const matchingEnv = lookupResult.environments?.find((env) => env.name.toLowerCase() === parsedDomain.environment.toLowerCase());
282
+ if (matchingEnv?.active_release_id) {
283
+ releaseId = matchingEnv.active_release_id;
284
+ }
285
+ // Check if environment is protected and user is not authenticated
286
+ if (matchingEnv?.protected && !userToken) {
287
+ const originalUrl = req.url;
288
+ const redirectUrl = `https://veryfront.com/sign-in?from=${encodeURIComponent(originalUrl)}`;
289
+ logger?.info("Protected environment requires authentication", {
290
+ projectSlug,
291
+ environmentName: matchingEnv.name,
292
+ redirectUrl,
293
+ });
294
+ return makeErrorContext(302, "Authentication required", token, redirectUrl);
295
+ }
296
+ logger?.info("Resolved veryfront domain to project", {
297
+ projectSlug,
298
+ projectId,
299
+ releaseId,
300
+ targetEnvName: parsedDomain.environment,
301
+ environmentName: matchingEnv?.name,
302
+ });
303
+ }
304
+ }
305
+ }
306
+ // Error early if remote production but no releaseId
307
+ if (scope === "production" && projectSlug && !releaseId && !isLocalProject) {
308
+ logger?.error("Missing releaseId in production", undefined, {
309
+ projectSlug,
310
+ projectId,
311
+ host,
312
+ environment: scope,
313
+ });
314
+ return makeErrorContext(502, `Missing releaseId for production project: ${projectSlug}`, token);
315
+ }
316
+ // Compute contentSourceId using the single source of truth
317
+ const contentSourceId = computeContentSourceId(isLocalProject, scope, parsedDomain.branch, releaseId);
318
+ return {
319
+ token,
320
+ projectSlug,
321
+ projectId,
322
+ releaseId,
323
+ contentSourceId,
324
+ environment: scope,
325
+ localPath,
326
+ host,
327
+ parsedDomain,
328
+ isLocalProject,
329
+ };
330
+ }
331
+ /**
332
+ * Get token for API proxy requests.
333
+ */
334
+ async function getTokenForApi(req) {
335
+ const host = req.headers.get("host") || "";
336
+ const parsedDomain = parseProjectDomain(host);
337
+ const scope = getScope(parsedDomain.environment);
338
+ const projectSlug = parsedDomain.slug || undefined;
339
+ // Try user token first for preview
340
+ if (scope === "preview") {
341
+ const cookieHeader = req.headers.get("cookie") || "";
342
+ const userToken = extractUserToken(cookieHeader);
343
+ if (userToken)
344
+ return userToken;
345
+ }
346
+ // Fall back to OAuth (requires projectSlug or customDomain for project-scoped tokens)
347
+ if (config.clientId && config.clientSecret) {
348
+ const customDomain = !projectSlug ? host : undefined;
349
+ if (projectSlug || customDomain) {
350
+ try {
351
+ return await tokenManager.getToken(scope, projectSlug, customDomain);
352
+ }
353
+ catch (error) {
354
+ logger?.error("Token fetch failed for API", error, {
355
+ projectSlug,
356
+ customDomain,
357
+ });
358
+ }
359
+ }
360
+ }
361
+ // Fall back to static API token
362
+ if (config.apiToken) {
363
+ return config.apiToken;
364
+ }
365
+ return undefined;
366
+ }
367
+ /**
368
+ * Get token manager stats for monitoring.
369
+ */
370
+ async function getStats() {
371
+ return await tokenManager.getStats();
372
+ }
373
+ /**
374
+ * Close the token manager and clean up resources.
375
+ */
376
+ async function close() {
377
+ await tokenManager.close();
378
+ }
379
+ return {
380
+ processRequest,
381
+ getTokenForApi,
382
+ getStats,
383
+ close,
384
+ validateConfig,
385
+ localProjects,
386
+ };
387
+ }
388
+ /**
389
+ * Inject proxy context into request headers for the renderer.
390
+ * Used by both split mode (proxy/main.ts) and combined mode (scripts/server.ts).
391
+ */
392
+ export function injectContextHeaders(req, ctx) {
393
+ const headers = new dntShim.Headers(req.headers);
394
+ if (ctx.token)
395
+ headers.set("x-token", ctx.token);
396
+ headers.set("x-project-slug", ctx.projectSlug || "");
397
+ headers.set("x-environment", ctx.environment);
398
+ headers.set("x-content-source-id", ctx.contentSourceId);
399
+ headers.set("x-forwarded-host", ctx.host);
400
+ if (ctx.localPath)
401
+ headers.set("x-project-path", ctx.localPath);
402
+ // Forward project/branch context for logging
403
+ if (ctx.projectId)
404
+ headers.set("x-project-id", ctx.projectId);
405
+ if (ctx.releaseId)
406
+ headers.set("x-release-id", ctx.releaseId);
407
+ if (ctx.branchId)
408
+ headers.set("x-branch-id", ctx.branchId);
409
+ if (ctx.branchName)
410
+ headers.set("x-branch-name", ctx.branchName);
411
+ return new dntShim.Request(req.url, {
412
+ method: req.method,
413
+ headers,
414
+ body: req.body,
415
+ redirect: "manual",
416
+ });
417
+ }
@@ -0,0 +1,29 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error";
2
+ declare class ProxyLogger {
3
+ private format;
4
+ private log;
5
+ debug(message: string, context?: Record<string, unknown>): void;
6
+ info(message: string, context?: Record<string, unknown>): void;
7
+ warn(message: string, context?: Record<string, unknown>): void;
8
+ error(message: string, error?: unknown): void;
9
+ error(message: string, context: Record<string, unknown>, error?: unknown): void;
10
+ /**
11
+ * Create a child logger with bound context.
12
+ */
13
+ child(context: Record<string, unknown>): ChildProxyLogger;
14
+ }
15
+ declare class ChildProxyLogger {
16
+ private parent;
17
+ private boundContext;
18
+ constructor(parent: ProxyLogger, boundContext: Record<string, unknown>);
19
+ private merge;
20
+ debug(message: string, context?: Record<string, unknown>): void;
21
+ info(message: string, context?: Record<string, unknown>): void;
22
+ warn(message: string, context?: Record<string, unknown>): void;
23
+ error(message: string, error?: unknown): void;
24
+ error(message: string, context: Record<string, unknown>, error?: unknown): void;
25
+ child(context: Record<string, unknown>): ChildProxyLogger;
26
+ }
27
+ export declare const proxyLogger: ProxyLogger;
28
+ export {};
29
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/proxy/logger.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAwL3D,cAAM,WAAW;IACf,OAAO,CAAC,MAAM,CAAkB;IAEhC,OAAO,CAAC,GAAG;IAiCX,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI9D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI;IAC7C,KAAK,CACH,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,OAAO,GACd,IAAI;IAiBP;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB;CAG1D;AAED,cAAM,gBAAgB;IAElB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,YAAY;gBADZ,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAG/C,OAAO,CAAC,KAAK;IAIb,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI9D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI;IAC7C,KAAK,CACH,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,OAAO,GACd,IAAI;IAoBP,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB;CAG1D;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC"}