@mastra/observability 1.17.0-alpha.0 → 1.17.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # @mastra/observability
2
2
 
3
+ ## 1.17.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added an `indexed` redaction style to `SensitiveDataFilter`. Instead of collapsing every sensitive value to the same `[REDACTED]` string, each unique value gets a stable token derived from the first matched field name, like `[APIKEY_1]`. ([#21328](https://github.com/mastra-ai/mastra/pull/21328))
8
+
9
+ ```ts
10
+ new SensitiveDataFilter({
11
+ redactionStyle: 'indexed',
12
+ });
13
+ ```
14
+
15
+ See [#21313](https://github.com/mastra-ai/mastra/issues/21313)
16
+
17
+ - Fixed traces that start under an external parent span not appearing in Mastra Studio. ([#20499](https://github.com/mastra-ai/mastra/pull/20499))
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies [[`088e41e`](https://github.com/mastra-ai/mastra/commit/088e41e434ed05f2c674b254f1034ec46a57a7be), [`aa3e7be`](https://github.com/mastra-ai/mastra/commit/aa3e7be30f8addb0278ea74429f4df054517a287), [`d118873`](https://github.com/mastra-ai/mastra/commit/d118873cfd5074b1f814a1c169a97ca7a3a29174), [`b2f0013`](https://github.com/mastra-ai/mastra/commit/b2f0013375588d40c03c13e843b99c0ff8872ca5), [`3b541ae`](https://github.com/mastra-ai/mastra/commit/3b541ae5d410c52b80a7e381d84d021cddb9a449), [`79dd7c2`](https://github.com/mastra-ai/mastra/commit/79dd7c261ee6be1fafedd4651959394db21d2cba), [`90822db`](https://github.com/mastra-ai/mastra/commit/90822dba08fb2169c518e4a6d7f127c098eb46b8), [`898bba4`](https://github.com/mastra-ai/mastra/commit/898bba46d4806dd255a44e5dc3a3d5827eaefdfe), [`b9a28ec`](https://github.com/mastra-ai/mastra/commit/b9a28ecf7acdc0cb7a543d5b660f9fbee301df9a), [`f9aab1c`](https://github.com/mastra-ai/mastra/commit/f9aab1cfc3fda03238a7fd7bd8b794e07497878c), [`3700208`](https://github.com/mastra-ai/mastra/commit/37002080c7838267803a7e579a7d58b908d62f36), [`e31421b`](https://github.com/mastra-ai/mastra/commit/e31421bc9c11c03c6e74f447ecb5820000e2b9d7), [`8b7131e`](https://github.com/mastra-ai/mastra/commit/8b7131eb0407f58f5205e68fb27b81f026488f28), [`161258b`](https://github.com/mastra-ai/mastra/commit/161258b3473a6d0fce00a43cab59d119a49a232f), [`aece0e7`](https://github.com/mastra-ai/mastra/commit/aece0e7cb124ae1eb1230689b887f5554b9a0bf0), [`ae79e34`](https://github.com/mastra-ai/mastra/commit/ae79e34c0bd8674fc24c7524217bfc4a051c6136), [`59d8898`](https://github.com/mastra-ai/mastra/commit/59d8898c8cb48b342fe5bcb5eee803cc8cc95060), [`a6c4399`](https://github.com/mastra-ai/mastra/commit/a6c4399763590b3dae21a2c81826e89a3b1deee4), [`a40f915`](https://github.com/mastra-ai/mastra/commit/a40f9157690d89ef13ce825cc88e30be581de5d4), [`8ea8038`](https://github.com/mastra-ai/mastra/commit/8ea80386fde53d26e2c0b2060c53bc9bd9be10f3), [`be31796`](https://github.com/mastra-ai/mastra/commit/be3179624ad5f77cff5fa342cd08046bf7605283), [`79c4f82`](https://github.com/mastra-ai/mastra/commit/79c4f8295f568752eeadf8a9b50010a7d9ec06ae), [`7dafa4f`](https://github.com/mastra-ai/mastra/commit/7dafa4f670fb16ec8ff07349645a00ca12bc5794)]:
22
+ - @mastra/core@1.59.0
23
+
24
+ ## 1.17.0-alpha.1
25
+
26
+ ### Minor Changes
27
+
28
+ - Added an `indexed` redaction style to `SensitiveDataFilter`. Instead of collapsing every sensitive value to the same `[REDACTED]` string, each unique value gets a stable token derived from the first matched field name, like `[APIKEY_1]`. ([#21328](https://github.com/mastra-ai/mastra/pull/21328))
29
+
30
+ ```ts
31
+ new SensitiveDataFilter({
32
+ redactionStyle: 'indexed',
33
+ });
34
+ ```
35
+
36
+ See [#21313](https://github.com/mastra-ai/mastra/issues/21313)
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies [[`898bba4`](https://github.com/mastra-ai/mastra/commit/898bba46d4806dd255a44e5dc3a3d5827eaefdfe), [`f9aab1c`](https://github.com/mastra-ai/mastra/commit/f9aab1cfc3fda03238a7fd7bd8b794e07497878c), [`e31421b`](https://github.com/mastra-ai/mastra/commit/e31421bc9c11c03c6e74f447ecb5820000e2b9d7), [`aece0e7`](https://github.com/mastra-ai/mastra/commit/aece0e7cb124ae1eb1230689b887f5554b9a0bf0)]:
41
+ - @mastra/core@1.59.0-alpha.2
42
+
3
43
  ## 1.17.0-alpha.0
4
44
 
5
45
  ### Minor Changes
package/dist/config.d.ts CHANGED
@@ -278,6 +278,7 @@ export declare const observabilityRegistryConfigSchema: z.ZodObject<{
278
278
  redactionStyle: z.ZodOptional<z.ZodEnum<{
279
279
  full: "full";
280
280
  partial: "partial";
281
+ indexed: "indexed";
281
282
  }>>;
282
283
  }, z.core.$strict>]>>;
283
284
  }, z.core.$loose>;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -35,6 +35,7 @@ path = __toESM(path, 1);
35
35
  let stream_web = require("stream/web");
36
36
  let _mastra_core_features = require("@mastra/core/features");
37
37
  let _mastra_core_storage = require("@mastra/core/storage");
38
+ let crypto = require("crypto");
38
39
  //#region src/bus/route-event.ts
39
40
  /**
40
41
  * Route a single event to the appropriate method on a handler.
@@ -770,7 +771,11 @@ const observabilityConfigValueSchema = zod_v4.z.object(observabilityInstanceConf
770
771
  const sensitiveDataFilterOptionsSchema = zod_v4.z.object({
771
772
  sensitiveFields: zod_v4.z.array(zod_v4.z.string()).optional(),
772
773
  redactionToken: zod_v4.z.string().optional(),
773
- redactionStyle: zod_v4.z.enum(["full", "partial"]).optional()
774
+ redactionStyle: zod_v4.z.enum([
775
+ "full",
776
+ "partial",
777
+ "indexed"
778
+ ]).optional()
774
779
  }).strict();
775
780
  const observabilityRegistryConfigSchema = zod_v4.z.object({
776
781
  default: zod_v4.z.object({ enabled: zod_v4.z.boolean().optional() }).optional().nullable(),
@@ -8748,13 +8753,26 @@ var ObservabilityRegistry = class {
8748
8753
  //#endregion
8749
8754
  //#region src/span_processors/sensitive-data-filter.ts
8750
8755
  /**
8756
+ * Maximum number of traces to keep indexed-redaction state for.
8757
+ * Spans never signal trace completion, so state is evicted least-recently-used.
8758
+ */
8759
+ const MAX_TRACKED_TRACES = 1e3;
8760
+ /**
8761
+ * Maximum number of unique values tracked per trace for indexed redaction.
8762
+ * Once reached, new values fall back to the full redaction token while
8763
+ * already-tracked values keep their assigned tokens.
8764
+ */
8765
+ const MAX_TRACKED_VALUES_PER_TRACE = 1e3;
8766
+ /**
8751
8767
  * SensitiveDataFilter
8752
8768
  *
8753
8769
  * An SpanOutputProcessor that redacts sensitive information from span fields.
8754
8770
  *
8755
8771
  * - Sensitive keys are matched case-insensitively, normalized to remove separators.
8756
- * - Sensitive values are redacted using either full or partial redaction.
8772
+ * - Sensitive values are redacted using full, partial, or indexed redaction.
8757
8773
  * - Partial redaction always keeps 3 chars at the start and end.
8774
+ * - Indexed redaction assigns each unique value a stable `[LABEL_N]` token,
8775
+ * consistent across all spans of a trace.
8758
8776
  * - JSON strings containing sensitive fields are parsed and redacted.
8759
8777
  * - If filtering a field fails, the field is replaced with:
8760
8778
  * `{ error: { processor: "sensitive-data-filter" } }`
@@ -8764,6 +8782,7 @@ var SensitiveDataFilter = class {
8764
8782
  sensitiveFields;
8765
8783
  redactionToken;
8766
8784
  redactionStyle;
8785
+ traceStates = /* @__PURE__ */ new Map();
8767
8786
  constructor(options = {}) {
8768
8787
  this.sensitiveFields = (options.sensitiveFields || [
8769
8788
  "password",
@@ -8793,42 +8812,63 @@ var SensitiveDataFilter = class {
8793
8812
  * @returns A new span with sensitive values redacted
8794
8813
  */
8795
8814
  process(span) {
8796
- span.attributes = this.tryFilter(span.attributes);
8797
- span.metadata = this.tryFilter(span.metadata);
8798
- span.input = this.tryFilter(span.input);
8799
- span.output = this.tryFilter(span.output);
8800
- span.errorInfo = this.tryFilter(span.errorInfo);
8815
+ const indexedState = this.redactionStyle === "indexed" ? this.getTraceState(span.traceId) : void 0;
8816
+ span.attributes = this.tryFilter(span.attributes, indexedState);
8817
+ span.metadata = this.tryFilter(span.metadata, indexedState);
8818
+ span.input = this.tryFilter(span.input, indexedState);
8819
+ span.output = this.tryFilter(span.output, indexedState);
8820
+ span.errorInfo = this.tryFilter(span.errorInfo, indexedState);
8801
8821
  return span;
8802
8822
  }
8803
8823
  /**
8824
+ * Get (or create) the indexed-redaction state for a trace.
8825
+ * Uses the Map's insertion order as an LRU: accessed traces are re-inserted,
8826
+ * and the least recently used trace is evicted once the cap is exceeded.
8827
+ */
8828
+ getTraceState(traceId) {
8829
+ let state = this.traceStates.get(traceId);
8830
+ if (state) this.traceStates.delete(traceId);
8831
+ else state = {
8832
+ tokensByValue: /* @__PURE__ */ new Map(),
8833
+ counters: /* @__PURE__ */ new Map()
8834
+ };
8835
+ this.traceStates.set(traceId, state);
8836
+ while (this.traceStates.size > MAX_TRACKED_TRACES) {
8837
+ const oldest = this.traceStates.keys().next().value;
8838
+ if (oldest === void 0) break;
8839
+ this.traceStates.delete(oldest);
8840
+ }
8841
+ return state;
8842
+ }
8843
+ /**
8804
8844
  * Recursively filter objects/arrays for sensitive keys.
8805
8845
  * Handles circular references by replacing with a marker.
8806
8846
  * Also attempts to parse and redact JSON strings.
8807
8847
  */
8808
- deepFilter(obj, seen = /* @__PURE__ */ new WeakSet()) {
8848
+ deepFilter(obj, seen = /* @__PURE__ */ new WeakSet(), indexedState) {
8809
8849
  if (obj === null || typeof obj !== "object") {
8810
8850
  if (typeof obj === "string") {
8811
8851
  const trimmed = obj.trim();
8812
- if (trimmed.startsWith("{") || trimmed.startsWith("[")) return this.redactJsonString(obj);
8852
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) return this.redactJsonString(obj, indexedState);
8813
8853
  }
8814
8854
  return obj;
8815
8855
  }
8816
8856
  if (seen.has(obj)) return "[Circular Reference]";
8817
8857
  seen.add(obj);
8818
8858
  if (obj instanceof Date) return obj;
8819
- if (Array.isArray(obj)) return obj.map((item) => this.deepFilter(item, seen));
8859
+ if (Array.isArray(obj)) return obj.map((item) => this.deepFilter(item, seen, indexedState));
8820
8860
  const filtered = {};
8821
8861
  for (const key of Object.keys(obj)) {
8822
8862
  const normKey = this.normalizeKey(key);
8823
- if (this.isSensitive(normKey)) if (obj[key] && typeof obj[key] === "object") filtered[key] = this.deepFilter(obj[key], seen);
8824
- else filtered[key] = this.redactValue(obj[key]);
8825
- else filtered[key] = this.deepFilter(obj[key], seen);
8863
+ if (this.isSensitive(normKey)) if (obj[key] && typeof obj[key] === "object") filtered[key] = this.deepFilter(obj[key], seen, indexedState);
8864
+ else filtered[key] = this.redactValue(obj[key], normKey, indexedState);
8865
+ else filtered[key] = this.deepFilter(obj[key], seen, indexedState);
8826
8866
  }
8827
8867
  return filtered;
8828
8868
  }
8829
- tryFilter(value) {
8869
+ tryFilter(value, indexedState) {
8830
8870
  try {
8831
- return this.deepFilter(value);
8871
+ return this.deepFilter(value, /* @__PURE__ */ new WeakSet(), indexedState);
8832
8872
  } catch {
8833
8873
  return { error: { processor: this.name } };
8834
8874
  }
@@ -8858,11 +8898,11 @@ var SensitiveDataFilter = class {
8858
8898
  * Attempt to parse a string as JSON and redact sensitive fields within it.
8859
8899
  * If parsing fails or no sensitive data is found, returns the original string.
8860
8900
  */
8861
- redactJsonString(str) {
8901
+ redactJsonString(str, indexedState) {
8862
8902
  try {
8863
8903
  const parsed = JSON.parse(str);
8864
8904
  if (parsed && typeof parsed === "object") {
8865
- const filtered = this.deepFilter(parsed, /* @__PURE__ */ new WeakSet());
8905
+ const filtered = this.deepFilter(parsed, /* @__PURE__ */ new WeakSet(), indexedState);
8866
8906
  return JSON.stringify(filtered);
8867
8907
  }
8868
8908
  return str;
@@ -8874,17 +8914,36 @@ var SensitiveDataFilter = class {
8874
8914
  * Redact a sensitive value.
8875
8915
  * - Full style: replaces with a fixed token.
8876
8916
  * - Partial style: shows 3 chars at start and end, hides the middle.
8917
+ * - Indexed style: replaces with a stable `[LABEL_N]` token, where the label
8918
+ * comes from the normalized field name and the same value always maps to
8919
+ * the same token within a trace.
8877
8920
  *
8878
- * Non-string values are converted to strings before partial redaction.
8879
- */
8880
- redactValue(value) {
8881
- if (this.redactionStyle === "full") return this.redactionToken;
8882
- const str = String(value);
8883
- const len = str.length;
8884
- if (len <= 6) return this.redactionToken;
8885
- return str.slice(0, 3) + "…" + str.slice(len - 3);
8921
+ * Non-string values are converted to strings before partial or indexed redaction.
8922
+ */
8923
+ redactValue(value, normKey, indexedState) {
8924
+ if (this.redactionStyle === "partial") {
8925
+ const str = String(value);
8926
+ const len = str.length;
8927
+ if (len <= 6) return this.redactionToken;
8928
+ return str.slice(0, 3) + "…" + str.slice(len - 3);
8929
+ }
8930
+ if (this.redactionStyle === "indexed" && indexedState) {
8931
+ const valueKey = (0, crypto.createHash)("sha256").update(String(value)).digest("hex");
8932
+ const existing = indexedState.tokensByValue.get(valueKey);
8933
+ if (existing) return existing;
8934
+ if (indexedState.tokensByValue.size >= MAX_TRACKED_VALUES_PER_TRACE) return this.redactionToken;
8935
+ const label = normKey.toUpperCase();
8936
+ const count = (indexedState.counters.get(label) ?? 0) + 1;
8937
+ indexedState.counters.set(label, count);
8938
+ const token = `[${label}_${count}]`;
8939
+ indexedState.tokensByValue.set(valueKey, token);
8940
+ return token;
8941
+ }
8942
+ return this.redactionToken;
8943
+ }
8944
+ async shutdown() {
8945
+ this.traceStates.clear();
8886
8946
  }
8887
- async shutdown() {}
8888
8947
  };
8889
8948
  //#endregion
8890
8949
  //#region src/default.ts