@fulmenhq/tsfulmen 0.3.3 → 0.4.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/README.md +30 -1
  3. package/config/crucible-ts/taxonomy/metrics.yaml +1 -1
  4. package/dist/appidentity/index.js +9 -2209
  5. package/dist/appidentity/index.js.map +1 -1
  6. package/dist/assets/index.d.ts +179 -0
  7. package/dist/assets/index.js +4 -0
  8. package/dist/assets/index.js.map +1 -0
  9. package/dist/bin/prometheus-cli.js +15 -9139
  10. package/dist/bin/prometheus-cli.js.map +1 -1
  11. package/dist/bin/schema-cli.js +4 -6098
  12. package/dist/bin/schema-cli.js.map +1 -1
  13. package/dist/bin/signals-cli.js +15 -1910
  14. package/dist/bin/signals-cli.js.map +1 -1
  15. package/dist/chunk-3HISR2XI.js +36 -0
  16. package/dist/chunk-3HISR2XI.js.map +1 -0
  17. package/dist/chunk-5HZEJGZ5.js +725 -0
  18. package/dist/chunk-5HZEJGZ5.js.map +1 -0
  19. package/dist/chunk-7SVYOPJ3.js +9412 -0
  20. package/dist/chunk-7SVYOPJ3.js.map +1 -0
  21. package/dist/chunk-BCO3FUUO.js +682 -0
  22. package/dist/chunk-BCO3FUUO.js.map +1 -0
  23. package/dist/chunk-BJDL6JEX.js +208 -0
  24. package/dist/chunk-BJDL6JEX.js.map +1 -0
  25. package/dist/chunk-BTUS6PZZ.js +302 -0
  26. package/dist/chunk-BTUS6PZZ.js.map +1 -0
  27. package/dist/chunk-CW4CSNVF.js +410 -0
  28. package/dist/chunk-CW4CSNVF.js.map +1 -0
  29. package/dist/chunk-HIBZ2AY7.js +194 -0
  30. package/dist/chunk-HIBZ2AY7.js.map +1 -0
  31. package/dist/chunk-HS4F3BRR.js +985 -0
  32. package/dist/chunk-HS4F3BRR.js.map +1 -0
  33. package/dist/chunk-HY6JQOFN.js +32 -0
  34. package/dist/chunk-HY6JQOFN.js.map +1 -0
  35. package/dist/chunk-K2FYT43R.js +837 -0
  36. package/dist/chunk-K2FYT43R.js.map +1 -0
  37. package/dist/chunk-K7BMFGQP.js +43 -0
  38. package/dist/chunk-K7BMFGQP.js.map +1 -0
  39. package/dist/chunk-LWAH2UG7.js +103 -0
  40. package/dist/chunk-LWAH2UG7.js.map +1 -0
  41. package/dist/chunk-OHE2AOH4.js +273 -0
  42. package/dist/chunk-OHE2AOH4.js.map +1 -0
  43. package/dist/chunk-P3DNOZOG.js +1488 -0
  44. package/dist/chunk-P3DNOZOG.js.map +1 -0
  45. package/dist/chunk-PQ6TKPUN.js +27 -0
  46. package/dist/chunk-PQ6TKPUN.js.map +1 -0
  47. package/dist/chunk-QCCN6POA.js +211 -0
  48. package/dist/chunk-QCCN6POA.js.map +1 -0
  49. package/dist/chunk-RSLFR4TO.js +631 -0
  50. package/dist/chunk-RSLFR4TO.js.map +1 -0
  51. package/dist/chunk-UP2VWCW5.js +33 -0
  52. package/dist/chunk-UP2VWCW5.js.map +1 -0
  53. package/dist/chunk-W6TQFTTY.js +130 -0
  54. package/dist/chunk-W6TQFTTY.js.map +1 -0
  55. package/dist/chunk-WSMVLWLB.js +269 -0
  56. package/dist/chunk-WSMVLWLB.js.map +1 -0
  57. package/dist/config/index.js +6 -1220
  58. package/dist/config/index.js.map +1 -1
  59. package/dist/crucible/fulpack/index.js +2 -25
  60. package/dist/crucible/fulpack/index.js.map +1 -1
  61. package/dist/crucible/index.js +13 -1129
  62. package/dist/crucible/index.js.map +1 -1
  63. package/dist/docscribe/index.js +2 -680
  64. package/dist/docscribe/index.js.map +1 -1
  65. package/dist/errors/index.js +5 -1831
  66. package/dist/errors/index.js.map +1 -1
  67. package/dist/errors-D7KXV3QW.js +4 -0
  68. package/dist/errors-D7KXV3QW.js.map +1 -0
  69. package/dist/errors-RBJX6ETJ.js +8 -0
  70. package/dist/errors-RBJX6ETJ.js.map +1 -0
  71. package/dist/export-BWRETGYS.js +6 -0
  72. package/dist/export-BWRETGYS.js.map +1 -0
  73. package/dist/foundry/index.js +340 -3949
  74. package/dist/foundry/index.js.map +1 -1
  75. package/dist/foundry/similarity/index.js +3 -134
  76. package/dist/foundry/similarity/index.js.map +1 -1
  77. package/dist/fulencode/index.js +3 -319
  78. package/dist/fulencode/index.js.map +1 -1
  79. package/dist/fulhash/index.js +3 -611
  80. package/dist/fulhash/index.js.map +1 -1
  81. package/dist/fulpack/index.js +3 -1515
  82. package/dist/fulpack/index.js.map +1 -1
  83. package/dist/hash-YOJYVOWH.js +4 -0
  84. package/dist/hash-YOJYVOWH.js.map +1 -0
  85. package/dist/index.d.ts +1 -1
  86. package/dist/index.js +14 -4395
  87. package/dist/index.js.map +1 -1
  88. package/dist/loader-H5K7HSO5.js +9 -0
  89. package/dist/loader-H5K7HSO5.js.map +1 -0
  90. package/dist/logging/index.js +2 -723
  91. package/dist/logging/index.js.map +1 -1
  92. package/dist/pathfinder/index.js +18 -2341
  93. package/dist/pathfinder/index.js.map +1 -1
  94. package/dist/prom-client-PNEBGD3G.js +4801 -0
  95. package/dist/prom-client-PNEBGD3G.js.map +1 -0
  96. package/dist/reports/license-inventory.csv +1 -1
  97. package/dist/schema/index.d.ts +19 -6
  98. package/dist/schema/index.js +4 -6148
  99. package/dist/schema/index.js.map +1 -1
  100. package/dist/signals/index.js +8 -2767
  101. package/dist/signals/index.js.map +1 -1
  102. package/dist/similarity/index.js +3 -134
  103. package/dist/similarity/index.js.map +1 -1
  104. package/dist/telemetry/http/index.js +9 -930
  105. package/dist/telemetry/http/index.js.map +1 -1
  106. package/dist/telemetry/index.js +4 -1561
  107. package/dist/telemetry/index.js.map +1 -1
  108. package/dist/telemetry/prometheus/index.js +7 -8422
  109. package/dist/telemetry/prometheus/index.js.map +1 -1
  110. package/dist/validator-U4CKD2Y3.js +6 -0
  111. package/dist/validator-U4CKD2Y3.js.map +1 -0
  112. package/package.json +5 -1
  113. package/schemas/crucible-ts/library/module-manifest/v1.0.0/module-manifest.schema.json +1 -1
  114. package/schemas/crucible-ts/observability/logging/v1.0.0/definitions.schema.json +1 -1
  115. package/schemas/crucible-ts/observability/logging/v1.0.0/log-event.schema.json +13 -13
  116. package/schemas/crucible-ts/observability/logging/v1.0.0/logger-config.schema.json +2 -2
  117. package/schemas/crucible-ts/observability/logging/v1.0.0/logging-policy.schema.json +1 -1
  118. package/schemas/crucible-ts/observability/logging/v1.0.0/middleware-config.schema.json +2 -2
  119. package/schemas/crucible-ts/observability/logging/v1.0.0/severity-filter.schema.json +3 -3
  120. package/schemas/crucible-ts/upstream/3leaps/crucible/PROVENANCE.md +3 -3
  121. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/catalog/classifiers/README.md +1 -1
  122. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/classifiers-framework.md +1 -1
  123. package/schemas/crucible-ts/upstream/3leaps/crucible/docs/standards/data-sensitivity-classification.md +1 -1
