@monochromatic-dev/module-logger 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +58 -12
- package/dist/final/neutral/browser.d.mts +60 -0
- package/dist/final/neutral/browser.mjs +1 -0
- package/dist/final/neutral/index.d.mts +366 -572
- package/dist/final/neutral/index.mjs +2 -3
- package/dist/final/neutral/indexed-db-hsIfv7Cv.mjs +2 -0
- package/dist/final/neutral/types-BkkBXgY3.d.mts +76 -0
- package/dist/final/node/file-CRGb1hDK.mjs +1 -0
- package/dist/final/node/index.d.mts +366 -572
- package/dist/final/node/index.mjs +3 -3
- package/dist/final/node/node.d.mts +103 -0
- package/dist/final/node/node.mjs +1 -0
- package/dist/final/node/types-BkkBXgY3.d.mts +76 -0
- package/package.json +19 -5
- package/src/artifact-platform-split.unit.test.ts +140 -0
- package/src/browser.ts +14 -0
- package/src/create-logger.ts +249 -151
- package/src/create-logger.unit.test.ts +527 -75
- package/src/default-sinks.neutral.ts +34 -0
- package/src/default-sinks.node.ts +32 -0
- package/src/error-format.ts +23 -23
- package/src/index.ts +2 -0
- package/src/logger.ts +23 -50
- package/src/node.ts +23 -0
- package/src/sink/console-control-chars.ts +64 -64
- package/src/sink/console-control-chars.unit.test.ts +14 -14
- package/src/sink/console.ts +194 -194
- package/src/sink/console.unit.test.ts +18 -18
- package/src/sink/file.ts +136 -140
- package/src/sink/file.unit.test.ts +19 -26
- package/src/sink/index.ts +4 -7
- package/src/sink/indexed-db-util.ts +42 -42
- package/src/sink/indexed-db.browser.test.ts +7 -7
- package/src/sink/indexed-db.ts +109 -109
- package/src/sink/indexed-db.unit.test.ts +5 -13
- package/src/sink/local-storage-key.ts +73 -73
- package/src/sink/local-storage-key.unit.test.ts +8 -8
- package/src/sink/local-storage-quota.ts +37 -37
- package/src/sink/local-storage-quota.unit.test.ts +8 -8
- package/src/sink/local-storage-store.ts +113 -113
- package/src/sink/local-storage-store.unit.test.ts +35 -35
- package/src/sink/local-storage.ts +72 -72
- package/src/sink/local-storage.unit.test.ts +27 -27
- package/src/sink/noop.ts +20 -20
- package/src/sink/noop.unit.test.ts +1 -1
- package/src/sink/opfs.browser.test.ts +7 -7
- package/src/sink/opfs.ts +62 -62
- package/src/sink/opfs.unit.test.ts +5 -13
- package/src/sink/record-buffer.ts +84 -84
- package/src/sink/record-buffer.unit.test.ts +20 -20
- package/src/sink/session-storage-quota.ts +34 -34
- package/src/sink/session-storage-quota.unit.test.ts +8 -8
- package/src/sink/session-storage-store.ts +72 -72
- package/src/sink/session-storage.ts +48 -48
- package/src/sink/session-storage.unit.test.ts +39 -39
- package/src/sink/web-storage-quota-error.ts +22 -22
- package/src/sink/web-storage-quota-error.unit.test.ts +2 -2
- package/src/sink/web-storage-runtime.ts +24 -24
- package/src/startup.unit.test.ts +18 -18
- package/src/tagged.ts +35 -35
- package/src/tagged.unit.test.ts +8 -8
- package/src/types.ts +39 -39
|
@@ -1,137 +1,89 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname as dirname$1, join as join$1 } from "node:path";
|
|
3
|
-
//#region src/types.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Log severity levels ordered from least to most severe.
|
|
6
|
-
*/
|
|
7
|
-
type Level = "debug" | "error" | "fatal" | "info" | "trace" | "warn";
|
|
8
|
-
/**
|
|
9
|
-
* Structured log record written to sinks.
|
|
10
|
-
*/
|
|
11
|
-
type LogRecord = {
|
|
12
|
-
readonly level: Level;
|
|
13
|
-
readonly message: string;
|
|
14
|
-
readonly timestamp: number;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Optional drain hook for sinks that buffer records internally.
|
|
18
|
-
* Called via logger-level {@link Logger.flush} to force buffered work
|
|
19
|
-
* through before a process exit, critical error boundary, or assertion.
|
|
20
|
-
*
|
|
21
|
-
* Always async: sinks whose drain is synchronous return an
|
|
22
|
-
* already-resolved promise so callers `await` uniformly. A `void` arm is
|
|
23
|
-
* not used; under the `no-optional-escape` rule `T | void` is a banned
|
|
24
|
-
* fake-optional encoding, and there is no real synchronous value to carry.
|
|
25
|
-
*/
|
|
26
|
-
type SinkFlush = () => Promise<void>;
|
|
27
|
-
/**
|
|
28
|
-
* Verification function that checks if a sink backend is available.
|
|
29
|
-
* May run setup side effects (resolving a log path, opening a writable
|
|
30
|
-
* stream) and reports whether the backend is usable. A sink whose
|
|
31
|
-
* verification resolves `false` (or rejects) is dropped by the logger and
|
|
32
|
-
* receives no further records.
|
|
33
|
-
*
|
|
34
|
-
* Always async, matching `write` and `flush`: a synchronous check returns an
|
|
35
|
-
* already-resolved promise (`Promise.resolve(check)`) so the logger awaits
|
|
36
|
-
* verification uniformly with no sync/async branch.
|
|
37
|
-
*/
|
|
38
|
-
type Verify = () => Promise<boolean>;
|
|
39
|
-
/**
|
|
40
|
-
* Sink that receives log records. A sink is a self-describing adapter: it
|
|
41
|
-
* carries everything the logger must know to use it, namely how to
|
|
42
|
-
* `verify` its backend is available, how to `write` a record, and
|
|
43
|
-
* optionally how to `flush` buffered work. Holding `verify` on the sink
|
|
44
|
-
* (rather than as a sibling export the logger pairs by hand) lets the
|
|
45
|
-
* logger treat a registry as a plain `Sink[]` and lets a test supply one
|
|
46
|
-
* self-contained fake.
|
|
47
|
-
*
|
|
48
|
-
* Sinks that buffer records (e.g. microtask-batched console) may
|
|
49
|
-
* expose a `flush` hook so callers can force emission on demand.
|
|
50
|
-
*
|
|
51
|
-
* `write` is always async: a synchronous sink does its work eagerly and
|
|
52
|
-
* returns an already-resolved promise, so the logger observes a uniform
|
|
53
|
-
* `Promise<void>`. A rejected write is handled per sink and does not
|
|
54
|
-
* disable the backend; only a failed `verify` drops a sink. A `void` arm
|
|
55
|
-
* is not used, for the reason stated on {@link SinkFlush}.
|
|
56
|
-
*/
|
|
57
|
-
type Sink = {
|
|
58
|
-
readonly flush?: SinkFlush;
|
|
59
|
-
readonly verify: Verify;
|
|
60
|
-
readonly write: (record: LogRecord) => Promise<void>;
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* Logger interface with 6 log levels plus `flush` for startup and sink drains.
|
|
64
|
-
* `flush()` resolves once startup verification has completed, tracked sink
|
|
65
|
-
* writes have settled, and every available sink's own {@link SinkFlush} hook
|
|
66
|
-
* has settled. Safe to call even when no sink buffers.
|
|
67
|
-
*/
|
|
68
|
-
type Logger = {
|
|
69
|
-
readonly debug: (message: string) => void;
|
|
70
|
-
readonly error: (message: string) => void;
|
|
71
|
-
readonly fatal: (message: string) => void;
|
|
72
|
-
readonly flush: () => Promise<void>;
|
|
73
|
-
readonly info: (message: string) => void;
|
|
74
|
-
readonly trace: (message: string) => void;
|
|
75
|
-
readonly warn: (message: string) => void;
|
|
76
|
-
};
|
|
77
|
-
//#endregion
|
|
1
|
+
import { a as SinkFlush, i as Sink, n as LogRecord, o as Verify, r as Logger, t as Level } from "./types-BkkBXgY3.mjs";
|
|
78
2
|
//#region src/create-logger.d.ts
|
|
79
3
|
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
4
|
+
Default `flush()` deadline in milliseconds. Measured on 2026-09-06: a
|
|
5
|
+
default logger flushing 100 records through the console and file sinks
|
|
6
|
+
settles in about 2 ms locally, so this leaves three orders of magnitude for
|
|
7
|
+
a slow but working backend while still bounding shutdown on a wedged one.
|
|
8
|
+
Override per logger through the `flushDeadlineMs` option of
|
|
9
|
+
{@link createLogger}.
|
|
10
|
+
*/
|
|
87
11
|
export declare const DEFAULT_FLUSH_DEADLINE_MS = 5e3;
|
|
88
12
|
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
13
|
+
Default per-sink `verify()` time limit in milliseconds. Measured on
|
|
14
|
+
2026-09-06: the default logger's five shipped verifies complete together in
|
|
15
|
+
about 2.4 ms locally, so this leaves three orders of magnitude for a slow
|
|
16
|
+
but working backend probe (a network filesystem, a busy IndexedDB) while a
|
|
17
|
+
verify that never answers (a hung mount, an IndexedDB open blocked by
|
|
18
|
+
another tab) can no longer stall startup. Override per logger through the
|
|
19
|
+
`verifyTimeoutMs` option of {@link createLogger}.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_VERIFY_TIMEOUT_MS = 5e3;
|
|
22
|
+
/**
|
|
23
|
+
Most records the logger buffers before its sinks have verified. Startup
|
|
24
|
+
lasts at most {@link DEFAULT_VERIFY_TIMEOUT_MS}, so this bounds the memory a
|
|
25
|
+
burst during that window can claim; on overflow the oldest buffered record
|
|
26
|
+
is dropped so the newest (usually most diagnostic) context survives, and
|
|
27
|
+
one synthetic `warn` record naming the dropped count is written to every
|
|
28
|
+
available sink once initialization completes.
|
|
29
|
+
*/
|
|
30
|
+
export declare const STARTUP_BUFFER_CAP = 1e4;
|
|
31
|
+
/**
|
|
32
|
+
Builds a multi-sink logger over the supplied sink adapters. All
|
|
33
|
+
orchestration (per-sink availability, startup buffering and replay,
|
|
34
|
+
in-flight write tracking, and flush) lives here; the exported default
|
|
35
|
+
`logger` is just this factory applied to the default sink set, and tests
|
|
36
|
+
apply it to fake sinks to exercise the orchestration directly.
|
|
37
|
+
|
|
38
|
+
Verification runs eagerly at construction and never blocks callers:
|
|
39
|
+
records emitted while an async sink is still verifying buffer internally
|
|
40
|
+
and replay to that sink the moment it verifies. Every sink verifies
|
|
41
|
+
concurrently under its own time limit (`verifyTimeoutMs`, default
|
|
42
|
+
{@link DEFAULT_VERIFY_TIMEOUT_MS}), so one backend that never answers
|
|
43
|
+
cannot starve the others or keep the logger from initializing. A sink
|
|
44
|
+
whose `verify` resolves `false`, throws, or runs past the limit is dropped
|
|
45
|
+
and receives no records; an answer that arrives after the limit is
|
|
46
|
+
ignored. A rejected `write` is the sink's own concern and does not disable
|
|
47
|
+
the backend.
|
|
48
|
+
|
|
49
|
+
`flush()` always resolves: one deadline (`flushDeadlineMs`, default
|
|
50
|
+
{@link DEFAULT_FLUSH_DEADLINE_MS}) wraps startup verification, the
|
|
51
|
+
in-flight write drain, and every sink flush hook together. When it elapses
|
|
52
|
+
the logger reports one breadcrumb, abandons the tracked writes from its
|
|
53
|
+
view (the sinks expose no cancellation, so the underlying work continues),
|
|
54
|
+
and resolves, so a wedged backend cannot hang a shutdown.
|
|
55
|
+
|
|
56
|
+
@param sinks - Sink adapters to fan each record out to, in priority order.
|
|
57
|
+
|
|
58
|
+
@param flushDeadlineMs - Milliseconds one `flush()` may take before it
|
|
59
|
+
resolves anyway; raise it for slow but working backends such as network
|
|
60
|
+
filesystems.
|
|
61
|
+
|
|
62
|
+
@param verifyTimeoutMs - Milliseconds one sink's `verify()` may take before
|
|
63
|
+
the sink counts as unavailable; raise it for a slow but working probe.
|
|
64
|
+
|
|
65
|
+
@returns Logger plus its eager `initPromise`; callers need not await
|
|
66
|
+
`initPromise` before logging, since startup records replay on verify.
|
|
67
|
+
|
|
68
|
+
@example
|
|
69
|
+
```ts
|
|
70
|
+
const { logger } = createLogger({ sinks: [createConsoleSink()] });
|
|
71
|
+
logger.info('ready');
|
|
72
|
+
await logger.flush();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
@example
|
|
76
|
+
```ts
|
|
77
|
+
const { logger } = createLogger({
|
|
78
|
+
sinks: [createFileSink()],
|
|
79
|
+
flushDeadlineMs: 30_000,
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
*/
|
|
83
|
+
export declare function createLogger({ sinks, flushDeadlineMs, verifyTimeoutMs }: {
|
|
133
84
|
readonly sinks: readonly Sink[];
|
|
134
85
|
readonly flushDeadlineMs?: number;
|
|
86
|
+
readonly verifyTimeoutMs?: number;
|
|
135
87
|
}): {
|
|
136
88
|
readonly initPromise: Promise<void>;
|
|
137
89
|
readonly logger: Logger;
|
|
@@ -139,310 +91,152 @@ export declare function createLogger({ sinks, flushDeadlineMs }: {
|
|
|
139
91
|
//#endregion
|
|
140
92
|
//#region src/logger.d.ts
|
|
141
93
|
/**
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
94
|
+
Eager readiness promise. Consumers do not need to await this before logging;
|
|
95
|
+
{@link Logger.flush} awaits it internally, and startup records replay to
|
|
96
|
+
async sinks as they become available.
|
|
97
|
+
*/
|
|
146
98
|
export declare const initPromise: Promise<void>;
|
|
147
99
|
/**
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
100
|
+
Multi-sink logger that writes to all available backends.
|
|
101
|
+
Startup records replay to async sinks that verify after the log call.
|
|
102
|
+
Log calls throw only when initialization proves no backend is available,
|
|
103
|
+
which the console sink prevents in every supported runtime.
|
|
104
|
+
|
|
105
|
+
@example
|
|
106
|
+
```ts
|
|
107
|
+
import { logger, } from '\@monochromatic-dev/module-logger/logger';
|
|
108
|
+
|
|
109
|
+
logger.error('unexpected shutdown',);
|
|
110
|
+
await logger.flush();
|
|
111
|
+
```
|
|
112
|
+
*/
|
|
161
113
|
export declare const logger: Logger;
|
|
162
114
|
//#endregion
|
|
163
115
|
//#region src/sink/console.d.ts
|
|
164
116
|
/**
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
117
|
+
Builds a microtask-batched console sink. The pending buffer, schedule flag,
|
|
118
|
+
and memoized verbose detection live in this instance's closure (no
|
|
119
|
+
module-global state), so independent loggers and tests stay isolated with
|
|
120
|
+
no reset hook. Collapses contiguous same-level runs into single `console.*`
|
|
121
|
+
calls, sharply reducing console-panel overhead when an instrumented path
|
|
122
|
+
emits many records per sync frame.
|
|
123
|
+
|
|
124
|
+
@returns Sink that writes formatted lines to `console.*`, except
|
|
125
|
+
process-hosted debug records write to stderr.
|
|
126
|
+
|
|
127
|
+
@example
|
|
128
|
+
```ts
|
|
129
|
+
const { logger } = createLogger({ sinks: [createConsoleSink()] });
|
|
130
|
+
logger.info('server started');
|
|
131
|
+
```
|
|
132
|
+
*/
|
|
181
133
|
declare function createConsoleSink(): Sink;
|
|
182
134
|
//#endregion
|
|
183
|
-
//#region src/error-format.d.ts
|
|
184
|
-
/**
|
|
185
|
-
* Reports a logger-internal caught value without going back through logger
|
|
186
|
-
* sinks, formatting it via {@link caughtValueText}.
|
|
187
|
-
*
|
|
188
|
-
* @param context - Human-readable operation that caught the value.
|
|
189
|
-
*
|
|
190
|
-
* @param error - Caught value to include in the diagnostic.
|
|
191
|
-
*
|
|
192
|
-
* @mutates error - `caughtValueText` may invoke string-conversion hooks.
|
|
193
|
-
*
|
|
194
|
-
* @example
|
|
195
|
-
* ```ts
|
|
196
|
-
* reportLoggerInternalError({
|
|
197
|
-
* context: 'console sink verify failed',
|
|
198
|
-
* error: new Error('blocked'),
|
|
199
|
-
* });
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
declare function reportLoggerInternalError({ context, error }: {
|
|
203
|
-
readonly context: string;
|
|
204
|
-
readonly error: unknown;
|
|
205
|
-
}): void;
|
|
206
|
-
//#endregion
|
|
207
|
-
//#region src/sink/file.d.ts
|
|
208
|
-
/**
|
|
209
|
-
* Sentinel returned by {@link findNodeModulesUp} when no ancestor directory
|
|
210
|
-
* contains a `node_modules`. A unique symbol so it never collides with a real
|
|
211
|
-
* path string the walk might otherwise return, keeping the result free of a
|
|
212
|
-
* banned `string | undefined` union.
|
|
213
|
-
*
|
|
214
|
-
* @example
|
|
215
|
-
* ```ts
|
|
216
|
-
* const dir = await findNodeModulesUp({ cwd, stat, dirname, join });
|
|
217
|
-
* if (dir === NO_NODE_MODULES_FOUND) {
|
|
218
|
-
* // no ancestor project root
|
|
219
|
-
* }
|
|
220
|
-
* ```
|
|
221
|
-
*/
|
|
222
|
-
declare const NO_NODE_MODULES_FOUND: unique symbol;
|
|
223
|
-
/**
|
|
224
|
-
* Walks up from `cwd` to find the nearest ancestor directory containing a
|
|
225
|
-
* `node_modules` subdirectory, returning that subdirectory's absolute path.
|
|
226
|
-
*
|
|
227
|
-
* Using find-up rather than cwd-relative placement keeps log directories
|
|
228
|
-
* anchored to the project the caller actually belongs to. Without this,
|
|
229
|
-
* scripts invoked from build output (e.g. `dist/`) or other stray cwds
|
|
230
|
-
* would create `node_modules/.monochromatic/` inside those trees, polluting
|
|
231
|
-
* shipped artifacts.
|
|
232
|
-
*
|
|
233
|
-
* Exported primarily so `index.unit.test.ts` can exercise both the hit
|
|
234
|
-
* and miss paths directly with an injected `stat`.
|
|
235
|
-
*
|
|
236
|
-
* @param cwd - starting directory for the upward search
|
|
237
|
-
*
|
|
238
|
-
* @param stat - `node:fs/promises` stat (injected so the dynamic
|
|
239
|
-
* import stays in one place)
|
|
240
|
-
*
|
|
241
|
-
* @param dirname - `node:path` dirname
|
|
242
|
-
*
|
|
243
|
-
* @param join - `node:path` join
|
|
244
|
-
*
|
|
245
|
-
* @param reportError - logger fault reporter injected for deterministic tests
|
|
246
|
-
*
|
|
247
|
-
* @returns absolute path to the nearest ancestor `node_modules`, or
|
|
248
|
-
* {@link NO_NODE_MODULES_FOUND} when no ancestor contains one
|
|
249
|
-
*
|
|
250
|
-
* @example
|
|
251
|
-
* ```ts
|
|
252
|
-
* const dir = await findNodeModulesUp({ cwd: process.cwd(), stat, dirname, join });
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
|
-
declare function findNodeModulesUp({ cwd, stat, dirname, join, reportError }: {
|
|
256
|
-
readonly cwd: string;
|
|
257
|
-
readonly stat: typeof stat$1;
|
|
258
|
-
readonly dirname: typeof dirname$1;
|
|
259
|
-
readonly join: typeof join$1;
|
|
260
|
-
readonly reportError?: typeof reportLoggerInternalError;
|
|
261
|
-
}): Promise<string | typeof NO_NODE_MODULES_FOUND>;
|
|
262
|
-
/**
|
|
263
|
-
* Builds a file sink that appends JSONL records to the nearest ancestor
|
|
264
|
-
* `node_modules/.monochromatic/{timestamp}.log.jsonl` (resolved once during
|
|
265
|
-
* verification). The resolved path, the cached `appendFile`, and the
|
|
266
|
-
* verification memo live in this instance's closure (no module-global state),
|
|
267
|
-
* so independent loggers and tests never share a log file or need a reset
|
|
268
|
-
* hook. No `flush` hook: each `write` awaits `appendFile` directly, so there
|
|
269
|
-
* is no buffered state to drain.
|
|
270
|
-
*
|
|
271
|
-
* @returns Sink backed by `node:fs/promises`.
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* ```ts
|
|
275
|
-
* const { logger } = createLogger({ sinks: [createFileSink()] });
|
|
276
|
-
* logger.error('unhandled rejection');
|
|
277
|
-
* await logger.flush();
|
|
278
|
-
* ```
|
|
279
|
-
*/
|
|
280
|
-
declare function createFileSink(): Sink;
|
|
281
|
-
//#endregion
|
|
282
|
-
//#region src/sink/indexed-db.d.ts
|
|
283
|
-
/**
|
|
284
|
-
* Builds an IndexedDB sink that buffers serialized records through the shared
|
|
285
|
-
* {@link createRecordBuffer} policy and persists each newline-joined JSONL
|
|
286
|
-
* batch as one string value per transaction, measured at 0.15 µs of
|
|
287
|
-
* main-thread enqueue per record on headless Chromium 149 (one `add` per
|
|
288
|
-
* 32 KiB batch). The connection lives in this instance's closure (no
|
|
289
|
-
* module-global state), so independent loggers and tests never share a
|
|
290
|
-
* handle or need a reset hook.
|
|
291
|
-
*
|
|
292
|
-
* Records are readable the moment their transaction settles (DevTools
|
|
293
|
-
* Application tab included), survive tab close and browser restart, and
|
|
294
|
-
* auto-incremented keys serialize across tabs, so no run-scoped naming is
|
|
295
|
-
* needed. Retention trims oldest-first past {@link MAX_STORED_BATCHES}.
|
|
296
|
-
* Transactions use the default relaxed durability: relaxed commits reach the
|
|
297
|
-
* browser's storage backend promptly and survive renderer crashes, and the
|
|
298
|
-
* OS-crash window `durability: 'strict'` would close is the rarest failure
|
|
299
|
-
* class, not worth an fsync per batch.
|
|
300
|
-
*
|
|
301
|
-
* Flush triggers (32 KiB in-write cap, `warn`-or-worse severity, 250 ms
|
|
302
|
-
* quiet-period deadline, page lifecycle, and the `flush` hook) are the
|
|
303
|
-
* buffer's; see {@link createRecordBuffer}. The sink's `flush` hook awaits
|
|
304
|
-
* every issued batch transaction before resolving.
|
|
305
|
-
*
|
|
306
|
-
* @returns Sink backed by IndexedDB.
|
|
307
|
-
*
|
|
308
|
-
* @example
|
|
309
|
-
* ```ts
|
|
310
|
-
* const { logger } = createLogger({ sinks: [createIndexedDbSink()] });
|
|
311
|
-
* logger.warn('quota nearing limit');
|
|
312
|
-
* ```
|
|
313
|
-
*/
|
|
314
|
-
declare function createIndexedDbSink(): Sink;
|
|
315
|
-
//#endregion
|
|
316
135
|
//#region src/sink/local-storage.d.ts
|
|
317
136
|
/**
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
137
|
+
Builds a localStorage sink that buffers serialized records through the
|
|
138
|
+
shared {@link createRecordBuffer} policy and persists each newline-joined
|
|
139
|
+
JSONL batch under a run-scoped counter-incremented key through
|
|
140
|
+
{@link createLocalStorageStore}. One uniform write path runs on every
|
|
141
|
+
runtime; no per-runtime mode exists. Flush triggers (32 KiB in-write cap,
|
|
142
|
+
`warn`-or-worse severity, 250 ms quiet-period deadline, page lifecycle,
|
|
143
|
+
and the `flush` hook) are the buffer's; see {@link createRecordBuffer}.
|
|
144
|
+
|
|
145
|
+
Unlike the sessionStorage sink, whose store dies with the tab, this sink's
|
|
146
|
+
batches survive tab close and browser restart, bounded by oldest-first
|
|
147
|
+
eviction at half the localStorage quota; that makes it the web storage sink
|
|
148
|
+
whose records remain inspectable after a full crash-and-restart.
|
|
149
|
+
|
|
150
|
+
@returns Sink backed by web `localStorage`.
|
|
151
|
+
|
|
152
|
+
@example
|
|
153
|
+
```ts
|
|
154
|
+
const { logger } = createLogger({ sinks: [createLocalStorageSink()] });
|
|
155
|
+
logger.info('user signed in'); // buffered
|
|
156
|
+
logger.warn('quota near'); // flushes both records in one batch
|
|
157
|
+
```
|
|
158
|
+
*/
|
|
340
159
|
declare function createLocalStorageSink(): Sink;
|
|
341
160
|
//#endregion
|
|
342
161
|
//#region src/sink/noop.d.ts
|
|
343
162
|
/**
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
163
|
+
Builds a noop sink that discards every record and always verifies as
|
|
164
|
+
available. Stateless, so the returned adapters share the same functions;
|
|
165
|
+
the factory shape merely matches the other sinks. Useful as a stand-in
|
|
166
|
+
that disables logging without removing log calls.
|
|
167
|
+
|
|
168
|
+
@returns Sink that discards all records and exposes no `flush` (nothing
|
|
169
|
+
is buffered).
|
|
170
|
+
|
|
171
|
+
@example
|
|
172
|
+
```ts
|
|
173
|
+
const { logger } = createLogger({ sinks: [createNoopSink()] });
|
|
174
|
+
logger.info('goes nowhere');
|
|
175
|
+
```
|
|
176
|
+
*/
|
|
358
177
|
declare function createNoopSink(): Sink;
|
|
359
178
|
//#endregion
|
|
360
|
-
//#region src/sink/opfs.d.ts
|
|
361
|
-
/**
|
|
362
|
-
* Builds an OPFS sink that buffers serialized records through the shared
|
|
363
|
-
* {@link createRecordBuffer} policy and appends each newline-joined JSONL
|
|
364
|
-
* batch to a per-session file in the Origin Private File System with one
|
|
365
|
-
* stream write per batch. The kept-open writable stream lives in this
|
|
366
|
-
* instance's closure (no module-global state), so independent loggers and
|
|
367
|
-
* tests never share a handle or need a reset hook.
|
|
368
|
-
*
|
|
369
|
-
* Flush triggers (32 KiB in-write cap, `warn`-or-worse severity, 250 ms
|
|
370
|
-
* quiet-period deadline, page lifecycle, and the `flush` hook) are the
|
|
371
|
-
* buffer's; see {@link createRecordBuffer}. Batch writes queue on the stream
|
|
372
|
-
* in issue order, so ordering holds at the batch boundary, and the sink's
|
|
373
|
-
* `flush` hook awaits every issued batch before resolving.
|
|
374
|
-
*
|
|
375
|
-
* @returns Sink backed by OPFS.
|
|
376
|
-
*
|
|
377
|
-
* @example
|
|
378
|
-
* ```ts
|
|
379
|
-
* const { logger } = createLogger({ sinks: [createOpfsSink()] });
|
|
380
|
-
* logger.warn('quota nearing limit');
|
|
381
|
-
* ```
|
|
382
|
-
*/
|
|
383
|
-
declare function createOpfsSink(): Sink;
|
|
384
|
-
//#endregion
|
|
385
179
|
//#region src/sink/session-storage.d.ts
|
|
386
180
|
/**
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
181
|
+
Builds a sessionStorage sink that buffers serialized records through the
|
|
182
|
+
shared {@link createRecordBuffer} policy and persists each newline-joined
|
|
183
|
+
JSONL batch under a counter-incremented key through
|
|
184
|
+
{@link createSessionStorageStore}. One uniform write path runs on every
|
|
185
|
+
runtime; no per-runtime mode exists. Flush triggers (32 KiB in-write cap,
|
|
186
|
+
`warn`-or-worse severity, 250 ms quiet-period deadline, page lifecycle,
|
|
187
|
+
and the `flush` hook) are the buffer's; see {@link createRecordBuffer}.
|
|
188
|
+
|
|
189
|
+
@returns Sink backed by web `sessionStorage`.
|
|
190
|
+
|
|
191
|
+
@example
|
|
192
|
+
```ts
|
|
193
|
+
const { logger } = createLogger({ sinks: [createSessionStorageSink()] });
|
|
194
|
+
logger.info('user signed in'); // buffered
|
|
195
|
+
logger.warn('quota near'); // flushes both records in one batch
|
|
196
|
+
```
|
|
197
|
+
*/
|
|
404
198
|
declare function createSessionStorageSink(): Sink;
|
|
405
199
|
declare namespace index_d_exports {
|
|
406
|
-
export {
|
|
200
|
+
export { createConsoleSink, createLocalStorageSink, createNoopSink, createSessionStorageSink };
|
|
407
201
|
}
|
|
408
202
|
//#endregion
|
|
409
203
|
//#region src/tagged.d.ts
|
|
410
204
|
/**
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
205
|
+
Wraps a logger so every message is prefixed with `[tag] `.
|
|
206
|
+
Callers typically pass `myFn.name` as tag to keep prefixes
|
|
207
|
+
in sync with refactors.
|
|
208
|
+
|
|
209
|
+
@param tag - Prefix string inserted before each message
|
|
210
|
+
|
|
211
|
+
@param l - Base logger to wrap; defaults to the module-level {@link logger}
|
|
212
|
+
singleton
|
|
213
|
+
|
|
214
|
+
@returns Logger whose methods prepend `[tag] ` to every message
|
|
215
|
+
|
|
216
|
+
@example
|
|
217
|
+
```ts
|
|
218
|
+
import { tagged } from '\@monochromatic-dev/module-logger/tagged';
|
|
219
|
+
|
|
220
|
+
function handleRequest({ l }: { l: Logger }): void {
|
|
221
|
+
l.info('received');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
handleRequest({ l: tagged({ tag: handleRequest.name }) });
|
|
225
|
+
// logs: [handleRequest] received
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
@example
|
|
229
|
+
```ts
|
|
230
|
+
// Composing tags: the outermost wrap (`l2` here) prepends to the message
|
|
231
|
+
// last, so its tag ends up rightmost. The innermost wrap (`l1`) hits the
|
|
232
|
+
// underlying logger first, so its tag is leftmost. The chain reads
|
|
233
|
+
// root-first: outer wrap = inner tag position.
|
|
234
|
+
const l1 = tagged({ tag: 'http' });
|
|
235
|
+
const l2 = tagged({ tag: 'retry', l: l1 });
|
|
236
|
+
l2.info('attempt 3');
|
|
237
|
+
// logs: [http] [retry] attempt 3
|
|
238
|
+
```
|
|
239
|
+
*/
|
|
446
240
|
export declare function tagged({ tag, l }: {
|
|
447
241
|
readonly l?: Logger;
|
|
448
242
|
readonly tag: string;
|
|
@@ -450,31 +244,31 @@ export declare function tagged({ tag, l }: {
|
|
|
450
244
|
//#endregion
|
|
451
245
|
//#region src/sink/console-control-chars.d.ts
|
|
452
246
|
/**
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
247
|
+
Neutralizes terminal control characters in console-bound text. One linear
|
|
248
|
+
pass over the code points: each neutralized control becomes a `\uXXXX`
|
|
249
|
+
escape, everything else is copied through, and newline and tab pass
|
|
250
|
+
untouched. Well-formed and malformed escape sequences get no
|
|
251
|
+
special treatment because the introducer byte itself is neutralized, so a
|
|
252
|
+
trailing lone ESC, an unterminated OSC, and a nested ESC all lose their
|
|
253
|
+
teeth the same way.
|
|
254
|
+
|
|
255
|
+
@param text - Message text destined for `console.*` or `process.stderr`.
|
|
256
|
+
|
|
257
|
+
@returns Text with every neutralized control rendered as `\uXXXX`.
|
|
258
|
+
|
|
259
|
+
@example
|
|
260
|
+
```ts
|
|
261
|
+
neutralizeControlCharacters('title:\u001B]0;x\u0007 ok\n\tnext');
|
|
262
|
+
// => 'title:\\u001B]0;x\\u0007 ok\n\tnext'
|
|
263
|
+
```
|
|
264
|
+
*/
|
|
471
265
|
declare function neutralizeControlCharacters(text: string): string;
|
|
472
266
|
//#endregion
|
|
473
267
|
//#region src/sink/local-storage-key.d.ts
|
|
474
268
|
/**
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
269
|
+
Parsed identity of one owned localStorage entry, used to order eviction
|
|
270
|
+
across runs.
|
|
271
|
+
*/
|
|
478
272
|
type ParsedLogKey = {
|
|
479
273
|
readonly key: string;
|
|
480
274
|
readonly stamp: number;
|
|
@@ -482,64 +276,64 @@ type ParsedLogKey = {
|
|
|
482
276
|
readonly index: number;
|
|
483
277
|
};
|
|
484
278
|
/**
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
279
|
+
Builds the namespaced localStorage key for one batch slot of one run.
|
|
280
|
+
|
|
281
|
+
@param stamp - Run creation time ordering runs oldest-first.
|
|
282
|
+
|
|
283
|
+
@param nonce - Same-millisecond disambiguator between concurrent tabs.
|
|
284
|
+
|
|
285
|
+
@param index - Zero-based batch slot within the run.
|
|
286
|
+
|
|
287
|
+
@returns Key such as `monochromatic.log.1753000000000.a1b2.3`.
|
|
288
|
+
|
|
289
|
+
@example
|
|
290
|
+
```ts
|
|
291
|
+
buildLogKey({ stamp: 1753000000000, nonce: 'a1b2', index: 3 });
|
|
292
|
+
```
|
|
293
|
+
*/
|
|
500
294
|
declare function buildLogKey({ stamp, nonce, index }: {
|
|
501
295
|
readonly stamp: number;
|
|
502
296
|
readonly nonce: string;
|
|
503
297
|
readonly index: number;
|
|
504
298
|
}): string;
|
|
505
299
|
/**
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
300
|
+
Parses a localStorage key back into its run identity, or reports it foreign
|
|
301
|
+
by leaving `parsed` absent. Parsing is strict (exact prefix, exactly the
|
|
302
|
+
identity segment count, digit-shaped stamp and index, non-empty nonce)
|
|
303
|
+
because eviction trusts this to never classify a host application's key, or
|
|
304
|
+
the sessionStorage sink's flat `monochromatic.log.{n}` shape, as evictable.
|
|
305
|
+
|
|
306
|
+
@param key - Candidate localStorage key.
|
|
307
|
+
|
|
308
|
+
@returns Wrapper whose `parsed` property is present only for an owned key.
|
|
309
|
+
|
|
310
|
+
@example
|
|
311
|
+
```ts
|
|
312
|
+
parseLogKey('monochromatic.log.1753000000000.a1b2.3').parsed; // ParsedLogKey
|
|
313
|
+
parseLogKey('monochromatic.log.5').parsed; // undefined: sessionStorage shape
|
|
314
|
+
```
|
|
315
|
+
*/
|
|
522
316
|
declare function parseLogKey(key: string): {
|
|
523
317
|
readonly parsed?: ParsedLogKey;
|
|
524
318
|
};
|
|
525
319
|
/**
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
320
|
+
Orders parsed keys oldest-first for eviction: by run stamp, then by nonce
|
|
321
|
+
(an arbitrary but stable tiebreak between same-millisecond runs), then by
|
|
322
|
+
batch index within the run.
|
|
323
|
+
|
|
324
|
+
@param first - Parsed key compared first.
|
|
325
|
+
|
|
326
|
+
@param second - Parsed key compared second.
|
|
327
|
+
|
|
328
|
+
@returns Negative when `first` is older, positive when newer, zero on ties.
|
|
329
|
+
|
|
330
|
+
@example
|
|
331
|
+
```ts
|
|
332
|
+
entries.toSorted(function byOldestFirst(first, second) {
|
|
333
|
+
return compareLogKeys({ first, second });
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
*/
|
|
543
337
|
declare function compareLogKeys({ first, second }: {
|
|
544
338
|
readonly first: ParsedLogKey;
|
|
545
339
|
readonly second: ParsedLogKey;
|
|
@@ -547,86 +341,86 @@ declare function compareLogKeys({ first, second }: {
|
|
|
547
341
|
//#endregion
|
|
548
342
|
//#region src/sink/local-storage-quota.d.ts
|
|
549
343
|
/**
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
344
|
+
Detects the current runtime's default localStorage quota in UTF-16 code
|
|
345
|
+
units, or `Number.POSITIVE_INFINITY` when the runtime is unrecognized so the
|
|
346
|
+
caller leaves its footprint uncapped and relies on reactive eviction alone.
|
|
347
|
+
|
|
348
|
+
@returns Total quota in code units, or `Number.POSITIVE_INFINITY` if unknown.
|
|
349
|
+
|
|
350
|
+
@example
|
|
351
|
+
```ts
|
|
352
|
+
const capChars = detectLocalStorageQuotaChars() / 2; // half the total
|
|
353
|
+
```
|
|
354
|
+
*/
|
|
561
355
|
declare function detectLocalStorageQuotaChars(): number;
|
|
562
356
|
//#endregion
|
|
563
357
|
//#region src/sink/local-storage-store.d.ts
|
|
564
358
|
/**
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
359
|
+
Builds the persistence engine behind the localStorage sink: each `persist`
|
|
360
|
+
lands one already-serialized batch under a run-scoped counter-incremented
|
|
361
|
+
key, with proactive and reactive quota eviction. Run identity and counters
|
|
362
|
+
live in this instance's closure (no module-global state), so independent
|
|
363
|
+
sinks and tests never share keys or need a reset hook.
|
|
364
|
+
|
|
365
|
+
Unlike sessionStorage, localStorage is shared by every tab of the origin and
|
|
366
|
+
survives restarts, so this engine differs from the sessionStorage engine in
|
|
367
|
+
two ways. Keys carry a run identity (see `local-storage-key.ts`), so
|
|
368
|
+
concurrent tabs never collide on a counter. And on its first persist the
|
|
369
|
+
engine adopts every strictly-parsed entry left by other runs into its
|
|
370
|
+
footprint tally, evicting those oldest-first before its own entries;
|
|
371
|
+
without that, leftovers from dead sessions would fill the store until no
|
|
372
|
+
run could ever write again. Adoption is deferred to first persist rather
|
|
373
|
+
than construction so building the default sink set never touches
|
|
374
|
+
`globalThis.localStorage` on runtimes where the sink never verifies (plain
|
|
375
|
+
Node warns on mere access). Keys that fail the strict parse, including the
|
|
376
|
+
host application's, are never counted and never evicted.
|
|
377
|
+
|
|
378
|
+
The engine caps its own footprint (adopted entries included) at half the
|
|
379
|
+
runtime's localStorage quota, proactively dropping oldest-first, and
|
|
380
|
+
reactively drops again if the real store still overflows; see
|
|
381
|
+
{@link createLocalStorageStore.persist}.
|
|
382
|
+
|
|
383
|
+
@returns Engine exposing `persist` for one batch value per call.
|
|
384
|
+
|
|
385
|
+
@example
|
|
386
|
+
```ts
|
|
387
|
+
const store = createLocalStorageStore();
|
|
388
|
+
store.persist('{"level":"info","message":"hi","timestamp":0}');
|
|
389
|
+
```
|
|
390
|
+
*/
|
|
597
391
|
declare function createLocalStorageStore(): {
|
|
598
392
|
readonly persist: (batch: string) => void;
|
|
599
393
|
};
|
|
600
394
|
//#endregion
|
|
601
395
|
//#region src/sink/record-buffer.d.ts
|
|
602
396
|
/**
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
397
|
+
Builds the buffering stage shared by batch-persisting sinks: serialized
|
|
398
|
+
records accumulate and leave as one newline-joined JSONL batch through
|
|
399
|
+
`onFlush`. One uniform policy runs on every runtime; no per-runtime mode
|
|
400
|
+
exists.
|
|
401
|
+
|
|
402
|
+
A batch flushes synchronously from inside `add` when it reaches
|
|
403
|
+
{@link FLUSH_BUFFER_CAP_CHARS} or when the record's severity is `warn` or
|
|
404
|
+
worse, by timer after {@link FLUSH_DEADLINE_MS} of quiet, on `pagehide`
|
|
405
|
+
and on the document becoming hidden (where those events exist), and on
|
|
406
|
+
`drain`. The byte-cap and severity flushes run on the caller's stack, so
|
|
407
|
+
neither a synchronous workload nor a wedged main thread can accumulate
|
|
408
|
+
more than one cap of unhanded records. When an addition would breach the
|
|
409
|
+
cap, the existing entries flush first so an oversized record's downstream
|
|
410
|
+
failure can only ever drop that record, never its batch-mates.
|
|
411
|
+
|
|
412
|
+
@param onFlush - Backend handoff receiving each newline-joined batch;
|
|
413
|
+
called synchronously from whichever trigger fires, in record order.
|
|
414
|
+
|
|
415
|
+
@returns Buffer exposing `add` for records and `drain` for forced flushes.
|
|
416
|
+
|
|
417
|
+
@example
|
|
418
|
+
```ts
|
|
419
|
+
const buffer = createRecordBuffer({ onFlush: (batch) => store.persist(batch) });
|
|
420
|
+
buffer.add({ level: 'info', serialized: JSON.stringify(record) });
|
|
421
|
+
buffer.drain();
|
|
422
|
+
```
|
|
423
|
+
*/
|
|
630
424
|
declare function createRecordBuffer({ onFlush }: {
|
|
631
425
|
readonly onFlush: (batch: string) => void;
|
|
632
426
|
}): {
|
|
@@ -639,35 +433,35 @@ declare function createRecordBuffer({ onFlush }: {
|
|
|
639
433
|
//#endregion
|
|
640
434
|
//#region src/sink/session-storage-quota.d.ts
|
|
641
435
|
/**
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
436
|
+
Detects the current runtime's default sessionStorage quota in UTF-16 code
|
|
437
|
+
units, or `Number.POSITIVE_INFINITY` when the runtime is unrecognized so the
|
|
438
|
+
caller leaves its footprint uncapped and relies on reactive eviction alone.
|
|
439
|
+
|
|
440
|
+
@returns Total quota in code units, or `Number.POSITIVE_INFINITY` if unknown.
|
|
441
|
+
|
|
442
|
+
@example
|
|
443
|
+
```ts
|
|
444
|
+
const capChars = detectSessionStorageQuotaChars() / 2; // half the total
|
|
445
|
+
```
|
|
446
|
+
*/
|
|
653
447
|
declare function detectSessionStorageQuotaChars(): number;
|
|
654
448
|
//#endregion
|
|
655
449
|
//#region src/sink/web-storage-quota-error.d.ts
|
|
656
450
|
/**
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
451
|
+
Reports whether a caught `setItem` value is a storage quota overflow, so
|
|
452
|
+
eviction reclaims space only for a full store and never for an unrelated
|
|
453
|
+
write fault such as a disabled-storage `SecurityError`.
|
|
454
|
+
|
|
455
|
+
@param error - Caught value from a `setItem` failure.
|
|
456
|
+
|
|
457
|
+
@returns Whether `error` names a quota overflow.
|
|
458
|
+
|
|
459
|
+
@example
|
|
460
|
+
```ts
|
|
461
|
+
try { sessionStorage.setItem(k, v); }
|
|
462
|
+
catch (error: unknown) { if (isQuotaExceededError(error)) evictOldest(); }
|
|
463
|
+
```
|
|
464
|
+
*/
|
|
671
465
|
declare function isQuotaExceededError(error: unknown): boolean;
|
|
672
466
|
//#endregion
|
|
673
467
|
export { type Level, type LogRecord, type Logger, type Sink, type SinkFlush, type Verify, buildLogKey as _buildLogKey, compareLogKeys as _compareLogKeys, createLocalStorageStore as _createLocalStorageStore, createRecordBuffer as _createRecordBuffer, detectLocalStorageQuotaChars as _detectLocalStorageQuotaChars, detectSessionStorageQuotaChars as _detectSessionStorageQuotaChars, isQuotaExceededError as _isQuotaExceededError, neutralizeControlCharacters as _neutralizeControlCharacters, parseLogKey as _parseLogKey, index_d_exports as sinks };
|