@generazioneai/telemetry 0.0.1 → 0.2.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 (59) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +43 -1
  3. package/dist/attributes.d.ts +13 -0
  4. package/dist/attributes.d.ts.map +1 -0
  5. package/dist/attributes.js +115 -0
  6. package/dist/attributes.js.map +1 -0
  7. package/dist/config.d.ts +22 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +44 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/final-mode.d.ts +23 -0
  12. package/dist/final-mode.d.ts.map +1 -0
  13. package/dist/final-mode.js +56 -0
  14. package/dist/final-mode.js.map +1 -0
  15. package/dist/index.d.ts +16 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +43 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/log-context.d.ts +8 -0
  20. package/dist/log-context.d.ts.map +1 -0
  21. package/dist/log-context.js +13 -0
  22. package/dist/log-context.js.map +1 -0
  23. package/dist/logger/index.d.ts +10 -0
  24. package/dist/logger/index.d.ts.map +1 -0
  25. package/dist/logger/index.js +23 -0
  26. package/dist/logger/index.js.map +1 -0
  27. package/dist/logger/json-logger.d.ts +39 -0
  28. package/dist/logger/json-logger.d.ts.map +1 -0
  29. package/dist/logger/json-logger.js +127 -0
  30. package/dist/logger/json-logger.js.map +1 -0
  31. package/dist/nats.interceptor.d.ts +18 -0
  32. package/dist/nats.interceptor.d.ts.map +1 -0
  33. package/dist/nats.interceptor.js +124 -0
  34. package/dist/nats.interceptor.js.map +1 -0
  35. package/dist/propagation.d.ts +18 -0
  36. package/dist/propagation.d.ts.map +1 -0
  37. package/dist/propagation.js +37 -0
  38. package/dist/propagation.js.map +1 -0
  39. package/dist/redaction.d.ts +13 -0
  40. package/dist/redaction.d.ts.map +1 -0
  41. package/dist/redaction.js +133 -0
  42. package/dist/redaction.js.map +1 -0
  43. package/dist/register.d.ts +2 -0
  44. package/dist/register.d.ts.map +1 -0
  45. package/dist/register.js +10 -0
  46. package/dist/register.js.map +1 -0
  47. package/dist/sanitizing-exporter.d.ts +13 -0
  48. package/dist/sanitizing-exporter.d.ts.map +1 -0
  49. package/dist/sanitizing-exporter.js +45 -0
  50. package/dist/sanitizing-exporter.js.map +1 -0
  51. package/dist/sdk.d.ts +18 -0
  52. package/dist/sdk.d.ts.map +1 -0
  53. package/dist/sdk.js +94 -0
  54. package/dist/sdk.js.map +1 -0
  55. package/dist/telemetry.module.d.ts +26 -0
  56. package/dist/telemetry.module.d.ts.map +1 -0
  57. package/dist/telemetry.module.js +78 -0
  58. package/dist/telemetry.module.js.map +1 -0
  59. package/package.json +92 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog — @generazioneai/telemetry
2
+
3
+ ## 0.2.0 — 2026-11-10
4
+
5
+ «Via gli interruttori» (decisione del 2026-11-10): niente `TELEMETRY_MODE`, la telemetria è accesa se c'è un endpoint
6
+ (`OTEL_EXPORTER_OTLP_ENDPOINT`, di serie il collector del cluster; vuota = spenta). In sviluppo locale l'endpoint di serie è vuoto e
7
+ `TELEMETRY_MODE=off` conta ancora; altrove si ignora con un avviso. **Non pubblicata.**
8
+
9
+ ## 0.1.0 — 2026-10-25
10
+ Prima versione (treno 3+4, O1; ADR-013, spec «Fondamenta enterprise» §5.2, decisioni 31, 32, 35).
11
+ - `@generazioneai/telemetry/register`: SDK OpenTelemetry Node (tracce e metriche OTLP/HTTP; HTTP, pg, ioredis, Prisma), spento di serie (`TELEMETRY_MODE=off`).
12
+ - `TelemetryModule.forRoot({ service })`: interceptor `nats.server <cmd>`, hook `traceparent` per `setNatsHeadersHook` di authz ≥ 0.7 (opzionale), spegnimento.
13
+ - `@generazioneai/telemetry/logger`: `JsonLogger` (`level`, `ts`, `service`, `msg`, `trace_id`, `span_id`, `cmd`, `juridicalId`), `createLogger` (`LOG_FORMAT`).
14
+ - Attributi a lista bianca, esportatore che ripulisce gli span, redazione di corpi, `Authorization`, cookie, email, nomi, codici fiscali, IBAN, JWT.
package/README.md CHANGED
@@ -1,3 +1,45 @@
1
1
  # @generazioneai/telemetry
2
2
 
