veryfront 0.1.1119 → 0.1.1122
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 +1 -1
- package/esm/src/agent/ag-ui/runtime-chat-stream-encoder.d.ts.map +1 -1
- package/esm/src/agent/ag-ui/runtime-chat-stream-encoder.js +41 -4
- package/esm/src/agent/hosted/chat-runtime-tool-assembly.d.ts.map +1 -1
- package/esm/src/agent/hosted/chat-runtime-tool-assembly.js +35 -5
- package/esm/src/agent/input/human-input.d.ts.map +1 -1
- package/esm/src/agent/input/human-input.js +2 -6
- package/esm/src/agent/react/use-chat/streaming/handler.js +21 -0
- package/esm/src/agent/react/use-chat/streaming/parts-builder.js +1 -0
- package/esm/src/agent/react/use-chat/streaming/types.d.ts +2 -0
- package/esm/src/agent/react/use-chat/streaming/types.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +1 -0
- package/esm/src/agent/service/detached-run-tracker.d.ts.map +1 -1
- package/esm/src/agent/service/detached-run-tracker.js +1 -5
- package/esm/src/agent/service/registration.d.ts.map +1 -1
- package/esm/src/agent/service/registration.js +2 -6
- package/esm/src/agent/streaming/chat-ui-message-stream.d.ts.map +1 -1
- package/esm/src/agent/streaming/chat-ui-message-stream.js +24 -0
- package/esm/src/build/bundler/code-splitter/manifest-builder.d.ts +4 -0
- package/esm/src/build/bundler/code-splitter/manifest-builder.d.ts.map +1 -1
- package/esm/src/build/bundler/code-splitter/manifest-builder.js +2 -5
- package/esm/src/build/production-build/local-release-assets.js +2 -2
- package/esm/src/chat/conversation.d.ts.map +1 -1
- package/esm/src/chat/conversation.js +1 -5
- package/esm/src/chat/protocol.d.ts +6 -0
- package/esm/src/chat/protocol.d.ts.map +1 -1
- package/esm/src/discovery/transpiler.d.ts.map +1 -1
- package/esm/src/discovery/transpiler.js +4 -8
- package/esm/src/errors/error-handlers.d.ts +31 -3
- package/esm/src/errors/error-handlers.d.ts.map +1 -1
- package/esm/src/errors/error-handlers.js +33 -12
- package/esm/src/errors/index.d.ts +1 -1
- package/esm/src/errors/index.d.ts.map +1 -1
- package/esm/src/eval/agent-service/durable-run-canaries/runner.d.ts.map +1 -1
- package/esm/src/eval/agent-service/durable-run-canaries/runner.js +1 -5
- package/esm/src/eval/agent-service/live-evals/api-client.d.ts.map +1 -1
- package/esm/src/eval/agent-service/live-evals/api-client.js +3 -4
- package/esm/src/eval/provenance.d.ts.map +1 -1
- package/esm/src/eval/provenance.js +3 -13
- package/esm/src/eval/report.d.ts.map +1 -1
- package/esm/src/eval/report.js +2 -8
- package/esm/src/html/styles-builder/plugin-loader.d.ts.map +1 -1
- package/esm/src/html/styles-builder/plugin-loader.js +2 -13
- package/esm/src/knowledge/index.d.ts.map +1 -1
- package/esm/src/knowledge/index.js +2 -5
- package/esm/src/metrics/index.d.ts.map +1 -1
- package/esm/src/metrics/index.js +2 -1
- package/esm/src/oauth/providers/base.d.ts.map +1 -1
- package/esm/src/oauth/providers/base.js +2 -6
- package/esm/src/platform/adapters/fs/github/github-api-client.d.ts +0 -1
- package/esm/src/platform/adapters/fs/github/github-api-client.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/github/github-api-client.js +36 -37
- package/esm/src/platform/adapters/fs/veryfront/retry.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/retry.js +12 -14
- package/esm/src/platform/adapters/veryfront-api-client/retry-handler.d.ts.map +1 -1
- package/esm/src/platform/adapters/veryfront-api-client/retry-handler.js +82 -86
- package/esm/src/proxy/logger.d.ts +2 -1
- package/esm/src/proxy/logger.d.ts.map +1 -1
- package/esm/src/proxy/logger.js +1 -112
- package/esm/src/proxy/routing-invalidation-redis.d.ts.map +1 -1
- package/esm/src/proxy/routing-invalidation-redis.js +2 -5
- package/esm/src/proxy/server-resolver.d.ts.map +1 -1
- package/esm/src/proxy/server-resolver.js +2 -1
- package/esm/src/release-assets/build-executor.js +5 -5
- package/esm/src/release-assets/index.d.ts +0 -1
- package/esm/src/release-assets/index.d.ts.map +1 -1
- package/esm/src/release-assets/index.js +0 -1
- package/esm/src/rendering/orchestrator/module-loader/cache.d.ts +9 -0
- package/esm/src/rendering/orchestrator/module-loader/cache.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/cache.js +2 -11
- package/esm/src/routing/api/module-loader/esbuild-plugin.d.ts.map +1 -1
- package/esm/src/routing/api/module-loader/esbuild-plugin.js +2 -5
- package/esm/src/sandbox/lazy-sandbox.js +4 -4
- package/esm/src/security/http/auth.d.ts.map +1 -1
- package/esm/src/security/http/auth.js +1 -24
- package/esm/src/server/handlers/studio/bridge-modules.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/studio/bridge-modules.handler.js +2 -5
- package/esm/src/server/project-env/fetcher.js +2 -2
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.d.ts.map +1 -1
- package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.js +1 -1
- package/esm/src/server/services/rsc/orchestrators/stream-handler.js +1 -4
- package/esm/src/transforms/esm/transform-utils.d.ts.map +1 -1
- package/esm/src/transforms/esm/transform-utils.js +2 -1
- package/esm/src/transforms/mdx/compiler/import-rewriter.d.ts.map +1 -1
- package/esm/src/transforms/mdx/compiler/import-rewriter.js +2 -1
- package/esm/src/transforms/pipeline/stages/resolve-imports.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/stages/resolve-imports.js +3 -1
- package/esm/src/utils/base64url.d.ts +4 -3
- package/esm/src/utils/base64url.d.ts.map +1 -1
- package/esm/src/utils/base64url.js +30 -3
- package/esm/src/utils/hash-utils.d.ts +4 -1
- package/esm/src/utils/hash-utils.d.ts.map +1 -1
- package/esm/src/utils/hash-utils.js +9 -3
- package/esm/src/utils/index.d.ts +3 -1
- package/esm/src/utils/index.d.ts.map +1 -1
- package/esm/src/utils/index.js +3 -1
- package/esm/src/utils/sleep.d.ts +3 -0
- package/esm/src/utils/sleep.d.ts.map +1 -0
- package/esm/src/utils/sleep.js +18 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/esm/src/workflow/claude-code/workspace-sync.d.ts.map +1 -1
- package/esm/src/workflow/claude-code/workspace-sync.js +3 -13
- package/esm/src/workflow/executor/dag/composite-node-execution.d.ts.map +1 -1
- package/esm/src/workflow/executor/dag/composite-node-execution.js +3 -24
- package/esm/src/workflow/executor/dag/loop-node-strategy.js +1 -1
- package/esm/src/workflow/executor/dag/utils.d.ts +0 -1
- package/esm/src/workflow/executor/dag/utils.d.ts.map +1 -1
- package/esm/src/workflow/executor/dag/utils.js +0 -17
- package/esm/src/workflow/executor/retry-policy.d.ts +13 -0
- package/esm/src/workflow/executor/retry-policy.d.ts.map +1 -0
- package/esm/src/workflow/executor/retry-policy.js +44 -0
- package/esm/src/workflow/executor/step-executor.d.ts +1 -11
- package/esm/src/workflow/executor/step-executor.d.ts.map +1 -1
- package/esm/src/workflow/executor/step-executor.js +6 -57
- package/esm/src/workflow/executor/workflow-executor.d.ts.map +1 -1
- package/esm/src/workflow/executor/workflow-executor.js +2 -3
- package/esm/src/workflow/worker/workflow-worker.d.ts +0 -4
- package/esm/src/workflow/worker/workflow-worker.d.ts.map +1 -1
- package/esm/src/workflow/worker/workflow-worker.js +2 -9
- package/package.json +5 -5
- package/esm/src/release-assets/hash.d.ts +0 -14
- package/esm/src/release-assets/hash.d.ts.map +0 -1
- package/esm/src/release-assets/hash.js +0 -22
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as dntShim from "../../../_dnt.shims.js";
|
|
2
2
|
import { getEnv } from "../../platform/compat/process.js";
|
|
3
3
|
import { INVALID_ARGUMENT, TOKEN_STORAGE_ERROR } from "../../errors/index.js";
|
|
4
|
-
import { logger as baseLogger } from "../../utils/index.js";
|
|
4
|
+
import { base64urlEncodeBytes, logger as baseLogger } from "../../utils/index.js";
|
|
5
5
|
const logger = baseLogger.component("o-auth");
|
|
6
6
|
/** Buffer before token expiry to trigger proactive refresh (5 minutes). */
|
|
7
7
|
const TOKEN_REFRESH_BUFFER_MS = 300_000;
|
|
@@ -19,11 +19,7 @@ function generateCodeVerifier() {
|
|
|
19
19
|
}
|
|
20
20
|
async function generateCodeChallenge(verifier) {
|
|
21
21
|
const data = new TextEncoder().encode(verifier);
|
|
22
|
-
|
|
23
|
-
return btoa(String.fromCharCode(...new Uint8Array(hash)))
|
|
24
|
-
.replace(/\+/g, "-")
|
|
25
|
-
.replace(/\//g, "_")
|
|
26
|
-
.replace(/=+$/, "");
|
|
22
|
+
return base64urlEncodeBytes(new Uint8Array(await dntShim.crypto.subtle.digest("SHA-256", data)));
|
|
27
23
|
}
|
|
28
24
|
/** Implement oauth provider. */
|
|
29
25
|
export class OAuthProvider {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-api-client.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/github/github-api-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAO5B,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAID,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,aAAa,CAA8B;gBAEtB,MAAM,EAAE,oBAAoB;IAEzD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAEK,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmBlD,WAAW,CACf,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,GAAG,iBAAiB,EAAE,CAAC;IAY7C,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IASvD,gBAAgB,IAAI,aAAa,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"github-api-client.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/github/github-api-client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAO5B,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAID,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,aAAa,CAA8B;gBAEtB,MAAM,EAAE,oBAAoB;IAEzD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAEK,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmBlD,WAAW,CACf,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,GAAG,iBAAiB,EAAE,CAAC;IAY7C,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IASvD,gBAAgB,IAAI,aAAa,GAAG,IAAI;IAIxC,OAAO,CAAC,OAAO;IAiDf,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,cAAc;IAkDtB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,mBAAmB;CAa5B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createError, toError } from "../../../../errors/index.js";
|
|
1
|
+
import { createError, retryWithBackoff, toError } from "../../../../errors/index.js";
|
|
2
2
|
import { logger } from "../../../../utils/index.js";
|
|
3
3
|
import { getGitHubBlobResponseSchema, getGitHubContentsResponseSchema, getGitHubTreeResponseSchema, } from "./schemas/index.js";
|
|
4
4
|
const LOG_PREFIX = "[GitHubApiClient]";
|
|
@@ -42,43 +42,46 @@ export class GitHubApiClient {
|
|
|
42
42
|
getRateLimitInfo() {
|
|
43
43
|
return this.rateLimitInfo;
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
request(endpoint) {
|
|
46
46
|
const url = `${this.baseUrl}${endpoint}`;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const errorBody = await response.text();
|
|
61
|
-
throw this.createAPIError(response.status, errorBody, endpoint);
|
|
62
|
-
}
|
|
63
|
-
return await response.json();
|
|
47
|
+
return retryWithBackoff(async () => {
|
|
48
|
+
const response = await fetch(url, {
|
|
49
|
+
headers: {
|
|
50
|
+
Authorization: `Bearer ${this.config.token}`,
|
|
51
|
+
Accept: "application/vnd.github.v3+json",
|
|
52
|
+
"User-Agent": "veryfront-server",
|
|
53
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
this.updateRateLimitInfo(response);
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
const errorBody = await response.text();
|
|
59
|
+
throw this.createAPIError(response.status, errorBody, endpoint);
|
|
64
60
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
61
|
+
return response.json();
|
|
62
|
+
}, {
|
|
63
|
+
// This client's config.retry.maxRetries has always meant TOTAL attempts
|
|
64
|
+
// (the old loop ran `attempt = 1..maxRetries`), unlike the veryfront-api
|
|
65
|
+
// clients where maxRetries means retries after the first try.
|
|
66
|
+
maxAttempts: this.config.retry.maxRetries,
|
|
67
|
+
initialDelay: this.config.retry.initialDelay,
|
|
68
|
+
maxDelay: this.config.retry.maxDelay,
|
|
69
|
+
shouldRetry: (error) => {
|
|
70
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
71
|
+
return !(this.isClientError(err) && !this.isRateLimitError(err));
|
|
72
|
+
},
|
|
73
|
+
computeDelay: (attempt, error) => {
|
|
74
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
75
|
+
return this.calculateRetryDelay(attempt + 1, err);
|
|
76
|
+
},
|
|
77
|
+
onRetry: ({ error, attempt, delay }) => {
|
|
73
78
|
logger.warn(`${LOG_PREFIX} Request failed, retrying`, {
|
|
74
|
-
attempt,
|
|
79
|
+
attempt: attempt + 1,
|
|
75
80
|
delay,
|
|
76
|
-
error:
|
|
81
|
+
error: error.message,
|
|
77
82
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
throw lastError ?? new Error("Request failed after retries");
|
|
83
|
+
},
|
|
84
|
+
});
|
|
82
85
|
}
|
|
83
86
|
updateRateLimitInfo(response) {
|
|
84
87
|
const limit = response.headers.get("X-RateLimit-Limit");
|
|
@@ -157,8 +160,4 @@ export class GitHubApiClient {
|
|
|
157
160
|
const delay = Math.min(this.config.retry.initialDelay * Math.pow(2, attempt - 1), this.config.retry.maxDelay);
|
|
158
161
|
return delay + Math.random() * RETRY_JITTER_MAX_MS;
|
|
159
162
|
}
|
|
160
|
-
// no cleanup needed: one-shot
|
|
161
|
-
sleep(ms) {
|
|
162
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
163
|
-
}
|
|
164
163
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiDH;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,CAAC,CAAC,CAWZ"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @module platform/adapters/fs/veryfront/retry
|
|
8
8
|
*/
|
|
9
9
|
import { logger as baseLogger } from "../../../../utils/index.js";
|
|
10
|
+
import { retryWithBackoff } from "../../../../errors/error-handlers.js";
|
|
10
11
|
const logger = baseLogger.component("fs-retry");
|
|
11
12
|
/** Delay between retries in milliseconds */
|
|
12
13
|
const RETRY_DELAY_MS = 500;
|
|
@@ -48,18 +49,15 @@ function isTransientError(error) {
|
|
|
48
49
|
* Execute an async function with a single retry for transient errors.
|
|
49
50
|
* Non-transient errors (4xx, validation) are thrown immediately.
|
|
50
51
|
*/
|
|
51
|
-
export
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
63
|
-
return fn();
|
|
64
|
-
}
|
|
52
|
+
export function withRetryOnTransient(fn, context) {
|
|
53
|
+
return retryWithBackoff(() => fn(), {
|
|
54
|
+
maxAttempts: 2,
|
|
55
|
+
computeDelay: () => RETRY_DELAY_MS,
|
|
56
|
+
shouldRetry: (error) => isTransientError(error),
|
|
57
|
+
onRetry: ({ error }) => {
|
|
58
|
+
logger.warn(`${context} — transient error, retrying once`, {
|
|
59
|
+
error: error.message,
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
});
|
|
65
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry-handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/adapters/veryfront-api-client/retry-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"retry-handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/adapters/veryfront-api-client/retry-handler.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,oFAAoF;IACpF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAaD,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,OAAO,CAAC,CA8GlB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { logger } from "../../../utils/index.js";
|
|
2
|
+
import { retryWithBackoff } from "../../../errors/error-handlers.js";
|
|
2
3
|
import { injectContext, withSpan } from "../../../observability/tracing/otlp-setup.js";
|
|
3
4
|
import { SpanNames } from "../../../observability/tracing/span-names.js";
|
|
4
5
|
import { recordApiRequest, recordApiRetry, } from "../../../observability/simple-metrics/metrics-recorder.js";
|
|
@@ -7,6 +8,13 @@ const apiLog = logger.component("api");
|
|
|
7
8
|
const veryfrontApiClientLog = logger.component("veryfront-api-client");
|
|
8
9
|
/** Default timeout for API requests (30 seconds) */
|
|
9
10
|
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
11
|
+
function logTimedOut(url, timeoutMs, attempt) {
|
|
12
|
+
veryfrontApiClientLog.warn("Request timed out", {
|
|
13
|
+
url: url.replace(/token=[^&]+/, "token=***"),
|
|
14
|
+
timeoutMs,
|
|
15
|
+
attempt: attempt + 1,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
10
18
|
export async function requestWithRetry(url, apiToken, retryConfig, options = {}) {
|
|
11
19
|
const urlObj = new URL(url);
|
|
12
20
|
const urlPath = urlObj.pathname;
|
|
@@ -14,102 +22,90 @@ export async function requestWithRetry(url, apiToken, retryConfig, options = {})
|
|
|
14
22
|
const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
15
23
|
// Note: We only trace the individual fetch attempts (HTTP_CLIENT_FETCH),
|
|
16
24
|
// not the outer retry wrapper, to reduce span nesting and trace size.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
apiLog.debug("Request completed", {
|
|
39
|
-
path: urlPath,
|
|
40
|
-
status: response.status,
|
|
41
|
-
durationMs: Math.round(duration),
|
|
42
|
-
});
|
|
43
|
-
if (!response.ok) {
|
|
44
|
-
const text = await response.text();
|
|
45
|
-
// Optional probes (for example stylesheet candidates) may expect a 404.
|
|
46
|
-
// Keep only explicit opt-ins below warn while preserving thrown error semantics.
|
|
47
|
-
const isExpected404 = options.expected404 === true && response.status === 404;
|
|
48
|
-
// 4xx = client errors (expected, e.g. 404 for missing deno.json) → warn
|
|
49
|
-
// 5xx = server errors (unexpected) → error
|
|
50
|
-
const logLevel = isExpected404 ? "debug" : response.status >= 500 ? "error" : "warn";
|
|
51
|
-
veryfrontApiClientLog[logLevel]("Request failed", {
|
|
52
|
-
url: url.replace(/token=[^&]+/, "token=***"),
|
|
53
|
-
status: response.status,
|
|
54
|
-
statusText: response.statusText,
|
|
55
|
-
responseText: text.slice(0, 500),
|
|
56
|
-
});
|
|
57
|
-
throw API_CLIENT_ERROR.create({
|
|
58
|
-
detail: `API request failed: ${response.status} ${response.statusText}`,
|
|
59
|
-
status: response.status,
|
|
60
|
-
context: { details: { url, responseText: text } },
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
const data = options.returnText ? await response.text() : await response.json();
|
|
64
|
-
return { data, status: response.status, duration };
|
|
65
|
-
}, {
|
|
66
|
-
"http.method": options.method ?? "GET",
|
|
67
|
-
"http.url": url,
|
|
68
|
-
"http.target": urlPath,
|
|
69
|
-
"http.host": urlObj.host,
|
|
70
|
-
"http.scheme": urlObj.protocol.replace(":", ""),
|
|
71
|
-
"http.retry_attempt": attempt,
|
|
25
|
+
const result = await retryWithBackoff((signal, attempt) => {
|
|
26
|
+
return withSpan(SpanNames.HTTP_CLIENT_FETCH, async () => {
|
|
27
|
+
const startTime = performance.now();
|
|
28
|
+
const headers = new Headers(options.headers);
|
|
29
|
+
headers.set("Authorization", `Bearer ${apiToken}`);
|
|
30
|
+
if (!headers.has("Content-Type")) {
|
|
31
|
+
headers.set("Content-Type", "application/json");
|
|
32
|
+
}
|
|
33
|
+
injectContext(headers);
|
|
34
|
+
const response = await fetch(url, {
|
|
35
|
+
method: options.method ?? "GET",
|
|
36
|
+
headers,
|
|
37
|
+
body: options.body,
|
|
38
|
+
signal,
|
|
39
|
+
});
|
|
40
|
+
const duration = performance.now() - startTime;
|
|
41
|
+
recordApiRequest(response.status);
|
|
42
|
+
apiLog.debug("Request completed", {
|
|
43
|
+
path: urlPath,
|
|
44
|
+
status: response.status,
|
|
45
|
+
durationMs: Math.round(duration),
|
|
72
46
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
const text = await response.text();
|
|
49
|
+
// Optional probes (for example stylesheet candidates) may expect a 404.
|
|
50
|
+
// Keep only explicit opt-ins below warn while preserving thrown error semantics.
|
|
51
|
+
const isExpected404 = options.expected404 === true && response.status === 404;
|
|
52
|
+
// 4xx = client errors (expected, e.g. 404 for missing deno.json) → warn
|
|
53
|
+
// 5xx = server errors (unexpected) → error
|
|
54
|
+
const logLevel = isExpected404 ? "debug" : response.status >= 500 ? "error" : "warn";
|
|
55
|
+
veryfrontApiClientLog[logLevel]("Request failed", {
|
|
80
56
|
url: url.replace(/token=[^&]+/, "token=***"),
|
|
81
|
-
|
|
82
|
-
|
|
57
|
+
status: response.status,
|
|
58
|
+
statusText: response.statusText,
|
|
59
|
+
responseText: text.slice(0, 500),
|
|
60
|
+
});
|
|
61
|
+
throw API_CLIENT_ERROR.create({
|
|
62
|
+
detail: `API request failed: ${response.status} ${response.statusText}`,
|
|
63
|
+
status: response.status,
|
|
64
|
+
context: { details: { url, responseText: text } },
|
|
83
65
|
});
|
|
84
66
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
67
|
+
const data = options.returnText ? await response.text() : await response.json();
|
|
68
|
+
return { data, status: response.status, duration };
|
|
69
|
+
}, {
|
|
70
|
+
"http.method": options.method ?? "GET",
|
|
71
|
+
"http.url": url,
|
|
72
|
+
"http.target": urlPath,
|
|
73
|
+
"http.host": urlObj.host,
|
|
74
|
+
"http.scheme": urlObj.protocol.replace(":", ""),
|
|
75
|
+
"http.retry_attempt": attempt,
|
|
76
|
+
});
|
|
77
|
+
}, {
|
|
78
|
+
maxAttempts: maxRetries + 1,
|
|
79
|
+
initialDelay,
|
|
80
|
+
maxDelay,
|
|
81
|
+
timeoutMs,
|
|
82
|
+
shouldRetry: (error) => {
|
|
83
|
+
if (!(error instanceof VeryfrontError) || error.slug !== "api-client-error")
|
|
84
|
+
return true;
|
|
85
|
+
const status = error.status;
|
|
86
|
+
return !status || status < 400 || status >= 500 || status === 429;
|
|
87
|
+
},
|
|
88
|
+
onRetry: ({ error, attempt, delay, isTimeout }) => {
|
|
89
|
+
if (isTimeout)
|
|
90
|
+
logTimedOut(url, timeoutMs, attempt);
|
|
95
91
|
recordApiRetry();
|
|
96
92
|
veryfrontApiClientLog.warn("Request failed, retrying...", {
|
|
97
93
|
attempt: attempt + 1,
|
|
98
94
|
maxRetries,
|
|
99
95
|
delay,
|
|
100
|
-
error:
|
|
96
|
+
error: error.message,
|
|
101
97
|
timeout: isTimeout,
|
|
102
98
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
context: { details: { originalError: lastError } },
|
|
99
|
+
},
|
|
100
|
+
wrapFinalError: (lastError, lastAttempt) => {
|
|
101
|
+
if (lastError.name === "AbortError")
|
|
102
|
+
logTimedOut(url, timeoutMs, lastAttempt);
|
|
103
|
+
return API_CLIENT_ERROR.create({
|
|
104
|
+
detail: `API request failed after ${maxRetries} retries: ${lastError.message}`,
|
|
105
|
+
cause: lastError,
|
|
106
|
+
context: { details: { originalError: lastError } },
|
|
107
|
+
});
|
|
108
|
+
},
|
|
114
109
|
});
|
|
110
|
+
return result.data;
|
|
115
111
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LogLevelName } from "../utils/logger/core.js";
|
|
1
2
|
/**
|
|
2
3
|
* Request context for proxy logging.
|
|
3
4
|
* Stored in AsyncLocalStorage to propagate through the call stack.
|
|
@@ -17,7 +18,7 @@ interface ProxyRequestContext {
|
|
|
17
18
|
* All logs within the function will include the request context fields.
|
|
18
19
|
*/
|
|
19
20
|
export declare function runWithProxyRequestContext<T>(context: ProxyRequestContext, fn: () => T): T;
|
|
20
|
-
export type LogLevel =
|
|
21
|
+
export type LogLevel = LogLevelName;
|
|
21
22
|
declare class ProxyLogger {
|
|
22
23
|
private format;
|
|
23
24
|
private log;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/logger.ts"],"names":[],"mappings":"AAKA,OAAO,EAQL,KAAK,YAAY,EAIlB,MAAM,yBAAyB,CAAC;AAEjC;;;GAGG;AACH,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,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,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,OAAO,EAAE,mBAAmB,EAC5B,EAAE,EAAE,MAAM,CAAC,GACV,CAAC,CAEH;AASD,MAAM,MAAM,QAAQ,GAAG,YAAY,CAAC;AA2FpC,cAAM,WAAW;IACf,OAAO,CAAC,MAAM,CAAkB;IAEhC,OAAO,CAAC,GAAG;IA0CX,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,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI;IAmB/E;;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,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI;IAwB/E,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB;CAG1D;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC"}
|
package/esm/src/proxy/logger.js
CHANGED
|
@@ -3,6 +3,7 @@ import { getEnv } from "./env.js";
|
|
|
3
3
|
import { getTraceContext } from "./tracing.js";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
import { PROXY_RUNTIME_VERSION } from "./version.js";
|
|
6
|
+
import { ANSI, colorize, formatContextText, formatTimestamp, isRecord, LEVEL_COLORS, LEVEL_GLYPHS, padTag, serializeError, } from "../utils/logger/core.js";
|
|
6
7
|
const requestContextStore = new AsyncLocalStorage();
|
|
7
8
|
/**
|
|
8
9
|
* Run a function with proxy request context.
|
|
@@ -31,118 +32,6 @@ const MIN_LOG_LEVEL = (() => {
|
|
|
31
32
|
}
|
|
32
33
|
return "info"; // Default: suppress debug logs
|
|
33
34
|
})();
|
|
34
|
-
// ============================================================================
|
|
35
|
-
// INLINED FORMATTING UTILITIES (from src/utils/logger/core.ts)
|
|
36
|
-
// These must be kept in sync with core.ts but cannot be imported due to
|
|
37
|
-
// Docker build constraints (proxy is built independently).
|
|
38
|
-
// ============================================================================
|
|
39
|
-
const TAG_WIDTH = 10;
|
|
40
|
-
const PREFIX_WIDTH = 23; // timestamp(8) + gap(2) + tag(10) + space(1) + glyph(1) + space(1)
|
|
41
|
-
const LEVEL_GLYPHS = {
|
|
42
|
-
debug: "·",
|
|
43
|
-
info: "●",
|
|
44
|
-
warn: "▲",
|
|
45
|
-
error: "✖",
|
|
46
|
-
};
|
|
47
|
-
const ANSI = {
|
|
48
|
-
reset: "\u001b[0m",
|
|
49
|
-
dim: "\u001b[2m",
|
|
50
|
-
gray: "\u001b[90m",
|
|
51
|
-
red: "\u001b[31m",
|
|
52
|
-
green: "\u001b[32m",
|
|
53
|
-
yellow: "\u001b[33m",
|
|
54
|
-
cyan: "\u001b[36m",
|
|
55
|
-
};
|
|
56
|
-
const LEVEL_COLORS = {
|
|
57
|
-
debug: ANSI.gray,
|
|
58
|
-
info: ANSI.green,
|
|
59
|
-
warn: ANSI.yellow,
|
|
60
|
-
error: ANSI.red,
|
|
61
|
-
};
|
|
62
|
-
function padTag(tag) {
|
|
63
|
-
if (tag.length >= TAG_WIDTH)
|
|
64
|
-
return tag.slice(0, TAG_WIDTH);
|
|
65
|
-
return tag.padEnd(TAG_WIDTH, " ");
|
|
66
|
-
}
|
|
67
|
-
function formatTimestamp(date = new Date()) {
|
|
68
|
-
const pad = (value) => String(value).padStart(2, "0");
|
|
69
|
-
return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
70
|
-
}
|
|
71
|
-
function colorize(text, color, enable) {
|
|
72
|
-
if (!enable || !color)
|
|
73
|
-
return text;
|
|
74
|
-
return `${color}${text}${ANSI.reset}`;
|
|
75
|
-
}
|
|
76
|
-
function normalizeText(value) {
|
|
77
|
-
return value.replace(/\s+/g, " ");
|
|
78
|
-
}
|
|
79
|
-
function truncateText(value, maxLength = 80) {
|
|
80
|
-
if (value.length <= maxLength)
|
|
81
|
-
return value;
|
|
82
|
-
return `${value.slice(0, maxLength - 1)}…`;
|
|
83
|
-
}
|
|
84
|
-
function formatValue(value) {
|
|
85
|
-
if (typeof value === "string") {
|
|
86
|
-
const trimmed = normalizeText(value);
|
|
87
|
-
return /\s/.test(trimmed) ? JSON.stringify(trimmed) : trimmed;
|
|
88
|
-
}
|
|
89
|
-
if (typeof value === "number" || typeof value === "boolean")
|
|
90
|
-
return String(value);
|
|
91
|
-
if (value === null)
|
|
92
|
-
return "null";
|
|
93
|
-
if (value === undefined)
|
|
94
|
-
return "undefined";
|
|
95
|
-
let text;
|
|
96
|
-
try {
|
|
97
|
-
text = JSON.stringify(value);
|
|
98
|
-
}
|
|
99
|
-
catch (_) {
|
|
100
|
-
/* expected: non-serializable value */
|
|
101
|
-
text = String(value);
|
|
102
|
-
}
|
|
103
|
-
if (text === undefined)
|
|
104
|
-
return "undefined";
|
|
105
|
-
return truncateText(normalizeText(text));
|
|
106
|
-
}
|
|
107
|
-
function formatErrorText(error) {
|
|
108
|
-
if (error == null)
|
|
109
|
-
return "";
|
|
110
|
-
const message = [error.name, error.message].join(": ");
|
|
111
|
-
return truncateText(normalizeText(message), 120);
|
|
112
|
-
}
|
|
113
|
-
function serializeError(error) {
|
|
114
|
-
if (error == null)
|
|
115
|
-
return undefined;
|
|
116
|
-
if (error instanceof Error) {
|
|
117
|
-
const serialized = {
|
|
118
|
-
name: error.name,
|
|
119
|
-
message: error.message,
|
|
120
|
-
};
|
|
121
|
-
if (error.stack)
|
|
122
|
-
serialized.stack = error.stack;
|
|
123
|
-
return serialized;
|
|
124
|
-
}
|
|
125
|
-
return { name: "UnknownError", message: String(error) };
|
|
126
|
-
}
|
|
127
|
-
function formatContextText(context, error, enableColor) {
|
|
128
|
-
const entries = [];
|
|
129
|
-
for (const [key, value] of Object.entries(context)) {
|
|
130
|
-
entries.push(`${key}=${formatValue(value)}`);
|
|
131
|
-
}
|
|
132
|
-
const errorText = formatErrorText(error);
|
|
133
|
-
if (errorText)
|
|
134
|
-
entries.push(`err=${errorText}`);
|
|
135
|
-
if (entries.length === 0)
|
|
136
|
-
return "";
|
|
137
|
-
const coloredText = colorize(entries.join(" "), ANSI.dim, enableColor);
|
|
138
|
-
return `\n${" ".repeat(PREFIX_WIDTH)}${coloredText}`;
|
|
139
|
-
}
|
|
140
|
-
function isRecord(value) {
|
|
141
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
142
|
-
}
|
|
143
|
-
// ============================================================================
|
|
144
|
-
// END INLINED FORMATTING UTILITIES
|
|
145
|
-
// ============================================================================
|
|
146
35
|
function isTty() {
|
|
147
36
|
try {
|
|
148
37
|
if (typeof dntShim.Deno !== "undefined" && typeof dntShim.Deno.stdout?.isTerminal === "function") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing-invalidation-redis.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/routing-invalidation-redis.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"routing-invalidation-redis.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/routing-invalidation-redis.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,6BAA6B,EAC7B,iCAAiC,EAElC,MAAM,2BAA2B,CAAC;AAgBnC,KAAK,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAGhE,MAAM,WAAW,8BAA8B;IAC7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,IAAI,CAAC;IAChB,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC;CAClE;AAED,UAAU,yBAAyB;IACjC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,2BAA4B,SAAQ,iCAAiC;IACpF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,UAAU,uCAAuC;IAC/C,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,YAAY,CAAC,EAAE,CACb,QAAQ,EAAE,MAAM,KACb,8BAA8B,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,yBAAyB,CAAC;IACnC,YAAY,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgPD,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,uCAAuC,GAC/C,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CAgP7C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
2
|
import { getRedisModule } from "../platform/adapters/redis/modules.js";
|
|
3
3
|
import { getEnv } from "../platform/compat/process.js";
|
|
4
|
+
import { base64urlEncodeBytes } from "../utils/index.js";
|
|
4
5
|
const ROUTING_INVALIDATION_CHANNEL = "vf-proxy-routing-invalidations-v1";
|
|
5
6
|
const ROUTING_INVALIDATION_ACK_PREFIX = `${ROUTING_INVALIDATION_CHANNEL}:ack:`;
|
|
6
7
|
const DEFAULT_ACKNOWLEDGEMENT_TIMEOUT_MS = 1_500;
|
|
@@ -54,10 +55,6 @@ function signatureInput(domain, issuedAtMs, payload) {
|
|
|
54
55
|
const encoded = new TextEncoder().encode(`${signatureDomainPrefix(domain)}\0${issuedAtMs}\0${payload}`);
|
|
55
56
|
return encoded.buffer.slice(encoded.byteOffset, encoded.byteOffset + encoded.byteLength);
|
|
56
57
|
}
|
|
57
|
-
function base64UrlEncode(bytes) {
|
|
58
|
-
const binary = Array.from(new Uint8Array(bytes), (byte) => String.fromCharCode(byte)).join("");
|
|
59
|
-
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
|
|
60
|
-
}
|
|
61
58
|
function base64UrlDecode(value) {
|
|
62
59
|
if (!/^[A-Za-z0-9_-]+$/u.test(value))
|
|
63
60
|
return null;
|
|
@@ -73,7 +70,7 @@ async function createHmacKey(secret) {
|
|
|
73
70
|
return dntShim.crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]);
|
|
74
71
|
}
|
|
75
72
|
async function signPayload(key, domain, issuedAtMs, payload) {
|
|
76
|
-
return
|
|
73
|
+
return base64urlEncodeBytes(new Uint8Array(await dntShim.crypto.subtle.sign("HMAC", key, signatureInput(domain, issuedAtMs, payload))));
|
|
77
74
|
}
|
|
78
75
|
async function verifyPayloadSignature(key, domain, issuedAtMs, payload, signature) {
|
|
79
76
|
const signatureBytes = base64UrlDecode(signature);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-resolver.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/server-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"server-resolver.d.ts","sourceRoot":"","sources":["../../../src/src/proxy/server-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2BH,qBAAa,cAAc;IAMvB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;IARpB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,OAAO,CAAsD;IACrE,OAAO,CAAC,YAAY,CAA+C;gBAGzD,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAAe;IAQrC;;OAEG;IACG,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwCxE,KAAK,IAAI,IAAI;IAQb;;;;OAIG;YACW,WAAW;IAmCzB,OAAO,CAAC,OAAO;CAMhB"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { proxyLogger } from "./logger.js";
|
|
11
11
|
import { unrefTimer } from "../platform/compat/process.js";
|
|
12
|
+
import { encodeBase64 } from "../utils/index.js";
|
|
12
13
|
const logger = proxyLogger.child({ module: "server-resolver" });
|
|
13
14
|
/** Thrown when the API call fails (network error, non-OK status, parse error). */
|
|
14
15
|
class ServerResolverError extends Error {
|
|
@@ -91,7 +92,7 @@ export class ServerResolver {
|
|
|
91
92
|
const url = `${this.apiInternalUrl}/internal/environment-server?environmentId=${encodeURIComponent(environmentId)}`;
|
|
92
93
|
const headers = { Accept: "application/json" };
|
|
93
94
|
if (this.apiUser && this.apiPass) {
|
|
94
|
-
headers.Authorization = `Basic ${
|
|
95
|
+
headers.Authorization = `Basic ${encodeBase64(`${this.apiUser}:${this.apiPass}`)}`;
|
|
95
96
|
}
|
|
96
97
|
let response;
|
|
97
98
|
try {
|