veryfront 0.1.636 → 0.1.637

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.636",
3
+ "version": "0.1.637",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "workspace": [
@@ -1 +1 @@
1
- {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/src/errors/logging.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAiCN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAMN"}
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/src/errors/logging.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAoCN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAMN"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { isProduction } from "../platform/environment.js";
8
8
  import { serverLogger } from "../utils/logger/logger.js";
9
+ import { redactSensitive } from "../utils/logger/redact.js";
9
10
  function toContextRecord(value) {
10
11
  return value && typeof value === "object" && !Array.isArray(value)
11
12
  ? value
@@ -30,6 +31,9 @@ function mergeContext(errorContext, extraContext) {
30
31
  */
31
32
  export function logError(error, context) {
32
33
  const mergedContext = mergeContext(error.context, context);
34
+ // Redact once and reuse for both the production JSON entry and the dev-mode
35
+ // human-readable dump, so neither path can emit unredacted credentials.
36
+ const safeContext = redactSensitive(mergedContext);
33
37
  const entry = {
34
38
  level: "error",
35
39
  slug: error.slug,
@@ -40,7 +44,7 @@ export function logError(error, context) {
40
44
  status: error.status,
41
45
  docs: error.getDocsUrl(),
42
46
  timestamp: new Date().toISOString(),
43
- context: mergedContext,
47
+ context: safeContext,
44
48
  };
45
49
  if (isProduction()) {
46
50
  // Direct JSON output — this module owns its own structured format
@@ -57,8 +61,8 @@ export function logError(error, context) {
57
61
  serverLogger.error(` 💡 Suggestion: ${error.suggestion}`);
58
62
  }
59
63
  serverLogger.error(` 📚 Docs: ${entry.docs}`);
60
- if (mergedContext) {
61
- serverLogger.error(` Context: ${JSON.stringify(mergedContext, null, 2)}`);
64
+ if (safeContext) {
65
+ serverLogger.error(` Context: ${JSON.stringify(safeContext, null, 2)}`);
62
66
  }
63
67
  }
64
68
  }
@@ -24,5 +24,6 @@ export type { AuthorizationUrlOptions, OAuthProviderConfig, OAuthServiceConfig,
24
24
  export { OAuthProvider, OAuthService } from "./providers/base.js";
25
25
  export { airtableConfig, asanaConfig, bitbucketConfig, boxConfig, calendarConfig, clickupConfig, confluenceConfig, driveConfig, figmaConfig, freshdeskConfig, githubConfig, gitlabConfig, gmailConfig, hubspotConfig, intercomConfig, jiraConfig, linearConfig, mailchimpConfig, mondayConfig, notionConfig, oneDriveConfig, outlookConfig, pipedriveConfig, quickbooksConfig, salesforceConfig, sharePointConfig, sheetsConfig, shopifyConfig, slackConfig, teamsConfig, trelloConfig, twitterConfig, webexConfig, xeroConfig, zoomConfig, } from "./providers/index.js";
26
26
  export { MemoryTokenStore } from "./token-store/index.js";
27
+ export type { MemoryTokenStoreOptions } from "./token-store/index.js";
27
28
  export { createOAuthCallbackHandler, createOAuthDisconnectHandler, createOAuthInitHandler, createOAuthStatusHandler, type OAuthCallbackHandlerOptions, type OAuthInitHandlerOptions, } from "./handlers/index.js";
28
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EACL,cAAc,EACd,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,cAAc,EACd,UAAU,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,EAC5B,sBAAsB,EACtB,wBAAwB,EACxB,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EACL,cAAc,EACd,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,cAAc,EACd,UAAU,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,EAC5B,sBAAsB,EACtB,wBAAwB,EACxB,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC"}
@@ -4,5 +4,6 @@
4
4
  * @module oauth/token-store
5
5
  */
6
6
  export { MemoryTokenStore, memoryTokenStore } from "./memory.js";
7
+ export type { MemoryTokenStoreOptions } from "./memory.js";
7
8
  export type { OAuthState, OAuthTokens, StoredOAuthState, TokenStore } from "../types.js";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -1,17 +1,39 @@
1
1
  import type { OAuthTokens, StoredOAuthState, TokenStore } from "../types.js";
2
+ /** Options for {@link MemoryTokenStore}. */
3
+ export interface MemoryTokenStoreOptions {
4
+ /**
5
+ * Maximum number of `(serviceId, userId)` token slots to retain before
6
+ * least-recently-used eviction kicks in. Defaults to
7
+ * {@link DEFAULT_MAX_TOKEN_ENTRIES}.
8
+ */
9
+ maxEntries?: number;
10
+ }
2
11
  /**
3
12
  * In-memory TokenStore keyed by `(serviceId, userId)`.
4
13
  *
5
- * Suitable for development and tests. For production use a persistent store
6
- * (Redis, Postgres, ...) keyed the same way. Never share a single slot per
7
- * service across users see VULN-AUTH-2.
14
+ * Suitable for development and tests ONLY. It is process-local and not
15
+ * durable: tokens are lost on restart and not shared across instances or
16
+ * workers, and the exported {@link memoryTokenStore} singleton shares one
17
+ * keyspace process-wide. For production inject a persistent, scoped store
18
+ * (Redis, Postgres, ...) keyed the same way.
19
+ *
20
+ * The token map is bounded (see {@link MemoryTokenStoreOptions.maxEntries}) so
21
+ * it cannot grow without limit. Never share a single slot per service across
22
+ * users — see VULN-AUTH-2.
8
23
  */
9
24
  export declare class MemoryTokenStore implements TokenStore {
10
25
  private tokens;
11
26
  private states;
12
27
  private projectId;
13
- constructor(projectId?: string);
28
+ private warnedProductionUse;
29
+ constructor(projectId?: string, options?: MemoryTokenStoreOptions);
14
30
  private scopedKey;
31
+ /**
32
+ * Warn once if this non-durable store is used to persist tokens in
33
+ * production — almost always a misconfiguration (a persistent TokenStore
34
+ * should have been injected).
35
+ */
36
+ private warnIfProductionUse;
15
37
  getTokens(serviceId: string, userId: string): Promise<OAuthTokens | null>;
16
38
  setTokens(serviceId: string, userId: string, tokens: OAuthTokens): Promise<void>;
17
39
  clearTokens(serviceId: string, userId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK7E;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,SAAY;IAIjC,OAAO,CAAC,SAAS;IAIjB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAIzE,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhF,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9D;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAU7D,OAAO,CAAC,oBAAoB;IAS5B,iFAAiF;IACjF,oBAAoB,IAAI,MAAM,EAAE;IAOhC,4DAA4D;IAC5D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAQvD,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,gBAAgB,EAAE,UAAmC,CAAC"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/src/oauth/token-store/memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAgB7E,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,mBAAmB,CAAS;gBAExB,SAAS,SAAY,EAAE,OAAO,GAAE,uBAA4B;IAOxE,OAAO,CAAC,SAAS;IAIjB;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAW3B,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAMzE,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhF,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9D;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAU7D,OAAO,CAAC,oBAAoB;IAS5B,iFAAiF;IACjF,oBAAoB,IAAI,MAAM,EAAE;IAOhC,4DAA4D;IAC5D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAQvD,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,gBAAgB,EAAE,UAAmC,CAAC"}
@@ -1,26 +1,63 @@
1
+ import { logger as baseLogger } from "../../utils/index.js";
2
+ import { isProduction } from "../../platform/environment.js";
3
+ import { LRUCacheAdapter } from "../../utils/cache/stores/memory/lru-cache-adapter.js";
4
+ const logger = baseLogger.component("o-auth");
1
5
  /** State expiry window: reject any state older than this (10 minutes). */
2
6
  const STATE_EXPIRY_MS = 10 * 60 * 1_000;
7
+ /**
8
+ * Default cap on stored token slots. Bounds memory in long-lived processes;
9
+ * past this, the least-recently-used `(serviceId, userId)` slot is evicted
10
+ * (the affected user simply re-authenticates). Tokens are NOT given a TTL —
11
+ * an expired access token may still be refreshable via its refresh token, so
12
+ * eviction is by capacity/recency only.
13
+ */
14
+ const DEFAULT_MAX_TOKEN_ENTRIES = 10_000;
3
15
  /**
4
16
  * In-memory TokenStore keyed by `(serviceId, userId)`.
5
17
  *
6
- * Suitable for development and tests. For production use a persistent store
7
- * (Redis, Postgres, ...) keyed the same way. Never share a single slot per
8
- * service across users see VULN-AUTH-2.
18
+ * Suitable for development and tests ONLY. It is process-local and not
19
+ * durable: tokens are lost on restart and not shared across instances or
20
+ * workers, and the exported {@link memoryTokenStore} singleton shares one
21
+ * keyspace process-wide. For production inject a persistent, scoped store
22
+ * (Redis, Postgres, ...) keyed the same way.
23
+ *
24
+ * The token map is bounded (see {@link MemoryTokenStoreOptions.maxEntries}) so
25
+ * it cannot grow without limit. Never share a single slot per service across
26
+ * users — see VULN-AUTH-2.
9
27
  */
10
28
  export class MemoryTokenStore {
11
- tokens = new Map();
29
+ tokens;
12
30
  states = new Map();
13
31
  projectId;
14
- constructor(projectId = "default") {
32
+ warnedProductionUse = false;
33
+ constructor(projectId = "default", options = {}) {
15
34
  this.projectId = projectId;
35
+ this.tokens = new LRUCacheAdapter({
36
+ maxEntries: options.maxEntries ?? DEFAULT_MAX_TOKEN_ENTRIES,
37
+ });
16
38
  }
17
39
  scopedKey(serviceId, userId) {
18
40
  return `${this.projectId}:${serviceId}:${userId}`;
19
41
  }
42
+ /**
43
+ * Warn once if this non-durable store is used to persist tokens in
44
+ * production — almost always a misconfiguration (a persistent TokenStore
45
+ * should have been injected).
46
+ */
47
+ warnIfProductionUse() {
48
+ if (this.warnedProductionUse || !isProduction())
49
+ return;
50
+ this.warnedProductionUse = true;
51
+ logger.warn("MemoryTokenStore is persisting OAuth tokens in production. It is " +
52
+ "process-local and not durable (tokens are lost on restart and not " +
53
+ "shared across instances). Inject a persistent, scoped TokenStore " +
54
+ "(Redis/Postgres/...) instead.");
55
+ }
20
56
  getTokens(serviceId, userId) {
21
57
  return Promise.resolve(this.tokens.get(this.scopedKey(serviceId, userId)) ?? null);
22
58
  }
23
59
  setTokens(serviceId, userId, tokens) {
60
+ this.warnIfProductionUse();
24
61
  this.tokens.set(this.scopedKey(serviceId, userId), tokens);
25
62
  return Promise.resolve();
26
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"log-buffer.d.ts","sourceRoot":"","sources":["../../../src/src/observability/log-buffer.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,2BAA2B;AAC3B,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,uDAAuD;AACvD,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,8CAA8C;AAC9C,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEtD,4BAA4B;AAC5B,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAI9C,OAAO,CAAC,UAAU;IAIlB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,QAAQ;IAwB3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAInF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAIlF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAIlF,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAInF,KAAK,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,EAAE;IAqCrC,IAAI,CAAC,KAAK,SAAK,GAAG,QAAQ,EAAE;IAI5B,MAAM,IAAI,QAAQ,EAAE;IAIpB,KAAK,IAAI,IAAI;IAIb,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,YAAY,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;IAUxC,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAK9C,MAAM,IAAI,QAAQ,EAAE;IAIpB,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM;CAYrC;AAID,yBAAyB;AACzB,wBAAgB,YAAY,IAAI,SAAS,CAGxC;AAED,sCAAsC;AACtC,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,SAAY,GAAG,MAAM,IAAI,CA2ClF"}
1
+ {"version":3,"file":"log-buffer.d.ts","sourceRoot":"","sources":["../../../src/src/observability/log-buffer.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,2BAA2B;AAC3B,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,uDAAuD;AACvD,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,8CAA8C;AAC9C,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEtD,4BAA4B;AAC5B,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAI9C,OAAO,CAAC,UAAU;IAIlB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,QAAQ;IA2B3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAInF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAIlF,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAIlF,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAW,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAInF,KAAK,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,EAAE;IAqCrC,IAAI,CAAC,KAAK,SAAK,GAAG,QAAQ,EAAE;IAI5B,MAAM,IAAI,QAAQ,EAAE;IAIpB,KAAK,IAAI,IAAI;IAIb,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,YAAY,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;IAUxC,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI;IAK9C,MAAM,IAAI,QAAQ,EAAE;IAIpB,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM;CAYrC;AAID,yBAAyB;AACzB,wBAAgB,YAAY,IAAI,SAAS,CAGxC;AAED,sCAAsC;AACtC,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,SAAY,GAAG,MAAM,IAAI,CA6ClF"}
@@ -1,3 +1,4 @@
1
+ import { redactSensitive } from "../utils/logger/redact.js";
1
2
  /** Implement log buffer. */
2
3
  export class LogBuffer {
3
4
  entries = [];
@@ -13,6 +14,9 @@ export class LogBuffer {
13
14
  append(entry) {
14
15
  const fullEntry = {
15
16
  ...entry,
17
+ // Redact credential-like keys before the entry is buffered, surfaced to
18
+ // subscribers, or written to disk by the file subscriber (#1989).
19
+ data: entry.data ? redactSensitive(entry.data) : entry.data,
16
20
  id: this.generateId(),
17
21
  timestamp: Date.now(),
18
22
  };
@@ -136,7 +140,9 @@ export function interceptConsole(buffer, source = "console") {
136
140
  if (typeof a === "string")
137
141
  return a;
138
142
  try {
139
- return JSON.stringify(a);
143
+ // Redact object args before they are folded into the message string,
144
+ // where the per-entry data redaction can no longer reach them (#1989).
145
+ return JSON.stringify(redactSensitive(a));
140
146
  }
141
147
  catch (_) {
142
148
  /* expected: circular references or non-serializable values */
@@ -1 +1 @@
1
- {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/adapters/redis/modules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKnE,wBAAgB,cAAc,IAAI,OAAO,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;CACnC,CAAC,CAqCD;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/adapters/redis/modules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKnE,wBAAgB,cAAc,IAAI,OAAO,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;CACnC,CAAC,CA6BD;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
@@ -10,9 +10,7 @@ export function getRedisModule() {
10
10
  return withSpan("platform.redis.getModule", async () => {
11
11
  try {
12
12
  if (isDeno) {
13
- const denoRedisUrl = "https://deno.land/x/redis@v0.32.1/mod.ts";
14
- // @ts-ignore - Deno global
15
- DenoRedis = await import(denoRedisUrl);
13
+ NodeRedis = (await import("redis"));
16
14
  }
17
15
  else {
18
16
  NodeRedis = (await import("redis"));
@@ -20,14 +18,9 @@ export function getRedisModule() {
20
18
  }
21
19
  catch (error) {
22
20
  const message = error instanceof Error ? error.message : String(error);
23
- if (isDeno) {
24
- throw INITIALIZATION_ERROR.create({
25
- detail: `Failed to load Deno Redis module. Error: ${message}`,
26
- cause: error instanceof Error ? error : undefined,
27
- });
28
- }
21
+ const packageName = isDeno ? "npm:redis@5.11.0" : "redis";
29
22
  throw INITIALIZATION_ERROR.create({
30
- detail: `Failed to load 'redis' package. Please install it with: npm install redis\nError: ${message}`,
23
+ detail: `Failed to load '${packageName}' package. Please install it with: npm install redis\nError: ${message}`,
31
24
  cause: error instanceof Error ? error : undefined,
32
25
  });
33
26
  }
@@ -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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"}
@@ -1,6 +1,7 @@
1
1
  import { getEnv, isStdoutTTY } from "../../platform/compat/process.js";
2
2
  import { RUNTIME_VERSION } from "../version.js";
3
3
  import { ANSI, colorize, formatContextText, formatTimestamp, LEVEL_COLORS, LEVEL_GLYPHS, padTag, serializeError, } from "./core.js";
4
+ import { redactSensitive, sanitizeSerializedError, sanitizeUrlCredentials } from "./redact.js";
4
5
  export var LogLevel;
5
6
  (function (LogLevel) {
6
7
  LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
@@ -181,8 +182,11 @@ class ConsoleLogger {
181
182
  extractToEntryField(entry, mergedContext, "trace_id", (v) => String(v));
182
183
  extractToEntryField(entry, mergedContext, "span_id", (v) => String(v));
183
184
  extractToEntryField(entry, mergedContext, "project_slug", (v) => String(v));
184
- extractToEntryField(entry, mergedContext, "request_url", (v) => String(v));
185
- extractToEntryField(entry, mergedContext, "domain", (v) => String(v));
185
+ // request_url / domain are URL-shaped and lifted out of mergedContext
186
+ // *before* redactSensitive runs, so they bypass the key-based redactor.
187
+ // Scrub embedded credentials (userinfo, ?access_token=, …) here (#1989).
188
+ extractToEntryField(entry, mergedContext, "request_url", (v) => sanitizeUrlCredentials(String(v)));
189
+ extractToEntryField(entry, mergedContext, "domain", (v) => sanitizeUrlCredentials(String(v)));
186
190
  extractToEntryField(entry, mergedContext, "project_id", (v) => String(v));
187
191
  extractToEntryField(entry, mergedContext, "release_id", (v) => String(v));
188
192
  extractToEntryField(entry, mergedContext, "branch_id", (v) => String(v));
@@ -215,10 +219,16 @@ class ConsoleLogger {
215
219
  if (entry.conversationId && !entry.conversation_id) {
216
220
  entry.conversation_id = entry.conversationId;
217
221
  }
222
+ // Redact credential-like keys from the free-form context bag before
223
+ // serialization (the deliberate top-level fields above are already
224
+ // extracted out of mergedContext, so they are unaffected).
218
225
  if (Object.keys(mergedContext).length > 0)
219
- entry.context = mergedContext;
226
+ entry.context = redactSensitive(mergedContext);
227
+ // The serialized error (name/message/stack) bypasses the key-based
228
+ // redactor; scrub credentials embedded in its message/stack (DSNs, Mongo
229
+ // URIs, ?access_token= URLs, userinfo) before emission (#1989).
220
230
  if (error)
221
- entry.error = error;
231
+ entry.error = sanitizeSerializedError(error);
222
232
  return JSON.stringify(entry);
223
233
  }
224
234
  formatTextLine(level, message, args) {
@@ -231,7 +241,7 @@ class ConsoleLogger {
231
241
  const componentTag = this.componentName
232
242
  ? ` ${colorize(`[${this.componentName}]`, ANSI.dim, enableColor)}`
233
243
  : "";
234
- const contextText = formatContextText(mergedContext, error, enableColor);
244
+ const contextText = formatContextText(redactSensitive(mergedContext), sanitizeSerializedError(error), enableColor);
235
245
  return `${timestamp} ${tag} ${glyph}${componentTag} ${message}${contextText}`;
236
246
  }
237
247
  log(level, logLevel, consoleFn, message, args) {
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Secret / credential redaction for structured log context.
3
+ *
4
+ * Defense-in-depth (#1989): the logger, the error-logging path, and the
5
+ * observability log buffer all accept arbitrary `context`/`data` objects from
6
+ * callers and serialize them to log sinks. There is no guarantee a caller
7
+ * never hands us a tokens object, an `Authorization` header bag, or a request
8
+ * body with a password field. This pass masks values whose *key* looks like a
9
+ * credential before serialization, so an accidental
10
+ * `logger.info("...", { authorization: token })` cannot leak the secret.
11
+ *
12
+ * Scope is intentionally key-based: we do not attempt to find secrets embedded
13
+ * in free-form message strings (too lossy). The deny-list errs toward
14
+ * over-redaction — masking a benign `tokenCount` is acceptable; leaking a real
15
+ * token is not. The traversal fails *closed*: on a cycle, depth overflow, or a
16
+ * throwing getter it returns {@link REDACTED} rather than risk emitting an
17
+ * unredacted object.
18
+ */
19
+ /** Replacement value substituted for any sensitive field. */
20
+ export declare const REDACTED = "[REDACTED]";
21
+ /**
22
+ * Whether a context key names a credential and should have its value masked.
23
+ *
24
+ * Uses substring matching on a normalized key, so `clientSecret`,
25
+ * `x-api-key`, and `refresh_token` all match while benign words that merely
26
+ * *contain* a pattern as a separate token (e.g. `author`) do not — `author`
27
+ * normalizes to `author`, which contains none of the patterns.
28
+ */
29
+ export declare function isSensitiveKey(key: string): boolean;
30
+ /**
31
+ * Returns a redacted deep copy of `context`. Any property whose key is
32
+ * {@link isSensitiveKey} has its value replaced with {@link REDACTED}; nested
33
+ * plain objects, class instances, and arrays are traversed. The input is never
34
+ * mutated, and the pass fails closed (returns {@link REDACTED}) on cycles,
35
+ * depth overflow, or a throwing getter.
36
+ */
37
+ export declare function redactSensitive<T>(context: T): T;
38
+ /**
39
+ * Strip credentials from URL-shaped strings so they can be safely emitted in
40
+ * free-form text (error messages, stacks, lifted `request_url` fields). Unlike
41
+ * {@link redactSensitive}, which is key-based, this scrubs secrets embedded in
42
+ * the *value* itself:
43
+ *
44
+ * - URL userinfo: `http://user:pass@host` → `http://user:[REDACTED]@host`
45
+ * - sensitive query params: `?access_token=abc` → `?access_token=[REDACTED]`
46
+ *
47
+ * It is intentionally tolerant: it operates on any string (a DSN, a Mongo URI,
48
+ * an axios error message containing a URL) via regex rather than requiring a
49
+ * parseable URL, so malformed or partial URLs in error text are still scrubbed.
50
+ * Non-URL strings pass through unchanged.
51
+ */
52
+ export declare function sanitizeUrlCredentials(input: string): string;
53
+ /**
54
+ * Apply {@link sanitizeUrlCredentials} to the `message` and `stack` of a
55
+ * serialized-error-shaped object, returning a new object. Used by the logger's
56
+ * JSON and text paths so errors carrying DSNs, Mongo URIs, or
57
+ * `?access_token=`-bearing URLs do not leak credentials (the serialized error
58
+ * bypasses the key-based redactor). Returns the input unchanged when falsy.
59
+ */
60
+ export declare function sanitizeSerializedError<T extends {
61
+ message?: unknown;
62
+ stack?: unknown;
63
+ } | undefined>(error: T): T;
64
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../../../src/src/utils/logger/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,eAAe,CAAC;AA2CrC;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGnD;AA6ED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAEhD;AA2BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA4B5D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,CAAC,SAAS;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,EAC5D,KAAK,EAAE,CAAC,GAAG,CAAC,CAMb"}
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Secret / credential redaction for structured log context.
3
+ *
4
+ * Defense-in-depth (#1989): the logger, the error-logging path, and the
5
+ * observability log buffer all accept arbitrary `context`/`data` objects from
6
+ * callers and serialize them to log sinks. There is no guarantee a caller
7
+ * never hands us a tokens object, an `Authorization` header bag, or a request
8
+ * body with a password field. This pass masks values whose *key* looks like a
9
+ * credential before serialization, so an accidental
10
+ * `logger.info("...", { authorization: token })` cannot leak the secret.
11
+ *
12
+ * Scope is intentionally key-based: we do not attempt to find secrets embedded
13
+ * in free-form message strings (too lossy). The deny-list errs toward
14
+ * over-redaction — masking a benign `tokenCount` is acceptable; leaking a real
15
+ * token is not. The traversal fails *closed*: on a cycle, depth overflow, or a
16
+ * throwing getter it returns {@link REDACTED} rather than risk emitting an
17
+ * unredacted object.
18
+ */
19
+ import { isRecord } from "./core.js";
20
+ /** Replacement value substituted for any sensitive field. */
21
+ export const REDACTED = "[REDACTED]";
22
+ /**
23
+ * Normalized substrings that mark a key as sensitive. Matching is done against
24
+ * a lowercased, non-alphanumeric-stripped form of the key, so `API-Key`,
25
+ * `api_key`, and `apiKey` all collapse to `apikey` and match.
26
+ *
27
+ * Deliberately omitted to avoid false positives that swamp real logs:
28
+ * - bare `"auth"` (would mask `author`); `authorization`/`authToken` are still
29
+ * covered via `authorization`/`token`.
30
+ * - short tokens like `"dsn"`/`"sas"` (would mask `feedsNamespace`, etc.).
31
+ */
32
+ const SENSITIVE_KEY_PATTERNS = [
33
+ "password",
34
+ "passwd",
35
+ "pwd",
36
+ "passphrase",
37
+ "secret",
38
+ "clientsecret",
39
+ "token",
40
+ "apikey",
41
+ "accesskey",
42
+ "privatekey",
43
+ "credential",
44
+ "authorization",
45
+ "cookie",
46
+ "bearer",
47
+ "jwt",
48
+ "connectionstring",
49
+ "signature",
50
+ "sessionid",
51
+ "sid",
52
+ "otp",
53
+ "mfa",
54
+ "pin",
55
+ "salt",
56
+ "xsrf",
57
+ "csrf",
58
+ ];
59
+ /** Stop traversing past this depth to keep the pass cheap and stack-safe. */
60
+ const MAX_DEPTH = 16;
61
+ /**
62
+ * Whether a context key names a credential and should have its value masked.
63
+ *
64
+ * Uses substring matching on a normalized key, so `clientSecret`,
65
+ * `x-api-key`, and `refresh_token` all match while benign words that merely
66
+ * *contain* a pattern as a separate token (e.g. `author`) do not — `author`
67
+ * normalizes to `author`, which contains none of the patterns.
68
+ */
69
+ export function isSensitiveKey(key) {
70
+ const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
71
+ return SENSITIVE_KEY_PATTERNS.some((pattern) => normalized.includes(pattern));
72
+ }
73
+ /**
74
+ * A non-null, non-array object. {@link isRecord} covers class instances too,
75
+ * whose enumerable fields `JSON.stringify` *would* serialize, so we must
76
+ * traverse them to catch secrets.
77
+ */
78
+ function isTraversableRecord(value) {
79
+ return isRecord(value);
80
+ }
81
+ function hasToJson(value) {
82
+ return typeof value.toJSON === "function";
83
+ }
84
+ function redactValue(value, depth, seen) {
85
+ if (Array.isArray(value)) {
86
+ if (depth >= MAX_DEPTH || seen.has(value))
87
+ return REDACTED;
88
+ seen.add(value);
89
+ try {
90
+ return value.map((item) => redactValue(item, depth + 1, seen));
91
+ }
92
+ finally {
93
+ seen.delete(value);
94
+ }
95
+ }
96
+ // Objects defining `toJSON` (Date, URL, custom serializers) are serialized
97
+ // by `JSON.stringify` via the *return value* of `toJSON`, not their own
98
+ // enumerable keys. A key-based pass over the object's own properties would
99
+ // therefore miss credentials smuggled through `toJSON`, e.g.
100
+ // `{ toJSON: () => ({ apiKey: "sk-..." }) }` (CODEX P2). When `toJSON`
101
+ // returns a non-scalar (an object/array that could carry credential keys),
102
+ // redact *that* — the thing actually emitted. When it returns a scalar
103
+ // (Date/URL → ISO string), the original object is left intact, preserving
104
+ // prior behavior and identity.
105
+ if (isRecord(value) && hasToJson(value)) {
106
+ if (depth >= MAX_DEPTH || seen.has(value))
107
+ return REDACTED;
108
+ seen.add(value);
109
+ try {
110
+ const serialized = value.toJSON();
111
+ if (isRecord(serialized) || Array.isArray(serialized)) {
112
+ return redactValue(serialized, depth + 1, seen);
113
+ }
114
+ // Scalar result (string/number/…): the object serializes safely as-is.
115
+ return value;
116
+ }
117
+ catch {
118
+ // A throwing toJSON must never let the raw object (whose own keys we
119
+ // skipped) through: fail closed.
120
+ return REDACTED;
121
+ }
122
+ finally {
123
+ seen.delete(value);
124
+ }
125
+ }
126
+ if (isTraversableRecord(value)) {
127
+ if (depth >= MAX_DEPTH || seen.has(value))
128
+ return REDACTED;
129
+ seen.add(value);
130
+ try {
131
+ const out = {};
132
+ for (const [key, child] of Object.entries(value)) {
133
+ out[key] = isSensitiveKey(key) ? REDACTED : redactValue(child, depth + 1, seen);
134
+ }
135
+ return out;
136
+ }
137
+ catch {
138
+ // A throwing getter (or other access error) must never let an
139
+ // unredacted object through: fail closed.
140
+ return REDACTED;
141
+ }
142
+ finally {
143
+ seen.delete(value);
144
+ }
145
+ }
146
+ // Primitives and scalar-serializing objects (Date, URL, …) are returned
147
+ // untouched: they are not key/value bags we can safely rewrite.
148
+ return value;
149
+ }
150
+ /**
151
+ * Returns a redacted deep copy of `context`. Any property whose key is
152
+ * {@link isSensitiveKey} has its value replaced with {@link REDACTED}; nested
153
+ * plain objects, class instances, and arrays are traversed. The input is never
154
+ * mutated, and the pass fails closed (returns {@link REDACTED}) on cycles,
155
+ * depth overflow, or a throwing getter.
156
+ */
157
+ export function redactSensitive(context) {
158
+ return redactValue(context, 0, new Set());
159
+ }
160
+ /**
161
+ * Query-string parameter names that commonly carry credentials in URLs.
162
+ * Matched case-insensitively against the parameter name.
163
+ */
164
+ const SENSITIVE_URL_PARAMS = [
165
+ "access_token",
166
+ "accesstoken",
167
+ "refresh_token",
168
+ "api_key",
169
+ "apikey",
170
+ "code",
171
+ "token",
172
+ "secret",
173
+ "client_secret",
174
+ "password",
175
+ "passwd",
176
+ "pwd",
177
+ "state",
178
+ "sig",
179
+ "signature",
180
+ "auth",
181
+ ];
182
+ const URL_USERINFO_RE = /(\b[a-z][a-z0-9+.-]*:\/\/)([^/?#@\s]+)@/gi;
183
+ /**
184
+ * Strip credentials from URL-shaped strings so they can be safely emitted in
185
+ * free-form text (error messages, stacks, lifted `request_url` fields). Unlike
186
+ * {@link redactSensitive}, which is key-based, this scrubs secrets embedded in
187
+ * the *value* itself:
188
+ *
189
+ * - URL userinfo: `http://user:pass@host` → `http://user:[REDACTED]@host`
190
+ * - sensitive query params: `?access_token=abc` → `?access_token=[REDACTED]`
191
+ *
192
+ * It is intentionally tolerant: it operates on any string (a DSN, a Mongo URI,
193
+ * an axios error message containing a URL) via regex rather than requiring a
194
+ * parseable URL, so malformed or partial URLs in error text are still scrubbed.
195
+ * Non-URL strings pass through unchanged.
196
+ */
197
+ export function sanitizeUrlCredentials(input) {
198
+ if (typeof input !== "string" || input.length === 0)
199
+ return input;
200
+ // 1) userinfo: scheme://user:pass@ → mask the password (and any bare creds).
201
+ let out = input.replace(URL_USERINFO_RE, (_match, scheme, userinfo) => {
202
+ const colon = userinfo.indexOf(":");
203
+ if (colon === -1) {
204
+ // `scheme://token@host` — the whole userinfo is credential-like.
205
+ return `${scheme}${REDACTED}@`;
206
+ }
207
+ const user = userinfo.slice(0, colon);
208
+ return `${scheme}${user}:${REDACTED}@`;
209
+ });
210
+ // 2) sensitive query/fragment params: `key=value` → `key=[REDACTED]`.
211
+ // Match `?key=`, `&key=`, `;key=` separators and stop at the next delimiter.
212
+ out = out.replace(/([?&;])([a-z0-9_.\-]+)=([^&#;\s]*)/gi, (match, sep, key, _val) => {
213
+ const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
214
+ const sensitive = SENSITIVE_URL_PARAMS.some((p) => normalized === p.replace(/[^a-z0-9]/g, ""));
215
+ return sensitive ? `${sep}${key}=${REDACTED}` : match;
216
+ });
217
+ return out;
218
+ }
219
+ /**
220
+ * Apply {@link sanitizeUrlCredentials} to the `message` and `stack` of a
221
+ * serialized-error-shaped object, returning a new object. Used by the logger's
222
+ * JSON and text paths so errors carrying DSNs, Mongo URIs, or
223
+ * `?access_token=`-bearing URLs do not leak credentials (the serialized error
224
+ * bypasses the key-based redactor). Returns the input unchanged when falsy.
225
+ */
226
+ export function sanitizeSerializedError(error) {
227
+ if (!error)
228
+ return error;
229
+ const out = { ...error };
230
+ if (typeof out.message === "string")
231
+ out.message = sanitizeUrlCredentials(out.message);
232
+ if (typeof out.stack === "string")
233
+ out.stack = sanitizeUrlCredentials(out.stack);
234
+ return out;
235
+ }
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.636";
2
+ export declare const VERSION = "0.1.637";
3
3
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
3
  /** Shared version value. */
4
- export const VERSION = "0.1.636";
4
+ export const VERSION = "0.1.637";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.636",
3
+ "version": "0.1.637",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -358,6 +358,7 @@
358
358
  "mdast-util-to-string": "4.0.0",
359
359
  "react": "19.2.4",
360
360
  "react-dom": "19.2.4",
361
+ "redis": "5.11.0",
361
362
  "rehype-highlight": "7.0.2",
362
363
  "rehype-raw": "7.0.0",
363
364
  "rehype-sanitize": "6.0.0",