@@ -0,0 +1,725 @@
1
+ import { hostname } from 'os';
2
+ import pino from 'pino';
3
+ import { readFileSync, appendFileSync } from 'fs';
4
+ import { parse } from 'yaml';
5
+
6
+ // src/logging/logger.ts
7
+
8
+ // src/logging/types.ts
9
+ var LoggingProfile = /* @__PURE__ */ ((LoggingProfile2) => {
10
+ LoggingProfile2["SIMPLE"] = "simple";
11
+ LoggingProfile2["STRUCTURED"] = "structured";
12
+ LoggingProfile2["ENTERPRISE"] = "enterprise";
13
+ LoggingProfile2["CUSTOM"] = "custom";
14
+ return LoggingProfile2;
15
+ })(LoggingProfile || {});
16
+ var PolicyError = class extends Error {
17
+ constructor(message) {
18
+ super(message);
19
+ this.name = "PolicyError";
20
+ }
21
+ };
22
+
23
+ // src/logging/policy.ts
24
+ var PolicyEnforcer = class {
25
+ policy;
26
+ policyFile;
27
+ /**
28
+ * Create a new policy enforcer
29
+ *
30
+ * @param policyFile - Path to YAML policy file
31
+ * @throws {PolicyError} If policy file cannot be loaded or is invalid
32
+ */
33
+ constructor(policyFile) {
34
+ this.policyFile = policyFile;
35
+ this.policy = this.loadPolicy(policyFile);
36
+ }
37
+ /**
38
+ * Validate if a profile is allowed under the current policy
39
+ *
40
+ * @param profile - The logging profile to validate
41
+ * @param options - Optional validation context (appType, environment)
42
+ * @returns true if profile is allowed, false otherwise
43
+ *
44
+ * @example
45
+ * const enforcer = new PolicyEnforcer('/org/logging-policy.yaml');
46
+ * if (enforcer.validateProfile(LoggingProfile.ENTERPRISE, { environment: 'production' })) {
47
+ * // Profile is allowed
48
+ * }
49
+ */
50
+ validateProfile(profile, options) {
51
+ if (!this.policy.allowedProfiles.includes(profile)) {
52
+ return false;
53
+ }
54
+ if (options?.environment && this.policy.environmentRules) {
55
+ const envRules = this.policy.environmentRules[options.environment];
56
+ if (envRules && !envRules.includes(profile)) {
57
+ return false;
58
+ }
59
+ }
60
+ if (options?.appType && this.policy.requiredProfiles) {
61
+ const appTypeRules = this.policy.requiredProfiles[options.appType];
62
+ if (appTypeRules && !appTypeRules.includes(profile)) {
63
+ return false;
64
+ }
65
+ }
66
+ return true;
67
+ }
68
+ /**
69
+ * Get the required profile for a given app type and environment
70
+ *
71
+ * @param appType - The application type
72
+ * @param environment - The deployment environment
73
+ * @returns The required logging profile
74
+ * @throws {PolicyError} If no required profile found for app type
75
+ *
76
+ * @example
77
+ * const enforcer = new PolicyEnforcer('/org/logging-policy.yaml');
78
+ * const profile = enforcer.getRequiredProfile('api-server', 'production');
79
+ * // Returns LoggingProfile.ENTERPRISE
80
+ */
81
+ getRequiredProfile(appType, environment) {
82
+ if (this.policy.requiredProfiles?.[appType]) {
83
+ const profiles = this.policy.requiredProfiles[appType];
84
+ if (this.policy.environmentRules?.[environment]) {
85
+ const envProfiles = this.policy.environmentRules[environment];
86
+ const validProfiles = profiles.filter((p) => envProfiles.includes(p));
87
+ if (validProfiles.length > 0) {
88
+ return this.getMostRestrictiveProfile(validProfiles);
89
+ }
90
+ }
91
+ return this.getMostRestrictiveProfile(profiles);
92
+ }
93
+ throw new PolicyError(
94
+ `No required profile found for app type "${appType}" in policy ${this.policyFile}`
95
+ );
96
+ }
97
+ /**
98
+ * Get a helpful error message for policy validation failure
99
+ *
100
+ * @param profile - The profile that failed validation
101
+ * @param options - The validation options used
102
+ * @returns A descriptive error message
103
+ */
104
+ getValidationErrorMessage(profile, options) {
105
+ const parts = [`Profile "${profile}" not allowed by policy "${this.policyFile}".`];
106
+ if (options?.environment) {
107
+ parts.push(`Environment: ${options.environment}`);
108
+ }
109
+ if (options?.appType) {
110
+ parts.push(`App Type: ${options.appType}`);
111
+ }
112
+ parts.push(`Allowed profiles: ${this.policy.allowedProfiles.join(", ")}`);
113
+ if (options?.environment && this.policy.environmentRules?.[options.environment]) {
114
+ const envProfiles = this.policy.environmentRules[options.environment];
115
+ parts.push(`Environment "${options.environment}" allows: ${envProfiles.join(", ")}`);
116
+ }
117
+ if (options?.appType && this.policy.requiredProfiles?.[options.appType]) {
118
+ const appProfiles = this.policy.requiredProfiles[options.appType];
119
+ parts.push(`App type "${options.appType}" requires: ${appProfiles.join(", ")}`);
120
+ }
121
+ return parts.join(" | ");
122
+ }
123
+ /**
124
+ * Load and parse the policy file
125
+ *
126
+ * @param policyFile - Path to YAML policy file
127
+ * @returns Parsed logging policy
128
+ * @throws {PolicyError} If file cannot be read or parsed
129
+ */
130
+ loadPolicy(policyFile) {
131
+ try {
132
+ const content = readFileSync(policyFile, "utf-8");
133
+ const parsed = parse(content);
134
+ if (!parsed.allowedProfiles || !Array.isArray(parsed.allowedProfiles)) {
135
+ throw new PolicyError(
136
+ `Invalid policy file ${policyFile}: missing or invalid "allowedProfiles" field`
137
+ );
138
+ }
139
+ const validProfiles = Object.values(LoggingProfile);
140
+ for (const profile of parsed.allowedProfiles) {
141
+ if (!validProfiles.includes(profile)) {
142
+ throw new PolicyError(`Invalid policy file ${policyFile}: unknown profile "${profile}"`);
143
+ }
144
+ }
145
+ if (parsed.requiredProfiles) {
146
+ if (typeof parsed.requiredProfiles !== "object") {
147
+ throw new PolicyError(
148
+ `Invalid policy file ${policyFile}: "requiredProfiles" must be an object`
149
+ );
150
+ }
151
+ for (const [appType, profiles] of Object.entries(parsed.requiredProfiles)) {
152
+ if (!Array.isArray(profiles)) {
153
+ throw new PolicyError(
154
+ `Invalid policy file ${policyFile}: requiredProfiles["${appType}"] must be an array, got ${typeof profiles}. Check YAML formatting - each profile should be on a new line with a hyphen.`
155
+ );
156
+ }
157
+ for (const profile of profiles) {
158
+ if (!validProfiles.includes(profile)) {
159
+ throw new PolicyError(
160
+ `Invalid policy file ${policyFile}: requiredProfiles["${appType}"] contains unknown profile "${profile}"`
161
+ );
162
+ }
163
+ }
164
+ }
165
+ }
166
+ if (parsed.environmentRules) {
167
+ if (typeof parsed.environmentRules !== "object") {
168
+ throw new PolicyError(
169
+ `Invalid policy file ${policyFile}: "environmentRules" must be an object`
170
+ );
171
+ }
172
+ for (const [environment, profiles] of Object.entries(parsed.environmentRules)) {
173
+ if (!Array.isArray(profiles)) {
174
+ throw new PolicyError(
175
+ `Invalid policy file ${policyFile}: environmentRules["${environment}"] must be an array, got ${typeof profiles}. Check YAML formatting - each profile should be on a new line with a hyphen.`
176
+ );
177
+ }
178
+ for (const profile of profiles) {
179
+ if (!validProfiles.includes(profile)) {
180
+ throw new PolicyError(
181
+ `Invalid policy file ${policyFile}: environmentRules["${environment}"] contains unknown profile "${profile}"`
182
+ );
183
+ }
184
+ }
185
+ }
186
+ }
187
+ return parsed;
188
+ } catch (error) {
189
+ if (error instanceof PolicyError) {
190
+ throw error;
191
+ }
192
+ if (error.code === "ENOENT") {
193
+ throw new PolicyError(`Policy file not found: ${policyFile}`);
194
+ }
195
+ throw new PolicyError(
196
+ `Failed to load policy file ${policyFile}: ${error.message}`
197
+ );
198
+ }
199
+ }
200
+ /**
201
+ * Get the most restrictive profile from a list
202
+ * Order: CUSTOM > ENTERPRISE > STRUCTURED > SIMPLE
203
+ *
204
+ * @param profiles - List of profiles
205
+ * @returns The most restrictive profile
206
+ */
207
+ getMostRestrictiveProfile(profiles) {
208
+ const order = [
209
+ "custom" /* CUSTOM */,
210
+ "enterprise" /* ENTERPRISE */,
211
+ "structured" /* STRUCTURED */,
212
+ "simple" /* SIMPLE */
213
+ ];
214
+ for (const profile of order) {
215
+ if (profiles.includes(profile)) {
216
+ return profile;
217
+ }
218
+ }
219
+ return profiles[0];
220
+ }
221
+ };
222
+ var ConsoleSink = class {
223
+ write(event) {
224
+ console.log(JSON.stringify(event));
225
+ }
226
+ };
227
+ var FileSink = class {
228
+ constructor(filePath) {
229
+ this.filePath = filePath;
230
+ }
231
+ write(event) {
232
+ try {
233
+ appendFileSync(this.filePath, `${JSON.stringify(event)}
234
+ `);
235
+ } catch (error) {
236
+ console.error(`FileSink: Failed to write to ${this.filePath}:`, error.message);
237
+ console.log(JSON.stringify(event));
238
+ }
239
+ }
240
+ };
241
+ var NullSink = class {
242
+ write(_event) {
243
+ }
244
+ };
245
+
246
+ // src/logging/logger.ts
247
+ var Logger = class {
248
+ service;
249
+ profile;
250
+ impl;
251
+ constructor(config) {
252
+ this.service = config.service;
253
+ this.profile = config.profile;
254
+ if (config.policyFile) {
255
+ this.validatePolicy(config.profile, config.policyFile);
256
+ }
257
+ this.impl = this.createImplementation(config);
258
+ }
259
+ debug(message, context) {
260
+ this.impl.debug(message, context);
261
+ }
262
+ info(message, context) {
263
+ this.impl.info(message, context);
264
+ }
265
+ warn(message, context) {
266
+ this.impl.warn(message, context);
267
+ }
268
+ error(message, error, context) {
269
+ this.impl.error(message, error, context);
270
+ }
271
+ child(bindings) {
272
+ const childLogger = Object.create(this);
273
+ childLogger.impl = this.impl.child(bindings);
274
+ return childLogger;
275
+ }
276
+ validatePolicy(profile, policyFile) {
277
+ const enforcer = new PolicyEnforcer(policyFile);
278
+ const appType = process.env.APP_TYPE;
279
+ const environment = process.env.NODE_ENV;
280
+ if (!enforcer.validateProfile(profile, { appType, environment })) {
281
+ throw new PolicyError(enforcer.getValidationErrorMessage(profile, { appType, environment }));
282
+ }
283
+ }
284
+ createImplementation(config) {
285
+ switch (config.profile) {
286
+ case "simple" /* SIMPLE */:
287
+ return new SimpleLogger(config.service);
288
+ case "structured" /* STRUCTURED */: {
289
+ const structuredConfig = config;
290
+ return new StructuredLogger(
291
+ structuredConfig.service,
292
+ structuredConfig.filePath,
293
+ structuredConfig.middleware
294
+ );
295
+ }
296
+ case "enterprise" /* ENTERPRISE */:
297
+ return new EnterpriseLogger(config.service, {
298
+ // biome-ignore lint/suspicious/noExplicitAny: Phase 1 - proper discriminated union handling in Phase 2
299
+ sinks: config.sinks,
300
+ // biome-ignore lint/suspicious/noExplicitAny: Phase 1 - proper discriminated union handling in Phase 2
301
+ middleware: config.middleware
302
+ });
303
+ case "custom" /* CUSTOM */:
304
+ return new EnterpriseLogger(config.service, config.customConfig);
305
+ }
306
+ }
307
+ };
308
+ var SimpleLogger = class {
309
+ constructor(service) {
310
+ this.service = service;
311
+ this.pino = pino({
312
+ name: service,
313
+ level: "debug",
314
+ messageKey: "message",
315
+ base: void 0,
316
+ timestamp: false,
317
+ formatters: {
318
+ level: (label) => ({ severity: label.toUpperCase() }),
319
+ // biome-ignore lint/suspicious/noExplicitAny: Pino formatter requires any type
320
+ log: (object) => {
321
+ return {
322
+ service: this.service,
323
+ ...object
324
+ };
325
+ }
326
+ }
327
+ });
328
+ }
329
+ pino;
330
+ debug(message, context) {
331
+ this.pino.debug(context, message);
332
+ }
333
+ info(message, context) {
334
+ this.pino.info(context, message);
335
+ }
336
+ warn(message, context) {
337
+ this.pino.warn(context, message);
338
+ }
339
+ error(message, error, context) {
340
+ const errorContext = {
341
+ ...context,
342
+ ...error && { error: error.message, stack: error.stack }
343
+ };
344
+ this.pino.error(errorContext, message);
345
+ }
346
+ child(bindings) {
347
+ const childPino = this.pino.child(bindings);
348
+ const childLogger = Object.create(this);
349
+ childLogger.pino = childPino;
350
+ return childLogger;
351
+ }
352
+ };
353
+ var StructuredLogger = class _StructuredLogger {
354
+ constructor(service, filePath, middleware, bindings, existingPino) {
355
+ this.service = service;
356
+ this.filePath = filePath;
357
+ this.middleware = middleware ?? [];
358
+ this.bindings = bindings ?? {};
359
+ const config = {
360
+ name: service,
361
+ level: "debug",
362
+ messageKey: "message",
363
+ base: void 0,
364
+ timestamp: () => `,"timestamp":"${(/* @__PURE__ */ new Date()).toISOString()}"`,
365
+ formatters: {
366
+ level: (label) => ({ severity: label.toUpperCase() }),
367
+ // biome-ignore lint/suspicious/noExplicitAny: Pino formatter requires any type
368
+ log: (object) => {
369
+ return {
370
+ service: this.service,
371
+ ...object
372
+ };
373
+ }
374
+ }
375
+ };
376
+ this.pino = existingPino ?? (filePath ? pino(
377
+ config,
378
+ pino.multistream([{ stream: process.stdout }, { stream: pino.destination(filePath) }])
379
+ ) : pino(config));
380
+ }
381
+ pino;
382
+ middleware;
383
+ bindings;
384
+ debug(message, context) {
385
+ if (this.middleware.length > 0) {
386
+ this.logWithMiddleware("DEBUG", message, context);
387
+ } else {
388
+ this.pino.debug(context, message);
389
+ }
390
+ }
391
+ info(message, context) {
392
+ if (this.middleware.length > 0) {
393
+ this.logWithMiddleware("INFO", message, context);
394
+ } else {
395
+ this.pino.info(context, message);
396
+ }
397
+ }
398
+ warn(message, context) {
399
+ if (this.middleware.length > 0) {
400
+ this.logWithMiddleware("WARN", message, context);
401
+ } else {
402
+ this.pino.warn(context, message);
403
+ }
404
+ }
405
+ error(message, error, context) {
406
+ const errorContext = {
407
+ ...context,
408
+ ...error && { error: error.message, stack: error.stack }
409
+ };
410
+ if (this.middleware.length > 0) {
411
+ this.logWithMiddleware("ERROR", message, errorContext);
412
+ } else {
413
+ this.pino.error(errorContext, message);
414
+ }
415
+ }
416
+ logWithMiddleware(severity, message, context) {
417
+ let event = {
418
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
419
+ service: this.service,
420
+ severity,
421
+ message,
422
+ ...this.bindings,
423
+ ...context
424
+ };
425
+ for (const mw of this.middleware) {
426
+ event = mw.process(event);
427
+ }
428
+ const { message: finalMessage, severity: finalSeverity, ...finalContext } = event;
429
+ const level = (finalSeverity || severity).toLowerCase();
430
+ switch (level) {
431
+ case "debug":
432
+ this.pino.debug(finalContext, finalMessage);
433
+ break;
434
+ case "info":
435
+ this.pino.info(finalContext, finalMessage);
436
+ break;
437
+ case "warn":
438
+ this.pino.warn(finalContext, finalMessage);
439
+ break;
440
+ case "error":
441
+ this.pino.error(finalContext, finalMessage);
442
+ break;
443
+ default:
444
+ this.pino.info(finalContext, finalMessage);
445
+ }
446
+ }
447
+ child(bindings) {
448
+ const mergedBindings = { ...this.bindings, ...bindings };
449
+ const childPino = this.pino.child(bindings);
450
+ return new _StructuredLogger(
451
+ this.service,
452
+ this.filePath,
453
+ this.middleware,
454
+ mergedBindings,
455
+ childPino
456
+ );
457
+ }
458
+ };
459
+ var EnterpriseLogger = class _EnterpriseLogger {
460
+ constructor(service, config, bindings) {
461
+ this.service = service;
462
+ this.sinks = config?.sinks ?? [new ConsoleSink()];
463
+ this.middleware = config?.middleware ?? [];
464
+ this.bindings = bindings ?? {};
465
+ }
466
+ sinks;
467
+ middleware;
468
+ bindings;
469
+ debug(message, context) {
470
+ this.logWithPipeline("DEBUG", message, context);
471
+ }
472
+ info(message, context) {
473
+ this.logWithPipeline("INFO", message, context);
474
+ }
475
+ warn(message, context) {
476
+ this.logWithPipeline("WARN", message, context);
477
+ }
478
+ error(message, error, context) {
479
+ const errorContext = {
480
+ ...context,
481
+ ...error && {
482
+ error: error.message,
483
+ stack: error.stack,
484
+ errorType: error.constructor.name
485
+ }
486
+ };
487
+ this.logWithPipeline("ERROR", message, errorContext);
488
+ }
489
+ logWithPipeline(severity, message, context) {
490
+ let event = {
491
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
492
+ service: this.service,
493
+ severity,
494
+ message,
495
+ correlationId: context?.correlationId ?? this.generateCorrelationId(),
496
+ host: this.getHostname(),
497
+ pid: process.pid,
498
+ ...this.bindings,
499
+ ...context
500
+ };
501
+ for (const mw of this.middleware) {
502
+ event = mw.process(event);
503
+ }
504
+ for (const sink of this.sinks) {
505
+ sink.write(event);
506
+ }
507
+ }
508
+ child(bindings) {
509
+ const mergedBindings = { ...this.bindings, ...bindings };
510
+ return new _EnterpriseLogger(
511
+ this.service,
512
+ {
513
+ sinks: this.sinks,
514
+ middleware: this.middleware
515
+ },
516
+ mergedBindings
517
+ );
518
+ }
519
+ generateCorrelationId() {
520
+ return `corr-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
521
+ }
522
+ getHostname() {
523
+ try {
524
+ return hostname();
525
+ } catch {
526
+ return process.env.HOSTNAME || "unknown";
527
+ }
528
+ }
529
+ };
530
+
531
+ // src/logging/middleware.ts
532
+ var DEFAULT_SECRET_KEYS = [
533
+ "password",
534
+ "token",
535
+ "apikey",
536
+ "api_key",
537
+ "authorization",
538
+ "secret",
539
+ "cardnumber",
540
+ "card_number",
541
+ "cvv",
542
+ "ssn",
543
+ "accesstoken",
544
+ "access_token",
545
+ "refreshtoken",
546
+ "refresh_token"
547
+ ];
548
+ var DEFAULT_SECRET_PATTERNS = [
549
+ /SECRET_[A-Z0-9_]+/g,
550
+ // Environment variable secrets
551
+ /[A-Z0-9_]*TOKEN[A-Z0-9_]*/g,
552
+ // Token variants
553
+ /[A-Z0-9_]*KEY[A-Z0-9_]*/g,
554
+ // Key variants
555
+ /[A-Za-z0-9+/]{40,}={0,2}/g,
556
+ // Base64 blobs (~40+ chars)
557
+ /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
558
+ // Email addresses
559
+ /\b\d{13,19}\b/g
560
+ // Credit card numbers (13-19 digits)
561
+ ];
562
+ var MAX_PATTERN_SCAN_SIZE = 10240;
563
+ var RedactSecretsMiddleware = class {
564
+ secretKeys;
565
+ secretKeysLower;
566
+ patterns;
567
+ constructor(optionsOrKeys) {
568
+ let secretKeys;
569
+ let patterns = [];
570
+ let useDefaultPatterns = true;
571
+ if (Array.isArray(optionsOrKeys)) {
572
+ secretKeys = optionsOrKeys;
573
+ useDefaultPatterns = false;
574
+ } else {
575
+ secretKeys = optionsOrKeys?.secretKeys ?? DEFAULT_SECRET_KEYS;
576
+ patterns = optionsOrKeys?.patterns ?? [];
577
+ useDefaultPatterns = optionsOrKeys?.useDefaultPatterns ?? true;
578
+ }
579
+ this.secretKeys = secretKeys;
580
+ this.secretKeysLower = secretKeys.map((k) => k.toLowerCase());
581
+ this.patterns = [...useDefaultPatterns ? DEFAULT_SECRET_PATTERNS : [], ...patterns];
582
+ }
583
+ process(event) {
584
+ const redacted = { ...event };
585
+ for (const key of Object.keys(redacted)) {
586
+ if (this.isSecretKey(key)) {
587
+ redacted[key] = "[REDACTED]";
588
+ }
589
+ }
590
+ this.redactNested(redacted);
591
+ return redacted;
592
+ }
593
+ isSecretKey(key) {
594
+ return this.secretKeysLower.includes(key.toLowerCase());
595
+ }
596
+ redactNested(obj) {
597
+ for (const [key, value] of Object.entries(obj)) {
598
+ if (this.isSecretKey(key)) {
599
+ obj[key] = "[REDACTED]";
600
+ } else if (typeof value === "string") {
601
+ obj[key] = this.redactPatterns(value);
602
+ } else if (value && typeof value === "object") {
603
+ if (this.isPlainObject(value)) {
604
+ if (Array.isArray(value)) {
605
+ this.redactArray(value);
606
+ } else {
607
+ this.redactNested(value);
608
+ }
609
+ }
610
+ }
611
+ }
612
+ }
613
+ redactArray(arr) {
614
+ for (let i = 0; i < arr.length; i++) {
615
+ const item = arr[i];
616
+ if (typeof item === "string") {
617
+ arr[i] = this.redactPatterns(item);
618
+ } else if (item && typeof item === "object") {
619
+ if (this.isPlainObject(item)) {
620
+ if (Array.isArray(item)) {
621
+ this.redactArray(item);
622
+ } else {
623
+ this.redactNested(item);
624
+ }
625
+ }
626
+ }
627
+ }
628
+ }
629
+ /**
630
+ * Apply regex patterns to redact secrets from string values
631
+ * Skips strings larger than MAX_PATTERN_SCAN_SIZE for performance
632
+ */
633
+ redactPatterns(value) {
634
+ if (value.length > MAX_PATTERN_SCAN_SIZE) {
635
+ return value;
636
+ }
637
+ let result = value;
638
+ for (const pattern of this.patterns) {
639
+ pattern.lastIndex = 0;
640
+ result = result.replace(pattern, "[REDACTED]");
641
+ }
642
+ return result;
643
+ }
644
+ /**
645
+ * Check if value is a plain object (not Date, Buffer, Error, etc.)
646
+ */
647
+ isPlainObject(value) {
648
+ if (!value || typeof value !== "object") {
649
+ return false;
650
+ }
651
+ if (value instanceof Date || value instanceof Error || value instanceof RegExp || ArrayBuffer.isView(value) || // Covers Buffer, TypedArray, DataView
652
+ value instanceof ArrayBuffer) {
653
+ return false;
654
+ }
655
+ if (Array.isArray(value)) {
656
+ return true;
657
+ }
658
+ return true;
659
+ }
660
+ };
661
+ var AddFieldsMiddleware = class {
662
+ constructor(fields) {
663
+ this.fields = fields;
664
+ }
665
+ process(event) {
666
+ return {
667
+ ...event,
668
+ ...this.fields
669
+ };
670
+ }
671
+ };
672
+ var TransformMiddleware = class {
673
+ constructor(transformer) {
674
+ this.transformer = transformer;
675
+ }
676
+ process(event) {
677
+ return this.transformer(event);
678
+ }
679
+ };
680
+
681
+ // src/logging/create-logger.ts
682
+ function createLogger(config) {
683
+ return new Logger(config);
684
+ }
685
+ function createSimpleLogger(service) {
686
+ return new Logger({
687
+ service,
688
+ profile: "simple" /* SIMPLE */
689
+ });
690
+ }
691
+ function createStructuredLogger(service, filePath) {
692
+ return new Logger({
693
+ service,
694
+ profile: "structured" /* STRUCTURED */,
695
+ filePath
696
+ });
697
+ }
698
+ function createEnterpriseLogger(service, options) {
699
+ return new Logger({
700
+ service,
701
+ profile: "enterprise" /* ENTERPRISE */,
702
+ ...options
703
+ });
704
+ }
705
+ function createStructuredLoggerWithRedaction(service, options) {
706
+ return new Logger({
707
+ service,
708
+ profile: "structured" /* STRUCTURED */,
709
+ filePath: options?.filePath,
710
+ middleware: [
711
+ new RedactSecretsMiddleware({
712
+ secretKeys: options?.customFields,
713
+ patterns: options?.customPatterns,
714
+ useDefaultPatterns: options?.useDefaultPatterns
715
+ })
716
+ ]
717
+ });
718
+ }
719
+
720
+ // src/logging/index.ts
721
+ var VERSION = "0.1.0";
722
+
723
+ export { AddFieldsMiddleware, ConsoleSink, FileSink, Logger, LoggingProfile, NullSink, PolicyEnforcer, PolicyError, RedactSecretsMiddleware, TransformMiddleware, VERSION, createEnterpriseLogger, createLogger, createSimpleLogger, createStructuredLogger, createStructuredLoggerWithRedaction };
724
+ //# sourceMappingURL=chunk-5HZEJGZ5.js.map
725
+ //# sourceMappingURL=chunk-5HZEJGZ5.js.map