@composed-di/core 0.5.3-alpha → 0.6.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/errors.d.ts +0 -2
  2. package/dist/errors.d.ts.map +1 -1
  3. package/dist/errors.js +4 -4
  4. package/dist/errors.js.map +1 -1
  5. package/dist/index.d.ts +0 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +0 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/serviceFactory.d.ts.map +1 -1
  10. package/dist/serviceFactory.js.map +1 -1
  11. package/dist/serviceKey.d.ts +6 -0
  12. package/dist/serviceKey.d.ts.map +1 -1
  13. package/dist/serviceKey.js.map +1 -1
  14. package/dist/serviceModule.d.ts +1 -11
  15. package/dist/serviceModule.d.ts.map +1 -1
  16. package/dist/serviceModule.js +3 -146
  17. package/dist/serviceModule.js.map +1 -1
  18. package/dist/serviceScope.d.ts.map +1 -1
  19. package/dist/serviceScope.js.map +1 -1
  20. package/dist/serviceSelector.d.ts.map +1 -1
  21. package/dist/serviceSelector.js.map +1 -1
  22. package/dist/utils.d.ts.map +1 -1
  23. package/dist/utils.js.map +1 -1
  24. package/package.json +17 -17
  25. package/src/errors.ts +2 -10
  26. package/src/index.ts +7 -9
  27. package/src/serviceFactory.ts +33 -33
  28. package/src/serviceKey.ts +11 -4
  29. package/src/serviceModule.ts +53 -217
  30. package/src/serviceScope.ts +2 -2
  31. package/src/serviceSelector.ts +4 -4
  32. package/src/utils.ts +103 -103
  33. package/dist/redactingEventListener.d.ts +0 -119
  34. package/dist/redactingEventListener.d.ts.map +0 -1
  35. package/dist/redactingEventListener.js +0 -169
  36. package/dist/redactingEventListener.js.map +0 -1
  37. package/dist/serviceEventListener.d.ts +0 -133
  38. package/dist/serviceEventListener.d.ts.map +0 -1
  39. package/dist/serviceEventListener.js +0 -3
  40. package/dist/serviceEventListener.js.map +0 -1
  41. package/dist/serviceModuleListener.d.ts +0 -133
  42. package/dist/serviceModuleListener.d.ts.map +0 -1
  43. package/dist/serviceModuleListener.js +0 -3
  44. package/dist/serviceModuleListener.js.map +0 -1
  45. package/src/redactingEventListener.ts +0 -256
  46. package/src/serviceModuleListener.ts +0 -139
package/src/utils.ts CHANGED
@@ -1,38 +1,38 @@
1
- import { ServiceModule } from './serviceModule';
2
- import { ServiceKey } from './serviceKey';
1
+ import { ServiceModule } from './serviceModule'
2
+ import { ServiceKey } from './serviceKey'
3
3
 
4
4
  export interface DotGraphOptions {
5
5
  /** Graph direction: 'TB' (top-bottom), 'LR' (left-right), 'BT' (bottom-top), 'RL' (right-left) */
6
- direction?: 'TB' | 'LR' | 'BT' | 'RL';
6
+ direction?: 'TB' | 'LR' | 'BT' | 'RL'
7
7
  /** Title for the graph */
8
- title?: string;
8
+ title?: string
9
9
  /** Show nodes with no dependencies in a different color */
10
- highlightLeaves?: boolean;
10
+ highlightLeaves?: boolean
11
11
  /** Show nodes with no dependents in a different color */
12
- highlightRoots?: boolean;
12
+ highlightRoots?: boolean
13
13
  }
14
14
 
15
15
  export interface MermaidGraphOptions {
16
16
  /** Graph direction: 'TB' (top-bottom), 'LR' (left-right), 'BT' (bottom-top), 'RL' (right-left) */
17
- direction?: 'TB' | 'LR' | 'BT' | 'RL';
17
+ direction?: 'TB' | 'LR' | 'BT' | 'RL'
18
18
  /** Show nodes with no dependencies in a different color */
19
- highlightLeaves?: boolean;
19
+ highlightLeaves?: boolean
20
20
  /** Show nodes with no dependents in a different color */
21
- highlightRoots?: boolean;
21
+ highlightRoots?: boolean
22
22
  }
23
23
 
24
24
  /**
25
25
  * Escapes special characters in strings for DOT notation
26
26
  */