3
- Segnaposto. Il pacchetto vero arriva con la 0.1.0.
3
+ Osservabilità comune dei servizi Node (ADR-013, spec «Fondamenta enterprise» §5): tracce e metriche OpenTelemetry verso il collector, log JSON con `trace_id`, span dei comandi NATS, nessun dato personale.
4
+
5
+ ```bash
6
+ npm i @generazioneai/telemetry
7
+ ```
8
+
9
+ ## Uso
10
+ ```ts
11
+ // main.ts — PRIMA riga
12
+ import '@generazioneai/telemetry/register';
13
+ import { createLogger } from '@generazioneai/telemetry/logger';
14
+
15
+ const app = await NestFactory.create(AppModule, { logger: createLogger('hr') });
16
+
17
+ // app.module.ts
18
+ TelemetryModule.forRoot({ service: 'hr' })
19
+ ```
20
+
21
+ | Variabile | Valori | Di serie |
22
+ |---|---|---|
23
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | base OTLP/HTTP | `http://otel-collector.observability:4318` (in sviluppo locale: vuota); **vuota = spento** (il processo non carica l'SDK, nessuna connessione) |
24
+ | `TELEMETRY_MODE` | `on` | 0.2 (decisione del 2026-11-10): accesa se c'è l'endpoint. `off` conta solo in sviluppo locale e nei test (`SKILLERA_ENV` `dev`/`local` o `NODE_ENV` `development`/`test`, fuori da un cluster); altrove si ignora con un avviso |
25
+ | `OTEL_SERVICE_NAME` | nome | `name` del `package.json` (senza scope) |
26
+ | `SKILLERA_ENV` | | → `deployment.environment` |
27
+ | `LOG_FORMAT` | `text` \| `json` | `text` |
28
+ | `APP_LOGGER_LEVEL` | `log,error,warn,debug,verbose` \| `none` | `log,error,warn` (`fatal` segue `error`) |
29
+ | `TELEMETRY_SAMPLE_RATIO` | 0..1 | `1` (il campionamento in coda è del collector) |
30
+ | `OTEL_METRIC_EXPORT_INTERVAL` | ms | `60000` |
31
+
32
+ Impostare `OTEL_SERVICE_NAME` nei manifest: `register` parte prima di Nest e non conosce l'opzione `service` del modulo.
33
+
34
+ ## Cosa fa
35
+ - **`/register`**: Node SDK con OTLP/HTTP per tracce e metriche; strumentazioni HTTP (senza `health`/`metrics`), `pg`, `ioredis`, Prisma (le ultime tre opzionali). Nessun gestore di SIGTERM: lo spegnimento ordinato lo fa `TelemetryModule` (o `beforeExit`).
36
+ - **NATS**: l'interceptor globale (solo contesto `rpc`) apre `nats.server <cmd>` (kind consumer) come figlio del `traceparent` negli header, mette `cmd` e `juridicalId` nel contesto dei log, conta `nats_server_requests_total{cmd,outcome}` e `nats_server_request_duration_seconds{cmd}`. `juridicalId` viene dall'header `Gen-Tenant` o da `auth.juridicalId`/`auth.tenantId`/`dto.juridicalId`, solo se è un UUID.
37
+ - **Invio**: `traceparentHeadersHook` scrive `traceparent` negli header. `TelemetryModule.forRoot` lo registra con `setNatsHeadersHook` di `@generazioneai/authz` ≥ 0.7 se c'è (altrimenti nulla); si può passare il modulo con `authz: …` o spegnere con `authz: false`. Per gli eventi di JetStream ci pensa `@generazioneai/events` con `injectTraceContext`/`extractTraceContext`.
38
+ - **Log** (`JsonLogger`): `level`, `ts`, `service`, `msg`, `trace_id`, `span_id`, `cmd`, `juridicalId` (+ `context`, `err`, campi del messaggio-oggetto, mai in conflitto con quelli del contratto).
39
+ - **Dati personali** (decisione 35): gli span escono da `SanitizingSpanExporter`, che tiene solo gli attributi della **lista bianca** (`ALLOWED_ATTRIBUTES`: metodo, rotta come modello, comando, esito, durata, dimensioni, id di azienda UUID, `db.statement` senza letterali, redis solo il comando), stato senza messaggio, IP solo come hash (`client.ip_hash`). `redact()`/`maskString()` (usate dal logger) azzerano i valori di chiavi come `authorization`, `cookie`, `body`, `dto`, `email`, `*name`, `fiscalCode`, `iban`, `password`, `*token` e mascherano nel testo email, codici fiscali (anche omocodici), IBAN, JWT, `Bearer …`.
40
+
41
+ ## Compatibilità delle versioni OpenTelemetry
42
+ Le strumentazioni sono fissate alla famiglia `0.219` con `@opentelemetry/api` 1.9 (la `0.300` richiede api ≥ 1.10, che gli SDK 2.x non accettano ancora). Il servizio **non** deve avere un proprio `@opentelemetry/api` diverso.
43
+
44
+ ## Prove
45
+ `npm test`. La prova dell'SDK acceso gira in un processo Node figlio (le strumentazioni usano `import()` dinamici, che Jest non esegue) e costruisce il pacchetto in `.test-dist/`.
@@ -0,0 +1,13 @@
1
+ import type { Attributes } from '@opentelemetry/api';
2
+ /**
3
+ * Lista bianca degli attributi di un span (decisione 35): metodo, rotta come modello, comando, esito, durata, dimensione,
4
+ * id di azienda. Tutto il resto cade, anche se un'instrumentation lo scrive (`http.url`, `url.query`, intestazioni,
5
+ * `exception.message`, `db.query.parameter.*`…).
6
+ */
7
+ export declare const ALLOWED_ATTRIBUTES: ReadonlySet<string>;
8
+ export declare function hashIp(ip: string, salt?: string): string;
9
+ /** Toglie dal testo SQL stringhe e numeri letterali: restano struttura e segnaposto `$1`. */
10
+ export declare function sanitizeStatement(sql: string): string;
11
+ /** Copia degli attributi con solo quelli ammessi e ripuliti. */
12
+ export declare function sanitizeAttributes(attrs: Attributes | undefined): Attributes;
13
+ //# sourceMappingURL=attributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AAGrE;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAgDjD,CAAC;AAMH,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,SAAsC,GAAG,MAAM,CAErF;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKrD;AAOD,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CA2B5E"}
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ALLOWED_ATTRIBUTES = void 0;
4
+ exports.hashIp = hashIp;
5
+ exports.sanitizeStatement = sanitizeStatement;
6
+ exports.sanitizeAttributes = sanitizeAttributes;
7
+ const crypto_1 = require("crypto");
8
+ const redaction_1 = require("./redaction");
9
+ /**
10
+ * Lista bianca degli attributi di un span (decisione 35): metodo, rotta come modello, comando, esito, durata, dimensione,
11
+ * id di azienda. Tutto il resto cade, anche se un'instrumentation lo scrive (`http.url`, `url.query`, intestazioni,
12
+ * `exception.message`, `db.query.parameter.*`…).
13
+ */
14
+ exports.ALLOWED_ATTRIBUTES = new Set([
15
+ 'http.request.method',
16
+ 'http.method',
17
+ 'http.route',
18
+ 'http.response.status_code',
19
+ 'http.status_code',
20
+ 'http.request.body.size',
21
+ 'http.response.body.size',
22
+ 'http.request_content_length',
23
+ 'http.response_content_length',
24
+ 'network.protocol.name',
25
+ 'network.protocol.version',
26
+ 'network.transport',
27
+ 'url.scheme',
28
+ 'server.address',
29
+ 'server.port',
30
+ 'net.peer.name',
31
+ 'net.peer.port',
32
+ 'messaging.system',
33
+ 'messaging.operation',
34
+ 'messaging.operation.name',
35
+ 'messaging.operation.type',
36
+ 'messaging.destination.name',
37
+ 'messaging.message.body.size',
38
+ 'rpc.system',
39
+ 'rpc.method',
40
+ 'cmd',
41
+ 'outcome',
42
+ 'error.type',
43
+ 'exception.type',
44
+ 'db.system',
45
+ 'db.system.name',
46
+ 'db.operation',
47
+ 'db.operation.name',
48
+ 'db.namespace',
49
+ 'db.name',
50
+ 'db.sql.table',
51
+ 'db.collection.name',
52
+ 'db.statement',
53
+ 'db.query.text',
54
+ 'db.redis.database_index',
55
+ 'duration_ms',
56
+ 'size_bytes',
57
+ 'juridicalId',
58
+ 'gen.juridical_id',
59
+ 'job',
60
+ 'consumer',
61
+ 'event.subject',
62
+ ]);
63
+ const IP_KEYS = new Set(['client.address', 'net.sock.peer.addr', 'net.peer.ip', 'http.client_ip', 'net.sock.host.addr']);
64
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
65
+ const ID_KEYS = new Set(['juridicalId', 'gen.juridical_id']);
66
+ function hashIp(ip, salt = process.env.TELEMETRY_IP_SALT ?? '') {
67
+ return (0, crypto_1.createHash)('sha256').update(`${salt}${ip}`).digest('hex').slice(0, 16);
68
+ }
69
+ /** Toglie dal testo SQL stringhe e numeri letterali: restano struttura e segnaposto `$1`. */
70
+ function sanitizeStatement(sql) {
71
+ return sql
72
+ .replace(/'(?:[^']|'')*'/g, '?')
73
+ .replace(/(?<![\w$])\d+(?:\.\d+)?(?![\w$])/g, '?')
74
+ .slice(0, 1000);
75
+ }
76
+ function scalar(value) {
77
+ if (value === undefined || value === null || Array.isArray(value))
78
+ return undefined;
79
+ return value;
80
+ }
81
+ /** Copia degli attributi con solo quelli ammessi e ripuliti. */
82
+ function sanitizeAttributes(attrs) {
83
+ const out = {};
84
+ if (!attrs)
85
+ return out;
86
+ for (const [key, raw] of Object.entries(attrs)) {
87
+ const value = scalar(raw);
88
+ if (value === undefined)
89
+ continue;
90
+ if (IP_KEYS.has(key)) {
91
+ if (typeof value === 'string')
92
+ out['client.ip_hash'] = hashIp(value);
93
+ continue;
94
+ }
95
+ if (!exports.ALLOWED_ATTRIBUTES.has(key))
96
+ continue;
97
+ if (ID_KEYS.has(key)) {
98
+ if (typeof value === 'string' && UUID.test(value))
99
+ out[key] = value;
100
+ continue;
101
+ }
102
+ if (typeof value !== 'string') {
103
+ out[key] = value;
104
+ continue;
105
+ }
106
+ if (key === 'db.statement' || key === 'db.query.text') {
107
+ // Redis: solo il comando, mai chiavi e valori.
108
+ out[key] = attrs['db.system'] === 'redis' || attrs['db.system.name'] === 'redis' ? value.split(/\s+/)[0] : (0, redaction_1.maskString)(sanitizeStatement(value));
109
+ continue;
110
+ }
111
+ out[key] = (0, redaction_1.maskString)(value);
112
+ }
113
+ return out;
114
+ }
115
+ //# sourceMappingURL=attributes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export declare const DEFAULT_OTLP_ENDPOINT = "http://otel-collector.observability:4318";
2
+ export interface TelemetryConfig {
3
+ enabled: boolean;
4
+ endpoint: string;
5
+ serviceName: string;
6
+ environment?: string;
7
+ serviceVersion?: string;
8
+ sampleRatio: number;
9
+ metricIntervalMs: number;
10
+ }
11
+ /**
12
+ * 0.2 (via gli interruttori, 2026-11-10): accesa se c'è dove mandare (un endpoint), senza interruttore.
13
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT`: base OTLP/HTTP; **vuota = spento** (il processo non carica nulla, non apre connessioni).
14
+ * Di serie quella del collector nel cluster; in sviluppo locale (`isLocalDevEnv`) di serie vuota, cioè spenta;
15
+ * - `TELEMETRY_MODE=off` spegne solo in sviluppo locale e nei test; altrove si ignora con un avviso;
16
+ * - `OTEL_SERVICE_NAME`, altrimenti il `name` del `package.json` del processo;
17
+ * - `SKILLERA_ENV` → `deployment.environment`;
18
+ * - `TELEMETRY_SAMPLE_RATIO` (0..1, di serie 1: il campionamento in coda lo fa il collector);
19
+ * - `OTEL_METRIC_EXPORT_INTERVAL` (ms, di serie 60000).
20
+ */
21
+ export declare function readConfig(env?: NodeJS.ProcessEnv): TelemetryConfig;
22
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,6CAA6C,CAAC;AAEhF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAWD;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,eAAe,CAehF"}
package/dist/config.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_OTLP_ENDPOINT = void 0;
4
+ exports.readConfig = readConfig;
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const final_mode_1 = require("./final-mode");
8
+ exports.DEFAULT_OTLP_ENDPOINT = 'http://otel-collector.observability:4318';
9
+ function packageName() {
10
+ try {
11
+ const name = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'package.json'), 'utf8')).name;
12
+ return name?.replace(/^@[^/]+\//, '');
13
+ }
14
+ catch {
15
+ return undefined;
16
+ }
17
+ }
18
+ /**
19
+ * 0.2 (via gli interruttori, 2026-11-10): accesa se c'è dove mandare (un endpoint), senza interruttore.
20
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT`: base OTLP/HTTP; **vuota = spento** (il processo non carica nulla, non apre connessioni).
21
+ * Di serie quella del collector nel cluster; in sviluppo locale (`isLocalDevEnv`) di serie vuota, cioè spenta;
22
+ * - `TELEMETRY_MODE=off` spegne solo in sviluppo locale e nei test; altrove si ignora con un avviso;
23
+ * - `OTEL_SERVICE_NAME`, altrimenti il `name` del `package.json` del processo;
24
+ * - `SKILLERA_ENV` → `deployment.environment`;
25
+ * - `TELEMETRY_SAMPLE_RATIO` (0..1, di serie 1: il campionamento in coda lo fa il collector);
26
+ * - `OTEL_METRIC_EXPORT_INTERVAL` (ms, di serie 60000).
27
+ */
28
+ function readConfig(env = process.env) {
29
+ const rawEndpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;
30
+ const fallback = (0, final_mode_1.isLocalDevEnv)(env) ? '' : exports.DEFAULT_OTLP_ENDPOINT;
31
+ const endpoint = (rawEndpoint === undefined ? fallback : rawEndpoint).trim().replace(/\/+$/, '');
32
+ const ratio = Number(env.TELEMETRY_SAMPLE_RATIO ?? '1');
33
+ const mode = (0, final_mode_1.finalMode)({ name: 'TELEMETRY_MODE', final: 'on', allowed: ['on', 'off'], requested: env.TELEMETRY_MODE, env });
34
+ return {
35
+ enabled: mode === 'on' && endpoint !== '',
36
+ endpoint,
37
+ serviceName: env.OTEL_SERVICE_NAME?.trim() || packageName() || 'unknown-service',
38
+ environment: env.SKILLERA_ENV,
39
+ serviceVersion: env.npm_package_version,
40
+ sampleRatio: Number.isFinite(ratio) ? Math.min(1, Math.max(0, ratio)) : 1,
41
+ metricIntervalMs: Number(env.OTEL_METRIC_EXPORT_INTERVAL) > 0 ? Number(env.OTEL_METRIC_EXPORT_INTERVAL) : 60_000,
42
+ };
43
+ }
44
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAmCA,gCAeC;AAlDD,2BAAkC;AAClC,+BAA4B;AAC5B,6CAAwD;AAE3C,QAAA,qBAAqB,GAAG,0CAA0C,CAAC;AAYhF,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAA0B,CAAC;QAC9G,OAAO,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,WAAW,GAAG,GAAG,CAAC,2BAA2B,CAAC;IACpD,MAAM,QAAQ,GAAG,IAAA,0BAAa,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,6BAAqB,CAAC;IACjE,MAAM,QAAQ,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjG,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,sBAAsB,IAAI,GAAG,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,IAAA,sBAAS,EAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,CAAU,EAAE,SAAS,EAAE,GAAG,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IACrI,OAAO;QACL,OAAO,EAAE,IAAI,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE;QACzC,QAAQ;QACR,WAAW,EAAE,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,IAAI,WAAW,EAAE,IAAI,iBAAiB;QAChF,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,cAAc,EAAE,GAAG,CAAC,mBAAmB;QACvC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,MAAM;KACjH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ /** `true` solo in sviluppo locale o nei test: l'unico caso in cui le vecchie modalità contano ancora. */
2
+ export declare function isLocalDevEnv(env?: NodeJS.ProcessEnv): boolean;
3
+ export interface FinalModeOptions<T extends string> {
4
+ /** Nome della variabile (per l'avviso). */
5
+ name: string;
6
+ /** Il valore finale, quello che vale fuori dallo sviluppo locale. */
7
+ final: T;
8
+ /** I valori che lo sviluppo locale può ancora chiedere (il finale compreso). */
9
+ allowed: readonly T[];
10
+ /** Il valore chiesto (opzione o env); vuoto/assente = il finale. */
11
+ requested?: string | null;
12
+ env?: NodeJS.ProcessEnv;
13
+ /** Default `console.warn`. */
14
+ warn?: (message: string) => void;
15
+ }
16
+ /** Per i test: dimentica gli avvisi già dati. */
17
+ export declare function resetFinalModeWarnings(): void;
18
+ /**
19
+ * Il valore effettivo di una vecchia modalità: il finale, tranne in sviluppo locale dove si rispetta il valore chiesto (se è
20
+ * uno degli ammessi). Un valore sconosciuto o fuori posto non fa mai fallire l'avvio: vale il finale, con un avviso.
21
+ */
22
+ export declare function finalMode<T extends string>(o: FinalModeOptions<T>): T;
23
+ //# sourceMappingURL=final-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"final-mode.d.ts","sourceRoot":"","sources":["../src/final-mode.ts"],"names":[],"mappings":"AAYA,yGAAyG;AACzG,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAM3E;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM;IAChD,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,EAAE,CAAC,CAAC;IACT,gFAAgF;IAChF,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IACtB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAID,iDAAiD;AACjD,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAQD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAmBrE"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ // Valori finali fissi delle vecchie modalità di rilascio (decisione del CTO del 2026-11-10, «via gli interruttori»).
3
+ //
4
+ // Le variabili che sceglievano off/log/shadow/enforce (AUTHZ_ENFORCE_MODE, AUTHZ_INTERNAL_AUTH_MODE, AUTHZ_KEY_POLICY, …) non
5
+ // scelgono più nulla: vale sempre il comportamento finale. Resta UNA via di fuga, solo per lo sviluppo locale e i test
6
+ // (D-E del censimento): lì il valore dell'env (o dell'opzione) si rispetta ancora. In ogni altro ambiente un valore diverso
7
+ // dal finale si ignora con un avviso, una volta per variabile e valore: mai un crash all'avvio.
8
+ //
9
+ // Sviluppo locale = nessun `KUBERNETES_SERVICE_HOST` (mai dentro un cluster) E (`SKILLERA_ENV` è `dev`/`local`, oppure
10
+ // `SKILLERA_ENV` manca e `NODE_ENV` è `development`/`test`). Uno `SKILLERA_ENV` diverso (stg, prod, …) chiude sempre la via.
11
+ //
12
+ // Copia identica in authz, gateway-kit, events, telemetry e crypto (pacchetti pubblicati a parte, senza dipendenze fra loro).
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.isLocalDevEnv = isLocalDevEnv;
15
+ exports.resetFinalModeWarnings = resetFinalModeWarnings;
16
+ exports.finalMode = finalMode;
17
+ /** `true` solo in sviluppo locale o nei test: l'unico caso in cui le vecchie modalità contano ancora. */
18
+ function isLocalDevEnv(env = process.env) {
19
+ if ((env.KUBERNETES_SERVICE_HOST ?? '').trim())
20
+ return false;
21
+ const skilleraEnv = (env.SKILLERA_ENV ?? '').trim().toLowerCase();
22
+ if (skilleraEnv)
23
+ return skilleraEnv === 'dev' || skilleraEnv === 'local';
24
+ const nodeEnv = (env.NODE_ENV ?? '').trim().toLowerCase();
25
+ return nodeEnv === 'development' || nodeEnv === 'test';
26
+ }
27
+ const warned = new Set();
28
+ /** Per i test: dimentica gli avvisi già dati. */
29
+ function resetFinalModeWarnings() {
30
+ warned.clear();
31
+ }
32
+ function warnOnce(key, message, warn) {
33
+ if (warned.has(key))
34
+ return;
35
+ warned.add(key);
36
+ (warn ?? ((m) => console.warn(m)))(message);
37
+ }
38
+ /**
39
+ * Il valore effettivo di una vecchia modalità: il finale, tranne in sviluppo locale dove si rispetta il valore chiesto (se è
40
+ * uno degli ammessi). Un valore sconosciuto o fuori posto non fa mai fallire l'avvio: vale il finale, con un avviso.
41
+ */
42
+ function finalMode(o) {
43
+ const raw = (o.requested ?? '').toString().trim().toLowerCase();
44
+ if (!raw || raw === o.final)
45
+ return o.final;
46
+ const env = o.env ?? process.env;
47
+ if (!o.allowed.includes(raw)) {
48
+ warnOnce(`${o.name}|${raw}`, `[via-interruttori] ${o.name}=«${raw}» sconosciuto: vale «${o.final}» (ammessi solo in sviluppo locale: ${o.allowed.join(', ')})`, o.warn);
49
+ return o.final;
50
+ }
51
+ if (isLocalDevEnv(env))
52
+ return raw;
53
+ warnOnce(`${o.name}|${raw}`, `[via-interruttori] ${o.name}=«${raw}» ignorato: fuori dallo sviluppo locale vale sempre «${o.final}» (decisione 2026-11-10, via gli interruttori)`, o.warn);
54
+ return o.final;
55
+ }
56
+ //# sourceMappingURL=final-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"final-mode.js","sourceRoot":"","sources":["../src/final-mode.ts"],"names":[],"mappings":";AAAA,qHAAqH;AACrH,EAAE;AACF,8HAA8H;AAC9H,uHAAuH;AACvH,4HAA4H;AAC5H,gGAAgG;AAChG,EAAE;AACF,uHAAuH;AACvH,6HAA6H;AAC7H,EAAE;AACF,8HAA8H;;AAG9H,sCAMC;AAmBD,wDAEC;AAYD,8BAmBC;AA3DD,yGAAyG;AACzG,SAAgB,aAAa,CAAC,MAAyB,OAAO,CAAC,GAAG;IAChE,IAAI,CAAC,GAAG,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IAC7D,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClE,IAAI,WAAW;QAAE,OAAO,WAAW,KAAK,KAAK,IAAI,WAAW,KAAK,OAAO,CAAC;IACzE,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1D,OAAO,OAAO,KAAK,aAAa,IAAI,OAAO,KAAK,MAAM,CAAC;AACzD,CAAC;AAgBD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;AAEjC,iDAAiD;AACjD,SAAgB,sBAAsB;IACpC,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,OAAe,EAAE,IAA0B;IACxE,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO;IAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC,IAAI,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,SAAgB,SAAS,CAAmB,CAAsB;IAChE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChE,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IAC5C,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACjC,IAAI,CAAE,CAAC,CAAC,OAA6B,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACpD,QAAQ,CACN,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,EAClB,sBAAsB,CAAC,CAAC,IAAI,KAAK,GAAG,wBAAwB,CAAC,CAAC,KAAK,uCAAuC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACjI,CAAC,CAAC,IAAI,CACP,CAAC;QACF,OAAO,CAAC,CAAC,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,aAAa,CAAC,GAAG,CAAC;QAAE,OAAO,GAAQ,CAAC;IACxC,QAAQ,CACN,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,EAClB,sBAAsB,CAAC,CAAC,IAAI,KAAK,GAAG,wDAAwD,CAAC,CAAC,KAAK,gDAAgD,EACnJ,CAAC,CAAC,IAAI,CACP,CAAC;IACF,OAAO,CAAC,CAAC,KAAK,CAAC;AACjB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export { TelemetryModule, TelemetryService, TELEMETRY_OPTIONS } from './telemetry.module';
2
+ export type { TelemetryModuleOptions } from './telemetry.module';
3
+ export { NatsTelemetryInterceptor, resolveCmd, pickJuridicalId } from './nats.interceptor';
4
+ export { injectTraceContext, extractTraceContext, traceparentHeadersHook } from './propagation';
5
+ export type { NatsHeadersHook, HeadersLike, ReadableHeadersLike } from './propagation';
6
+ export { redact, maskString, isSensitiveKey, REDACTED } from './redaction';
7
+ export { sanitizeAttributes, sanitizeStatement, ALLOWED_ATTRIBUTES, hashIp } from './attributes';
8
+ export { SanitizingSpanExporter, sanitizeSpan } from './sanitizing-exporter';
9
+ export { runWithLogContext, getLogContext } from './log-context';
10
+ export type { LogContext } from './log-context';
11
+ export { startTelemetry, shutdownTelemetry, getTelemetry } from './sdk';
12
+ export type { TelemetryHandle } from './sdk';
13
+ export { readConfig, DEFAULT_OTLP_ENDPOINT } from './config';
14
+ export type { TelemetryConfig } from './config';
15
+ export { JsonLogger, createLogger, parseLogLevels } from './logger';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAChG,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACxE,YAAY,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseLogLevels = exports.createLogger = exports.JsonLogger = exports.DEFAULT_OTLP_ENDPOINT = exports.readConfig = exports.getTelemetry = exports.shutdownTelemetry = exports.startTelemetry = exports.getLogContext = exports.runWithLogContext = exports.sanitizeSpan = exports.SanitizingSpanExporter = exports.hashIp = exports.ALLOWED_ATTRIBUTES = exports.sanitizeStatement = exports.sanitizeAttributes = exports.REDACTED = exports.isSensitiveKey = exports.maskString = exports.redact = exports.traceparentHeadersHook = exports.extractTraceContext = exports.injectTraceContext = exports.pickJuridicalId = exports.resolveCmd = exports.NatsTelemetryInterceptor = exports.TELEMETRY_OPTIONS = exports.TelemetryService = exports.TelemetryModule = void 0;
4
+ var telemetry_module_1 = require("./telemetry.module");
5
+ Object.defineProperty(exports, "TelemetryModule", { enumerable: true, get: function () { return telemetry_module_1.TelemetryModule; } });
6
+ Object.defineProperty(exports, "TelemetryService", { enumerable: true, get: function () { return telemetry_module_1.TelemetryService; } });
7
+ Object.defineProperty(exports, "TELEMETRY_OPTIONS", { enumerable: true, get: function () { return telemetry_module_1.TELEMETRY_OPTIONS; } });
8
+ var nats_interceptor_1 = require("./nats.interceptor");
9
+ Object.defineProperty(exports, "NatsTelemetryInterceptor", { enumerable: true, get: function () { return nats_interceptor_1.NatsTelemetryInterceptor; } });
10
+ Object.defineProperty(exports, "resolveCmd", { enumerable: true, get: function () { return nats_interceptor_1.resolveCmd; } });
11
+ Object.defineProperty(exports, "pickJuridicalId", { enumerable: true, get: function () { return nats_interceptor_1.pickJuridicalId; } });
12
+ var propagation_1 = require("./propagation");
13
+ Object.defineProperty(exports, "injectTraceContext", { enumerable: true, get: function () { return propagation_1.injectTraceContext; } });
14
+ Object.defineProperty(exports, "extractTraceContext", { enumerable: true, get: function () { return propagation_1.extractTraceContext; } });
15
+ Object.defineProperty(exports, "traceparentHeadersHook", { enumerable: true, get: function () { return propagation_1.traceparentHeadersHook; } });
16
+ var redaction_1 = require("./redaction");
17
+ Object.defineProperty(exports, "redact", { enumerable: true, get: function () { return redaction_1.redact; } });
18
+ Object.defineProperty(exports, "maskString", { enumerable: true, get: function () { return redaction_1.maskString; } });
19
+ Object.defineProperty(exports, "isSensitiveKey", { enumerable: true, get: function () { return redaction_1.isSensitiveKey; } });
20
+ Object.defineProperty(exports, "REDACTED", { enumerable: true, get: function () { return redaction_1.REDACTED; } });
21
+ var attributes_1 = require("./attributes");
22
+ Object.defineProperty(exports, "sanitizeAttributes", { enumerable: true, get: function () { return attributes_1.sanitizeAttributes; } });
23
+ Object.defineProperty(exports, "sanitizeStatement", { enumerable: true, get: function () { return attributes_1.sanitizeStatement; } });
24
+ Object.defineProperty(exports, "ALLOWED_ATTRIBUTES", { enumerable: true, get: function () { return attributes_1.ALLOWED_ATTRIBUTES; } });
25
+ Object.defineProperty(exports, "hashIp", { enumerable: true, get: function () { return attributes_1.hashIp; } });
26
+ var sanitizing_exporter_1 = require("./sanitizing-exporter");
27
+ Object.defineProperty(exports, "SanitizingSpanExporter", { enumerable: true, get: function () { return sanitizing_exporter_1.SanitizingSpanExporter; } });
28
+ Object.defineProperty(exports, "sanitizeSpan", { enumerable: true, get: function () { return sanitizing_exporter_1.sanitizeSpan; } });
29
+ var log_context_1 = require("./log-context");
30
+ Object.defineProperty(exports, "runWithLogContext", { enumerable: true, get: function () { return log_context_1.runWithLogContext; } });
31
+ Object.defineProperty(exports, "getLogContext", { enumerable: true, get: function () { return log_context_1.getLogContext; } });
32
+ var sdk_1 = require("./sdk");
33
+ Object.defineProperty(exports, "startTelemetry", { enumerable: true, get: function () { return sdk_1.startTelemetry; } });
34
+ Object.defineProperty(exports, "shutdownTelemetry", { enumerable: true, get: function () { return sdk_1.shutdownTelemetry; } });
35
+ Object.defineProperty(exports, "getTelemetry", { enumerable: true, get: function () { return sdk_1.getTelemetry; } });
36
+ var config_1 = require("./config");
37
+ Object.defineProperty(exports, "readConfig", { enumerable: true, get: function () { return config_1.readConfig; } });
38
+ Object.defineProperty(exports, "DEFAULT_OTLP_ENDPOINT", { enumerable: true, get: function () { return config_1.DEFAULT_OTLP_ENDPOINT; } });
39
+ var logger_1 = require("./logger");
40
+ Object.defineProperty(exports, "JsonLogger", { enumerable: true, get: function () { return logger_1.JsonLogger; } });
41
+ Object.defineProperty(exports, "createLogger", { enumerable: true, get: function () { return logger_1.createLogger; } });
42
+ Object.defineProperty(exports, "parseLogLevels", { enumerable: true, get: function () { return logger_1.parseLogLevels; } });
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uDAA0F;AAAjF,mHAAA,eAAe,OAAA;AAAE,oHAAA,gBAAgB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAE7D,uDAA2F;AAAlF,4HAAA,wBAAwB,OAAA;AAAE,8GAAA,UAAU,OAAA;AAAE,mHAAA,eAAe,OAAA;AAC9D,6CAAgG;AAAvF,iHAAA,kBAAkB,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAAE,qHAAA,sBAAsB,OAAA;AAExE,yCAA2E;AAAlE,mGAAA,MAAM,OAAA;AAAE,uGAAA,UAAU,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,qGAAA,QAAQ,OAAA;AACrD,2CAAiG;AAAxF,gHAAA,kBAAkB,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AAAE,gHAAA,kBAAkB,OAAA;AAAE,oGAAA,MAAM,OAAA;AAC1E,6DAA6E;AAApE,6HAAA,sBAAsB,OAAA;AAAE,mHAAA,YAAY,OAAA;AAC7C,6CAAiE;AAAxD,gHAAA,iBAAiB,OAAA;AAAE,4GAAA,aAAa,OAAA;AAEzC,6BAAwE;AAA/D,qGAAA,cAAc,OAAA;AAAE,wGAAA,iBAAiB,OAAA;AAAE,mGAAA,YAAY,OAAA;AAExD,mCAA6D;AAApD,oGAAA,UAAU,OAAA;AAAE,+GAAA,qBAAqB,OAAA;AAE1C,mCAAoE;AAA3D,oGAAA,UAAU,OAAA;AAAE,sGAAA,YAAY,OAAA;AAAE,wGAAA,cAAc,OAAA"}
@@ -0,0 +1,8 @@
1
+ /** Campi che ogni riga di log dello stesso comando eredita (`cmd`, `juridicalId`). */
2
+ export interface LogContext {
3
+ cmd?: string;
4
+ juridicalId?: string;
5
+ }
6
+ export declare function runWithLogContext<T>(ctx: LogContext, fn: () => T): T;
7
+ export declare function getLogContext(): LogContext;
8
+ //# sourceMappingURL=log-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-context.d.ts","sourceRoot":"","sources":["../src/log-context.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEpE;AAED,wBAAgB,aAAa,IAAI,UAAU,CAE1C"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runWithLogContext = runWithLogContext;
4
+ exports.getLogContext = getLogContext;
5
+ const async_hooks_1 = require("async_hooks");
6
+ const storage = new async_hooks_1.AsyncLocalStorage();
7
+ function runWithLogContext(ctx, fn) {
8
+ return storage.run({ ...storage.getStore(), ...ctx }, fn);
9
+ }
10
+ function getLogContext() {
11
+ return storage.getStore() ?? {};
12
+ }
13
+ //# sourceMappingURL=log-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-context.js","sourceRoot":"","sources":["../src/log-context.ts"],"names":[],"mappings":";;AAUA,8CAEC;AAED,sCAEC;AAhBD,6CAAgD;AAQhD,MAAM,OAAO,GAAG,IAAI,+BAAiB,EAAc,CAAC;AAEpD,SAAgB,iBAAiB,CAAI,GAAe,EAAE,EAAW;IAC/D,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,SAAgB,aAAa;IAC3B,OAAO,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type LoggerService } from '@nestjs/common';
2
+ export { JsonLogger, parseLogLevels, DEFAULT_LOG_LEVELS } from './json-logger';
3
+ export type { JsonLoggerOptions } from './json-logger';
4
+ /**
5
+ * Il logger di `main.ts`: `LOG_FORMAT=json` → `JsonLogger`, altrimenti (di serie, `text`) il logger di testo di Nest.
6
+ *
7
+ * const app = await NestFactory.create(AppModule, { logger: createLogger('hr') });
8
+ */
9
+ export declare function createLogger(service: string, env?: NodeJS.ProcessEnv): LoggerService;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGnE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,aAAa,CAMjG"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_LOG_LEVELS = exports.parseLogLevels = exports.JsonLogger = void 0;
4
+ exports.createLogger = createLogger;
5
+ const common_1 = require("@nestjs/common");
6
+ const json_logger_1 = require("./json-logger");
7
+ var json_logger_2 = require("./json-logger");
8
+ Object.defineProperty(exports, "JsonLogger", { enumerable: true, get: function () { return json_logger_2.JsonLogger; } });
9
+ Object.defineProperty(exports, "parseLogLevels", { enumerable: true, get: function () { return json_logger_2.parseLogLevels; } });
10
+ Object.defineProperty(exports, "DEFAULT_LOG_LEVELS", { enumerable: true, get: function () { return json_logger_2.DEFAULT_LOG_LEVELS; } });
11
+ /**
12
+ * Il logger di `main.ts`: `LOG_FORMAT=json` → `JsonLogger`, altrimenti (di serie, `text`) il logger di testo di Nest.
13
+ *
14
+ * const app = await NestFactory.create(AppModule, { logger: createLogger('hr') });
15
+ */
16
+ function createLogger(service, env = process.env) {
17
+ json_logger_1.JsonLogger.defaultService = service;
18
+ if ((env.LOG_FORMAT ?? 'text').toLowerCase() === 'json') {
19
+ return new json_logger_1.JsonLogger({ service, levels: (0, json_logger_1.parseLogLevels)(env.APP_LOGGER_LEVEL) });
20
+ }
21
+ return new common_1.ConsoleLogger({ logLevels: (0, json_logger_1.parseLogLevels)(env.APP_LOGGER_LEVEL) });
22
+ }
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":";;;AAWA,oCAMC;AAjBD,2CAAmE;AACnE,+CAA2D;AAE3D,6CAA+E;AAAtE,yGAAA,UAAU,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,iHAAA,kBAAkB,OAAA;AAGvD;;;;GAIG;AACH,SAAgB,YAAY,CAAC,OAAe,EAAE,MAAyB,OAAO,CAAC,GAAG;IAChF,wBAAU,CAAC,cAAc,GAAG,OAAO,CAAC;IACpC,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QACxD,OAAO,IAAI,wBAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAA,4BAAc,EAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,IAAI,sBAAa,CAAC,EAAE,SAAS,EAAE,IAAA,4BAAc,EAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { LogLevel, LoggerService } from '@nestjs/common';
2
+ type Write = (line: string) => void;
3
+ export declare const DEFAULT_LOG_LEVELS: readonly LogLevel[];
4
+ /** `APP_LOGGER_LEVEL`: elenco separato da virgole (`log,error,warn`), `none` per spegnere. */
5
+ export declare function parseLogLevels(raw: string | undefined, fallback?: readonly LogLevel[]): LogLevel[];
6
+ export interface JsonLoggerOptions {
7
+ /** Nome del servizio nel campo `service`. Di serie `OTEL_SERVICE_NAME` o `unknown`. */
8
+ service?: string;
9
+ levels?: readonly LogLevel[];
10
+ write?: Write;
11
+ clock?: () => Date;
12
+ }
13
+ /**
14
+ * Una riga JSON per evento su stdout, con gli stessi campi in tutti i servizi Node:
15
+ * `level`, `ts`, `service`, `msg`, `trace_id`, `span_id`, `cmd`, `juridicalId` (solo id), più `context` (nome del logger di Nest)
16
+ * ed eventuali campi di un messaggio-oggetto. Ogni stringa e ogni oggetto passano dalla redazione: niente email, codici
17
+ * fiscali, IBAN, token, né i valori di chiavi come `password`, `authorization`, `body`.
18
+ * `trace_id`/`span_id` vengono dallo span attivo; `cmd`/`juridicalId` dal contesto del comando NATS in corso.
19
+ */
20
+ export declare class JsonLogger implements LoggerService {
21
+ /** Impostato da `TelemetryModule.forRoot({ service })`. */
22
+ static defaultService: string | undefined;
23
+ private levels;
24
+ private readonly service?;
25
+ private readonly write;
26
+ private readonly clock;
27
+ constructor(options?: JsonLoggerOptions);
28
+ setLogLevels(levels: LogLevel[]): void;
29
+ log(message: unknown, ...rest: unknown[]): void;
30
+ error(message: unknown, ...rest: unknown[]): void;
31
+ warn(message: unknown, ...rest: unknown[]): void;
32
+ debug(message: unknown, ...rest: unknown[]): void;
33
+ verbose(message: unknown, ...rest: unknown[]): void;
34
+ fatal(message: unknown, ...rest: unknown[]): void;
35
+ private emit;
36
+ private build;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=json-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-logger.d.ts","sourceRoot":"","sources":["../../src/logger/json-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK9D,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAGpC,eAAO,MAAM,kBAAkB,EAAE,SAAS,QAAQ,EAAsC,CAAC;AASzF,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,GAAE,SAAS,QAAQ,EAAuB,GAAG,QAAQ,EAAE,CAUtH;AAED,MAAM,WAAW,iBAAiB;IAChC,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;;;;GAMG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC9C,2DAA2D;IAC3D,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1C,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;gBAEvB,OAAO,GAAE,iBAAsB;IAO3C,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI;IAItC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAG/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGjD,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGhD,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGjD,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAGnD,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAIjD,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,KAAK;CA2Cd"}