@glassops/scribe 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,35 +20,42 @@ This ensures production, staging, and development never collide, and that multi
20
20
  ### Structured, operationally meaningful logs
21
21
 
22
22
  - JSON‑structured entries with timestamps.
23
- - Dailyrotated files with configurable retention.
24
- - Semantic log levels (critical, change, http, etc.) mapped to dedicated transports.
25
- - Requestscoped metadata (tenant, service, environment, user, correlationId, requestId).
23
+ - Daily-rotated files with configurable retention (default: 14 days).
24
+ - Semantic log levels (`critical`, `change`, `http`, etc.) mapped to dedicated transports.
25
+ - Request-scoped metadata (`tenant`, `service`, `environment`, `user`, `correlationId`, `requestId`).
26
26
 
27
27
  ### Deep, case‑insensitive redaction
28
28
 
29
29
  Sensitive keys are removed at any depth, regardless of casing:
30
30
 
31
- - password, Password, PASSWORD.
32
- - authorization, Authorization, etc.
31
+ - `password`, `Password`, `PASSWORD`
32
+ - `authorization`, `Authorization`, etc.
33
33
 
34
- Circular references become "[Circular]". Buffers become "[Binary]".
34
+ Other behaviors:
35
+
36
+ - Circular references → `"[Circular]"`
37
+ - Buffers → `"[Binary]"`
35
38
 
36
39
  ### Transport‑agnostic architecture
37
40
 
38
41
  File transports are enabled by default, but Scribe supports:
39
42
 
40
- - Console‑only mode.
41
- - Cloud‑only mode.
42
- - Hybrid mode.
43
+ - Console‑only mode
44
+ - Cloud‑only mode
45
+ - Hybrid mode
43
46
 
44
- Using:
47
+ Configurable through:
45
48
 
46
49
  - `disableFileTransports`
47
50
  - `extraTransports`
48
51
 
49
52
  ### Pure, re‑entrant API
50
53
 
51
- No global state, no shared mutable configuration, no hidden defaults. Every logger instance is fully deterministic and scoped.
54
+ - No global state
55
+ - No shared mutable configuration
56
+ - No hidden defaults
57
+
58
+ Every logger instance is fully deterministic and scoped.
52
59
 
53
60
  ## Installation
54
61
 
@@ -60,18 +67,16 @@ npm install @glassops/scribe
60
67
 
61
68
  Scribe is built around three principles:
62
69
 
63
- - Identity is explicit every log entry carries a complete scope describing tenant, environment, service, and correlation identifiers.
64
- - Streams are semantic — incidents, changes, HTTP traffic, and application logs are treated as distinct operational categories.
65
- - Safety is mandatory — redaction, sanitization, and directory grammar are enforced before logs reach any transport.
70
+ - **Identity is explicit**: Every log entry carries a complete scope describing tenant, environment, service, and correlation identifiers.
71
+ - **Streams are semantic**: Incidents, changes, HTTP traffic, and application logs are treated as distinct operational categories.
72
+ - **Safety is mandatory**: Redaction, sanitization, and directory grammar are enforced before logs reach any transport.
66
73
 
67
74
  ## Directory structure
68
75
 
69
- Scribe derives the log directory from the LoggerScope:
76
+ All segments of the directory path are sanitized to prevent traversal or invalid characters.
70
77
 
71
- With service: `<target>/<service>/<tenant>`
72
- Without service: `<target>/<tenant>/<environment>`
73
-
74
- All segments are sanitized to prevent traversal or invalid characters.
78
+ - With service: `<target>/<service>/<tenant>`
79
+ - Without service: `<target>/<tenant>/<environment>`
75
80
 
76
81
  ## Usage
77
82
 