27
27
  function escapeDotString(str: string): string {
28
- return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
28
+ return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n')
29
29
  }
30
30
 
31
31
  /**
32
32
  * Escapes special characters in strings for Mermaid notation
33
33
  */
34
34
  function escapeMermaidString(str: string): string {
35
- return str.replace(/"/g, '#quot;');
35
+ return str.replace(/"/g, '#quot;')
36
36
  }
37
37
 
38
38
  /**
@@ -56,98 +56,98 @@ export function createDotGraph(
56
56
  highlightRoots: true,
57
57
  },
58
58
  ): string {
59
- const factories = module.factories;
60
- const lines: string[] = [];
59
+ const factories = module.factories
60
+ const lines: string[] = []
61
61
 
62
62
  // Start the digraph
63
- lines.push('digraph ServiceDependencies {');
64
- lines.push(` label="${title}";`);
65
- lines.push(' labelloc="t";');
66
- lines.push(' fontsize=16;');
67
- lines.push(` rankdir=${direction};`);
68
- lines.push('');
63
+ lines.push('digraph ServiceDependencies {')
64
+ lines.push(` label="${title}";`)
65
+ lines.push(' labelloc="t";')
66
+ lines.push(' fontsize=16;')
67
+ lines.push(` rankdir=${direction};`)
68
+ lines.push('')
69
69
 
70
70
  // Default node styling
71
- lines.push(' node [');
72
- lines.push(' shape=box,');
73
- lines.push(' style="rounded,filled",');
74
- lines.push(' fillcolor="#e1f5ff",');
75
- lines.push(' color="#0288d1",');
76
- lines.push(' fontname="Arial",');
77
- lines.push(' fontsize=12');
78
- lines.push(' ];');
79
- lines.push('');
71
+ lines.push(' node [')
72
+ lines.push(' shape=box,')
73
+ lines.push(' style="rounded,filled",')
74
+ lines.push(' fillcolor="#e1f5ff",')
75
+ lines.push(' color="#0288d1",')
76
+ lines.push(' fontname="Arial",')
77
+ lines.push(' fontsize=12')
78
+ lines.push(' ];')
79
+ lines.push('')
80
80
 
81
81
  // Default edge styling
82
- lines.push(' edge [');
83
- lines.push(' color="#666666",');
84
- lines.push(' arrowsize=0.8');
85
- lines.push(' ];');
86
- lines.push('');
82
+ lines.push(' edge [')
83
+ lines.push(' color="#666666",')
84
+ lines.push(' arrowsize=0.8')
85
+ lines.push(' ];')
86
+ lines.push('')
87
87
 
88
88
  // Build dependency maps to identify leaves and roots
89
- const hasDependencies = new Set<string>();
90
- const hasDependents = new Set<string>();
89
+ const hasDependencies = new Set<string>()
90
+ const hasDependents = new Set<string>()
91
91
 
92
92
  factories.forEach((factory) => {
93
- const serviceName = factory.provides.name;
93
+ const serviceName = factory.provides.name
94
94
 
95
95
  if (factory.dependsOn.length > 0) {
96
- hasDependencies.add(serviceName);
96
+ hasDependencies.add(serviceName)
97
97
  }
98
98
 
99
99
  factory.dependsOn.forEach((dependency: ServiceKey<unknown>) => {
100
- hasDependents.add(dependency.name);
101
- });
102
- });
100
+ hasDependents.add(dependency.name)
101
+ })
102
+ })
103
103
 
104
104
  // Define nodes with special styling for leaves and roots
105
- const nodeIds = new Map<string, string>();
106
- let nodeCounter = 0;
105
+ const nodeIds = new Map<string, string>()
106
+ let nodeCounter = 0
107
107
 
108
108
  factories.forEach((factory) => {
109
- const serviceName = factory.provides.name;
110
- const nodeId = `node${nodeCounter++}`;
111
- nodeIds.set(serviceName, nodeId);
109
+ const serviceName = factory.provides.name
110
+ const nodeId = `node${nodeCounter++}`
111
+ nodeIds.set(serviceName, nodeId)
112
112
 
113
- const isLeaf = !hasDependencies.has(serviceName);
114
- const isRoot = !hasDependents.has(serviceName);
113
+ const isLeaf = !hasDependencies.has(serviceName)
114
+ const isRoot = !hasDependents.has(serviceName)
115
115
 
116
- let nodeStyle = '';
116
+ let nodeStyle = ''
117
117
 
118
118
  if (highlightLeaves && isLeaf) {
119
- nodeStyle = ' [fillcolor="#c8e6c9", color="#388e3c"]';
119
+ nodeStyle = ' [fillcolor="#c8e6c9", color="#388e3c"]'
120
120
  } else if (highlightRoots && isRoot) {
121
- nodeStyle = ' [fillcolor="#ffccbc", color="#d84315"]';
121
+ nodeStyle = ' [fillcolor="#ffccbc", color="#d84315"]'
122
122
  }
123
123
 
124
124
  lines.push(
125
125
  ` ${nodeId} [label="${escapeDotString(serviceName)}"]${nodeStyle};`,
126
- );
127
- });
126
+ )
127
+ })
128
128
 
129
- lines.push('');
129
+ lines.push('')
130
130
 
131
131
  // Define edges (dependencies)
132
132
  factories.forEach((factory) => {
133
- const serviceName = factory.provides.name;
134
- const serviceNodeId = nodeIds.get(serviceName)!;
133
+ const serviceName = factory.provides.name
134
+ const serviceNodeId = nodeIds.get(serviceName)!
135
135
 
136
136
  factory.dependsOn.forEach((dependency: ServiceKey<unknown>) => {
137
- const depName = dependency.name;
138
- const depNodeId = nodeIds.get(depName);
137
+ const depName = dependency.name
138
+ const depNodeId = nodeIds.get(depName)
139
139
 
140
140
  if (depNodeId) {
141
141
  // Arrow points from dependent to dependency (what needs it -> what provides it)
142
- lines.push(` ${serviceNodeId} -> ${depNodeId};`);
142
+ lines.push(` ${serviceNodeId} -> ${depNodeId};`)
143
143
  }
144
- });
145
- });
144
+ })
145
+ })
146
146
 
147
147
  // Close the digraph
148
- lines.push('}');
148
+ lines.push('}')
149
149
 
150
- return lines.join('\n');
150
+ return lines.join('\n')
151
151
  }
152
152
 
153
153
  /**
@@ -161,9 +161,9 @@ export function printDotGraph(
161
161
  module: ServiceModule,
162
162
  options?: DotGraphOptions,
163
163
  ): void {
164
- console.log(createDotGraph(module, options));
165
- console.log('\n\nCopy the DOT output above and paste it into:');
166
- console.log('https://dreampuf.github.io/GraphvizOnline/');
164
+ console.log(createDotGraph(module, options))
165
+ console.log('\n\nCopy the DOT output above and paste it into:')
166
+ console.log('https://dreampuf.github.io/GraphvizOnline/')
167
167
  }
168
168
 
169
169
  /**
@@ -185,79 +185,79 @@ export function createMermaidGraph(
185
185
  highlightRoots: true,
186
186
  },
187
187
  ): string {
188
- const factories = module.factories;
189
- const lines: string[] = [];
188
+ const factories = module.factories
189
+ const lines: string[] = []
190
190
 
191
191
  // Start the flowchart
192
- lines.push(`flowchart ${direction}`);
192
+ lines.push(`flowchart ${direction}`)
193
193
 
194
194
  // Build dependency maps to identify leaves and roots
195
- const hasDependencies = new Set<string>();
196
- const hasDependents = new Set<string>();
195
+ const hasDependencies = new Set<string>()
196
+ const hasDependents = new Set<string>()
197
197
 
198
198
  factories.forEach((factory) => {
199
- const serviceName = factory.provides.name;
199
+ const serviceName = factory.provides.name
200
200
 
201
201
  if (factory.dependsOn.length > 0) {
202
- hasDependencies.add(serviceName);
202
+ hasDependencies.add(serviceName)
203
203
  }
204
204
 
205
205
  factory.dependsOn.forEach((dependency) => {
206
- hasDependents.add(dependency.name);
207
- });
208
- });
206
+ hasDependents.add(dependency.name)
207
+ })
208
+ })
209
209
 
210
210
  // Define nodes with special styling for leaves and roots
211
- const nodeIds = new Map<string, string>();
212
- let nodeCounter = 0;
211
+ const nodeIds = new Map<string, string>()
212
+ let nodeCounter = 0
213
213
 
214
214
  factories.forEach((factory) => {
215
- const serviceName = factory.provides.name;
216
- const nodeId = `node${nodeCounter++}`;
217
- nodeIds.set(serviceName, nodeId);
215
+ const serviceName = factory.provides.name
216
+ const nodeId = `node${nodeCounter++}`
217
+ nodeIds.set(serviceName, nodeId)
218
218
 
219
- lines.push(` ${nodeId}["${escapeMermaidString(serviceName)}"]`);
220
- });
219
+ lines.push(` ${nodeId}["${escapeMermaidString(serviceName)}"]`)
220
+ })
221
221
 
222
- lines.push('');
222
+ lines.push('')
223
223
 
224
224
  // Define edges (dependencies)
225
225
  factories.forEach((factory) => {
226
- const serviceName = factory.provides.name;
227
- const serviceNodeId = nodeIds.get(serviceName)!;
226
+ const serviceName = factory.provides.name
227
+ const serviceNodeId = nodeIds.get(serviceName)!
228
228
 
229
229
  factory.dependsOn.forEach((dependency) => {
230
- const depName = dependency.name;
231
- const depNodeId = nodeIds.get(depName);
230
+ const depName = dependency.name
231
+ const depNodeId = nodeIds.get(depName)
232
232
 
233
233
  if (depNodeId) {
234
234
  // Arrow points from dependent to dependency (what needs it -> what provides it)
235
- lines.push(` ${serviceNodeId} --> ${depNodeId}`);
235
+ lines.push(` ${serviceNodeId} --> ${depNodeId}`)
236
236
  }
237
- });
238
- });
237
+ })
238
+ })
239
239
 
240
- lines.push('');
240
+ lines.push('')
241
241
 
242
242
  // Apply styling
243
243
  factories.forEach((factory) => {
244
- const serviceName = factory.provides.name;
245
- const serviceNodeId = nodeIds.get(serviceName)!;
244
+ const serviceName = factory.provides.name
245
+ const serviceNodeId = nodeIds.get(serviceName)!
246
246
 
247
- const isLeaf = !hasDependencies.has(serviceName);
248
- const isRoot = !hasDependents.has(serviceName);
247
+ const isLeaf = !hasDependencies.has(serviceName)
248
+ const isRoot = !hasDependents.has(serviceName)
249
249
 
250
250
  if (highlightLeaves && isLeaf) {
251
- lines.push(` style ${serviceNodeId} fill:#c8e6c9,stroke:#388e3c`);
251
+ lines.push(` style ${serviceNodeId} fill:#c8e6c9,stroke:#388e3c`)
252
252
  } else if (highlightRoots && isRoot) {
253
- lines.push(` style ${serviceNodeId} fill:#ffccbc,stroke:#d84315`);
253
+ lines.push(` style ${serviceNodeId} fill:#ffccbc,stroke:#d84315`)
254
254
  } else {
255
255
  // Default style
256
- lines.push(` style ${serviceNodeId} fill:#e1f5ff,stroke:#0288d1`);
256
+ lines.push(` style ${serviceNodeId} fill:#e1f5ff,stroke:#0288d1`)
257
257
  }
258
- });
258
+ })
259
259
 
260
- return lines.join('\n');
260
+ return lines.join('\n')
261
261
  }
262
262
 
263
263
  /**
@@ -271,7 +271,7 @@ export function printMermaidGraph(
271
271
  module: ServiceModule,
272
272
  options?: MermaidGraphOptions,
273
273
  ): void {
274
- console.log(createMermaidGraph(module, options));
275
- console.log('\n\nCopy the Mermaid output above and paste it into:');
276
- console.log('https://mermaid.live/');
274
+ console.log(createMermaidGraph(module, options))
275
+ console.log('\n\nCopy the Mermaid output above and paste it into:')
276
+ console.log('https://mermaid.live/')
277
277
  }
@@ -1,119 +0,0 @@
1
- import type { DisposeContext, EventSpan, InitializeContext, MethodCallContext, ServiceModuleListener } from './serviceModuleListener';
2
- import type { ServiceKey } from './serviceKey';
3
- /**
4
- * The placeholder that replaces a redacted value when no custom
5
- * transform is given for it.
6
- */
7
- export declare const REDACTED_VALUE = "[REDACTED]";
8
- /**
9
- * Custom masking for one included property, narrowed to the exact
10
- * method named when {@link RedactionRuleBuilder.redact} is called.
11
- * Omitting a side fully blanks it with {@link REDACTED_VALUE}; providing
12
- * one lets you report a partial mask instead (e.g. the last 4 digits of
13
- * a card number) — both always return a `string`, the masked
14
- * representation to report in place of the real value.
15
- */
16
- export type Mask<T, K extends Extract<keyof T, string>> = T[K] extends (...args: infer A) => infer R ? {
17
- maskArgs?: (...args: A) => string;
18
- maskResult?: (result: R) => string;
19
- } : never;
20
- /**
21
- * Marks a service — or specific properties of it — as sensitive, so the
22
- * values flowing through its events are redacted. Returned by
23
- * {@link RedactionRuleBuilder.build}, which is the only way to construct
24
- * one — the `redactAll`/per-property merge logic lives entirely inside
25
- * `maskArgs`/`maskResult`, so callers never need to know how a rule
26
- * reached its decision, only what to do with it.
27
- */
28
- export interface RedactionRule<T> {
29
- readonly key: ServiceKey<T>;
30
- /**
31
- * The args to report for a call to `functionName`: unchanged if not
32
- * redacted, otherwise blanked or run through a custom `maskArgs`.
33
- */
34
- maskArgs(functionName: string, args: readonly unknown[]): readonly unknown[];
35
- /**
36
- * The value to report for a success outcome: unchanged if not
37
- * redacted, otherwise blanked or run through a custom `maskResult`.
38
- * Omit `functionName` to ask about the initialize result (the service
39
- * instance itself), which only the rule's `redactAll` default touches.
40
- */
41
- maskResult(functionName: string | undefined, result: unknown): unknown;
42
- }
43
- /**
44
- * Fluent, single-key rule builder returned by {@link redactionRule}.
45
- * `redactAll`, `redact`, and `exclude` all merge into the same rule —
46
- * call them in any combination, in any order; the more specific
47
- * per-property calls (`redact`/`exclude`) always win over the blanket
48
- * `redactAll` default for the properties they name.
49
- *
50
- * @example
51
- * ```ts
52
- * const rules = [
53
- * redactionRule(SecretClientKey)
54
- * .redactAll()
55
- * .build(), // whole service is sensitive
56
- * redactionRule(BillingKey)
57
- * .redactAll()
58
- * .redact('chargeCard', { maskResult: (card) => `card ending in ${card.number.slice(-4)}` })
59
- * .exclude('ping') // redact everything except this, with one custom mask
60
- * .build(),
61
- * redactionRule(VaultKey)
62
- * .redact('getSecret')
63
- * .build(), // only this call, nothing else
64
- * ];
65
- * ```
66
- */
67
- export declare class RedactionRuleBuilder<T> {
68
- private readonly key;
69
- private redactAllFlag;
70
- private readonly overrides;
71
- constructor(key: ServiceKey<T>);
72
- /** Redacts every property, plus the initialize result, by default. */
73
- redactAll(): this;
74
- /**
75
- * Marks one property (method) as redacted, with optional custom
76
- * masking. Call repeatedly for several properties. Overrides
77
- * `redactAll`/`exclude` for this specific property.
78
- */
79
- redact<K extends Extract<keyof T, string>>(name: K, mask?: Mask<T, K>): this;
80
- /**
81
- * Marks one or more properties as explicitly NOT redacted, overriding
82
- * `redactAll` for just these.
83
- */
84
- exclude(...names: Extract<keyof T, string>[]): this;
85
- build(): RedactionRule<any>;
86
- }
87
- export declare function redactionRule<T>(key: ServiceKey<T>): RedactionRuleBuilder<T>;
88
- /**
89
- * A ServiceEventListener decorator that redacts sensitive values before
90
- * they reach the wrapped listener. Works with any implementation via
91
- * delegation: arguments in MethodCallContext and success values in
92
- * EventOutcome are replaced (wholesale, or via a custom transform)
93
- * before the delegate ever sees them — whatever it captures or exports
94
- * is already scrubbed.
95
- *
96
- * Failure outcomes are passed through unchanged so error reporting keeps
97
- * working; keep secrets out of error messages at the throwing site.
98
- *
99
- * @example
100
- * ```ts
101
- * const listener = new RedactingEventListener(
102
- * new OTELEventListener({ captureArguments: true, captureResults: true }),
103
- * [
104
- * redactionRule(SecretClientKey).redactAll().build(), // whole service is sensitive
105
- * redactionRule(VaultKey).redact('getSecret').build(), // only this call
106
- * redactionRule(HealthKey).redactAll().exclude('ping').build(), // everything but this call
107
- * ],
108
- * );
109
- * ```
110
- */
111
- export declare class RedactingEventListener implements ServiceModuleListener {
112
- private readonly delegate;
113
- private readonly rules;
114
- constructor(delegate: ServiceModuleListener, rules: readonly RedactionRule<any>[]);
115
- onInitialize(context: InitializeContext): EventSpan | void;
116
- onDispose(context: DisposeContext): EventSpan | void;
117
- onMethodCall(context: MethodCallContext): EventSpan | void;
118
- }
119
- //# sourceMappingURL=redactingEventListener.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redactingEventListener.d.ts","sourceRoot":"","sources":["../src/redactingEventListener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CACrE,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,MAAM,CAAC,GACR;IACE,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;CACpC,GACD,KAAK,CAAC;AAeV;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,OAAO,EAAE,CAAC;IAE7E;;;;;OAKG;IACH,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;CACxE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,oBAAoB,CAAC,CAAC;IAIrB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAHhC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;gBAErC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC;IAE/C,sEAAsE;IACtE,SAAS,IAAI,IAAI;IAKjB;;;;OAIG;IACH,MAAM,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IAK5E;;;OAGG;IACH,OAAO,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI;IAOnD,KAAK,IAAI,aAAa,CAAC,GAAG,CAAC;CAwC5B;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAE5E;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,sBAAuB,YAAW,qBAAqB;IAEhE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,QAAQ,EAAE,qBAAqB,EAC/B,KAAK,EAAE,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE;IAGvD,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,IAAI;IAK1D,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI;IAKpD,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,IAAI;CAY3D"}
@@ -1,169 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RedactingEventListener = exports.RedactionRuleBuilder = exports.REDACTED_VALUE = void 0;
4
- exports.redactionRule = redactionRule;
5
- /**
6
- * The placeholder that replaces a redacted value when no custom
7
- * transform is given for it.
8
- */
9
- exports.REDACTED_VALUE = '[REDACTED]';
10
- /**
11
- * Fluent, single-key rule builder returned by {@link redactionRule}.
12
- * `redactAll`, `redact`, and `exclude` all merge into the same rule —
13
- * call them in any combination, in any order; the more specific
14
- * per-property calls (`redact`/`exclude`) always win over the blanket
15
- * `redactAll` default for the properties they name.
16
- *
17
- * @example
18
- * ```ts
19
- * const rules = [
20
- * redactionRule(SecretClientKey)
21
- * .redactAll()
22
- * .build(), // whole service is sensitive
23
- * redactionRule(BillingKey)
24
- * .redactAll()
25
- * .redact('chargeCard', { maskResult: (card) => `card ending in ${card.number.slice(-4)}` })
26
- * .exclude('ping') // redact everything except this, with one custom mask
27
- * .build(),
28
- * redactionRule(VaultKey)
29
- * .redact('getSecret')
30
- * .build(), // only this call, nothing else
31
- * ];
32
- * ```
33
- */
34
- class RedactionRuleBuilder {
35
- constructor(key) {
36
- this.key = key;
37
- this.redactAllFlag = false;
38
- this.overrides = {};
39
- }
40
- /** Redacts every property, plus the initialize result, by default. */
41
- redactAll() {
42
- this.redactAllFlag = true;
43
- return this;
44
- }
45
- /**
46
- * Marks one property (method) as redacted, with optional custom
47
- * masking. Call repeatedly for several properties. Overrides
48
- * `redactAll`/`exclude` for this specific property.
49
- */
50
- redact(name, mask) {
51
- this.overrides[name] = Object.assign({ redacted: true }, mask);
52
- return this;
53
- }
54
- /**
55
- * Marks one or more properties as explicitly NOT redacted, overriding
56
- * `redactAll` for just these.
57
- */
58
- exclude(...names) {
59
- for (const name of names) {
60
- this.overrides[name] = { redacted: false };
61
- }
62
- return this;
63
- }
64
- build() {
65
- if (!this.redactAllFlag && Object.keys(this.overrides).length === 0) {
66
- throw new Error(`redactionRule(${this.key.name}) has no effect: call .redactAll() and/or .redact(...) ` +
67
- 'before .build(), otherwise this rule never redacts anything.');
68
- }
69
- const redactAllFlag = this.redactAllFlag;
70
- const overrides = this.overrides;
71
- return {
72
- key: this.key,
73
- maskArgs(functionName, args) {
74
- const override = overrides[functionName];
75
- const redacted = override ? override.redacted : redactAllFlag;
76
- if (!redacted) {
77
- return args;
78
- }
79
- return (override === null || override === void 0 ? void 0 : override.maskArgs)
80
- ? // A custom mask reports one string for the whole call,
81
- // rather than a value per argument.
82
- [override.maskArgs(...args)]
83
- : // Replace each argument rather than the whole array, so the
84
- // delegate still sees the call's arity.
85
- args.map(() => exports.REDACTED_VALUE);
86
- },
87
- maskResult(functionName, result) {
88
- const override = functionName === undefined ? undefined : overrides[functionName];
89
- const redacted = override ? override.redacted : redactAllFlag;
90
- if (!redacted) {
91
- return result;
92
- }
93
- return (override === null || override === void 0 ? void 0 : override.maskResult)
94
- ? override.maskResult(result)
95
- : exports.REDACTED_VALUE;
96
- },
97
- };
98
- }
99
- }
100
- exports.RedactionRuleBuilder = RedactionRuleBuilder;
101
- function redactionRule(key) {
102
- return new RedactionRuleBuilder(key);
103
- }
104
- /**
105
- * A ServiceEventListener decorator that redacts sensitive values before
106
- * they reach the wrapped listener. Works with any implementation via
107
- * delegation: arguments in MethodCallContext and success values in
108
- * EventOutcome are replaced (wholesale, or via a custom transform)
109
- * before the delegate ever sees them — whatever it captures or exports
110
- * is already scrubbed.
111
- *
112
- * Failure outcomes are passed through unchanged so error reporting keeps
113
- * working; keep secrets out of error messages at the throwing site.
114
- *
115
- * @example
116
- * ```ts
117
- * const listener = new RedactingEventListener(
118
- * new OTELEventListener({ captureArguments: true, captureResults: true }),
119
- * [
120
- * redactionRule(SecretClientKey).redactAll().build(), // whole service is sensitive
121
- * redactionRule(VaultKey).redact('getSecret').build(), // only this call
122
- * redactionRule(HealthKey).redactAll().exclude('ping').build(), // everything but this call
123
- * ],
124
- * );
125
- * ```
126
- */
127
- class RedactingEventListener {
128
- constructor(delegate, rules) {
129
- this.delegate = delegate;
130
- this.rules = rules;
131
- }
132
- onInitialize(context) {
133
- var _a, _b;
134
- const rule = this.rules.find((r) => r.key === context.key);
135
- return redactSpan((_b = (_a = this.delegate).onInitialize) === null || _b === void 0 ? void 0 : _b.call(_a, context), rule);
136
- }
137
- onDispose(context) {
138
- var _a, _b;
139
- // Dispose carries no arguments and no result value; nothing to redact.
140
- return (_b = (_a = this.delegate).onDispose) === null || _b === void 0 ? void 0 : _b.call(_a, context);
141
- }
142
- onMethodCall(context) {
143
- var _a, _b;
144
- const rule = this.rules.find((r) => r.key === context.key);
145
- const span = (_b = (_a = this.delegate).onMethodCall) === null || _b === void 0 ? void 0 : _b.call(_a, rule
146
- ? Object.assign(Object.assign({}, context), { args: rule.maskArgs(context.functionName, context.args) }) : context);
147
- return redactSpan(span, rule, context.functionName);
148
- }
149
- }
150
- exports.RedactingEventListener = RedactingEventListener;
151
- /**
152
- * Wraps the delegate's EventSpan so success values are redacted before
153
- * `end` sees them, by delegating to the rule's `maskResult`. `run` (and
154
- * any future fields) pass through untouched. `functionName` is omitted
155
- * for the initialize result (the instance itself).
156
- */
157
- function redactSpan(span, rule, functionName) {
158
- if (!rule || !(span === null || span === void 0 ? void 0 : span.end)) {
159
- return span;
160
- }
161
- const end = span.end.bind(span);
162
- return Object.assign(Object.assign({}, span), { end: (outcome) => end(outcome.type === 'success'
163
- ? {
164
- type: 'success',
165
- value: rule.maskResult(functionName, outcome.value),
166
- }
167
- : outcome) });
168
- }
169
- //# sourceMappingURL=redactingEventListener.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redactingEventListener.js","sourceRoot":"","sources":["../src/redactingEventListener.ts"],"names":[],"mappings":"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"}