@@ -92,20 +97,24 @@ const directory = createDirectory("/var/logs", {
92
97
  ```ts
93
98
  import { createLogger } from "@glassops/scribe";
94
99
 
95
- const logger = createLogger(directory, {
96
- tenant: "acme",
97
- environment: "production",
98
- service: "billing",
99
- correlationId: "abc123",
100
- }, {
101
- level: "info",
102
- requestLog: "requests-%DATE%.log",
103
- appLog: "app-%DATE%.log",
104
- incidentLog: "incident-%DATE%.log",
105
- changeLog: "change-%DATE%.log",
106
- logToConsole: true,
107
- sensitiveKeys: ["password", "token"],
108
- });
100
+ const logger = createLogger(
101
+ directory,
102
+ {
103
+ tenant: "acme",
104
+ environment: "production",
105
+ service: "billing",
106
+ correlationId: "abc123",
107
+ },
108
+ {
109
+ level: "info",
110
+ requestLog: "requests-%DATE%.log",
111
+ appLog: "app-%DATE%.log",
112
+ incidentLog: "incident-%DATE%.log",
113
+ changeLog: "change-%DATE%.log",
114
+ logToConsole: true,
115
+ sensitiveKeys: ["password", "token"],
116
+ }
117
+ );
109
118
  ```
110
119
 
111
120
  ## Logging methods
@@ -124,47 +133,62 @@ Example:
124
133
  ```ts
125
134
  logger.logInfo("User updated profile", {
126
135
  userId: "123",
127
- password: "secret", // redacted
136
+ password: "secret", // redacted automatically
128
137
  });
129
138
  ```
130
139
 
131
140
  ## HTTP logging (Morgan integration)
132
141
 
142
+ Scribe supports direct integration with Morgan. ANSI sequences are stripped before writing to ensure clean JSON logs:
143
+
133
144
  ```ts
134
145
  app.use(morgan("combined", { stream: logger.createLoggerStream() }));
135
146
  ```
136
147
 
137
- ANSI sequences are stripped before writing, ensuring clean machine‑readable logs.
138
-
139
148
  ## Redaction behavior
140
149
 
141
- Scribe removes sensitive keys at any depth:
150
+ - Case-insensitive key matching
151
+ - Nested sensitive fields are recursively redacted
152
+ - **Circular references**: `"[Circular]"`
153
+ - **Buffers**: `"[Binary]"`
154
+
155
+ ## Scoping
156
+
157
+ You can derive a new logger with additional metadata:
142
158
 
143
159
  ```ts
144
- {
145
- password: "[REDACTED]",
146
- nested: {
147
- token: "[REDACTED]"
148
- }
149
- }
160
+ const userLogger = await logger.scope({ user: "steven" });
161
+ userLogger.logInfo("User action");
150
162
  ```
151
163
 
152
- - Case‑insensitive matching
153
- - Circular references → "[Circular]"
154
- - Buffers → "[Binary]"
164
+ Produces a new logger instance with merged scope. Logger directory may change if scope affects service or environment.
155
165
 
156
- ## Scoping
166
+ Existing transports are closed and rebuilt automatically if necessary.
157
167
 
158
- You can derive a new logger with additional metadata:
159
- const userLogger = logger.scope({ user: "steven" });
160
- userLogger.logInfo("User action");
168
+ ## Logger API
169
+
170
+ ```ts
171
+ interface ScribeLogger {
172
+ logError(error: string | Error, context?: Record<string, unknown>): void;
173
+ logWarn(message: string, context?: Record<string, unknown>): void;
174
+ logInfo(message: string, context?: Record<string, unknown>): void;
175
+ logDebug(message: string, context?: Record<string, unknown>): void;
176
+ logIncident(message: string, context?: Record<string, unknown>): void;
177
+ logChange(message: string, context?: Record<string, unknown>): void;
178
+ createLoggerStream(): { write: (message: string) => void };
179
+ scope(partial: Partial<LoggerScope>): Promise<void>;
180
+ close(): Promise<void>;
181
+ logger: Logger;
182
+ }
183
+ ```
161
184
 
162
- This produces a new logger instance with merged scope.
185
+ - `createLoggerStream()`: Returns a Morgan-compatible writable stream.
186
+ - `scope()`: Returns a `Promise<void>`; merges partial metadata into current logger.
187
+ - `close()`: Gracefully shuts down transports.
188
+ - `logger`: Exposes underlying Winston Logger instance.
163
189
 
164
190
  ## Transport configuration
165
191
 
166
- Scribe supports file‑based, console‑only, cloud‑only, and hybrid modes.
167
-
168
192
  ```ts
169
193
  interface LoggerOptions {
170
194
  level: LogLevel;
@@ -175,7 +199,6 @@ interface LoggerOptions {
175
199
  logToConsole?: boolean;
176
200
  sensitiveKeys?: string[];
177
201
  retention?: string;
178
-
179
202
  disableFileTransports?: boolean;
180
203
  extraTransports?: Transport[];
181
204
  }
@@ -191,11 +214,13 @@ interface LoggerOptions {
191
214
  - `change`
192
215
  - `debug`
193
216
 
217
+ Each level is treated as a separate operational stream rather than a severity threshold.
218
+
194
219
  ## Build and publish
195
220
 
196
- Scribe uses a strict file whitelist and a deterministic build pipeline.
221
+ Scribe uses a strict file whitelist and deterministic build pipeline.
197
222
 
198
- ## Scripts
223
+ ### Scripts
199
224
 
200
225
  ```json
201
226
  {
@@ -207,13 +232,13 @@ Scribe uses a strict file whitelist and a deterministic build pipeline.
207
232
  }
208
233
  ```
209
234
 
210
- Prepack ensures `dist/` is always built before:
235
+ Prepack ensures dist/ is always built before:
211
236
 
212
237
  - `npm publish`
213
238
  - `npm publish --dry-run`
214
239
  - `npm pack`
215
240
 
216
- Files included in the package
241
+ Files included in the package:
217
242
 
218
243
  ```json
219
244
  {
@@ -221,29 +246,21 @@ Files included in the package
221
246
  }
222
247
  ```
223
248
 
224
- This guarantees only compiled output and documentation are published.
249
+ Guarantees only compiled output and documentation are published.
225
250
 
226
251
  ## Design rationale
227
252
 
228
- - Directory grammar prevents crossenvironment and crosstenant collisions.
253
+ - Directory grammar prevents cross-environment and cross-tenant collisions.
229
254
  - Semantic log levels allow operational tooling to treat incidents, changes, and HTTP traffic as distinct streams.
230
- - Deep, caseinsensitive redaction prevents credential leakage.
231
- - Pure, reentrant API ensures deterministic behavior across multitenant and multiservice deployments.
255
+ - Deep, case-insensitive redaction prevents credential leakage.
256
+ - Pure, re-entrant API ensures deterministic behavior across multi-tenant and multi-service deployments.
232
257
  - Daily rotation keeps log files predictable for ingestion pipelines.
233
- - Transportagnostic design supports file, console, cloud, and hybrid logging.
258
+ - Transport-agnostic design supports file, console, cloud, and hybrid logging.
234
259
 
235
260
  ## License
236
261
 
237
262
  Copyright [2026] [GlassOps Limited]
238
263
 
239
- Licensed under the Apache License, Version 2.0 (the ["License"](LICENSE));
240
- you may not use this file except in compliance with the License.
241
- You may obtain a copy of the License at
242
-
243
- <http://www.apache.org/licenses/LICENSE-2.0>
264
+ Licensed under the Apache License, Version 2.0 (["License"](LICENSE)).
244
265
 
245
- Unless required by applicable law or agreed to in writing, software
246
- distributed under the License is distributed on an "AS IS" BASIS,
247
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
248
- See the License for the specific language governing permissions and
249
- limitations under the License.
266
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.
package/dist/types.d.ts CHANGED
@@ -6,7 +6,22 @@
6
6
  /* --------------------------------------------------------------------------
7
7
  |* NPM Dependencies
8
8
  \* -------------------------------------------------------------------------- */
9
- import type Transport from "winston-transport";
9
+ import type { Logger } from 'winston';
10
+ import type Transport from 'winston-transport';
11
+ export interface ScribeLogger {
12
+ logError: (error: string | Error, context?: Record<string, unknown>) => void;
13
+ logWarn: (message: string, context?: Record<string, unknown>) => void;
14
+ logInfo: (message: string, context?: Record<string, unknown>) => void;
15
+ logDebug: (message: string, context?: Record<string, unknown>) => void;
16
+ logIncident: (message: string, context?: Record<string, unknown>) => void;
17
+ logChange: (message: string, context?: Record<string, unknown>) => void;
18
+ createLoggerStream: () => {
19
+ write: (message: string) => void;
20
+ };
21
+ scope: (partial: Partial<LoggerScope>) => Promise<void>;
22
+ close: () => Promise<void>;
23
+ logger: Logger;
24
+ }
10
25
  /**
11
26
  * Describes the identity of the log stream. Every log entry is tagged with
12
27
  * these fields to ensure deterministic partitioning across tenants,
@@ -62,5 +77,5 @@ export interface LoggerOptions {
62
77
  * Supported semantic log levels. These map directly to Scribe's custom
63
78
  * level hierarchy and determine which transport receives each log entry.
64
79
  */
65
- export type LogLevel = "critical" | "error" | "warn" | "info" | "http" | "change" | "debug";
80
+ export type LogLevel = 'critical' | 'error' | 'warn' | 'info' | 'http' | 'change' | 'debug';
66
81
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;gFAOgF;AAChF,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAK/C;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAKD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC;IAC9B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACnC;AAKD;;;GAGG;AACH,MAAM,MAAM,QAAQ,GACd,UAAU,GACV,OAAO,GACP,MAAM,GACN,MAAM,GACN,MAAM,GACN,QAAQ,GACR,OAAO,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;gFAOgF;AAChF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAK/C,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC7E,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACvE,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC1E,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACxE,kBAAkB,EAAE,MAAM;QAAE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IAC/D,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAClB;AAKD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAKD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC;IAC9B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACnC;AAKD;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassops/scribe",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Deterministic, multi-tenant logging subsystem for GlassOps services.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "GlassOps Limited",