@spinajs/log-common 2.0.480 → 2.0.482

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 (68) hide show
  1. package/README.md +125 -4
  2. package/lib/cjs/BatchQueue.d.ts +127 -0
  3. package/lib/cjs/BatchQueue.d.ts.map +1 -0
  4. package/lib/cjs/BatchQueue.js +126 -0
  5. package/lib/cjs/BatchQueue.js.map +1 -0
  6. package/lib/cjs/filters/filter.d.ts +27 -0
  7. package/lib/cjs/filters/filter.d.ts.map +1 -0
  8. package/lib/cjs/filters/filter.js +20 -0
  9. package/lib/cjs/filters/filter.js.map +1 -0
  10. package/lib/cjs/filters/whenRepeated.d.ts +52 -0
  11. package/lib/cjs/filters/whenRepeated.d.ts.map +1 -0
  12. package/lib/cjs/filters/whenRepeated.js +98 -0
  13. package/lib/cjs/filters/whenRepeated.js.map +1 -0
  14. package/lib/cjs/format.d.ts +20 -0
  15. package/lib/cjs/format.d.ts.map +1 -0
  16. package/lib/cjs/format.js +75 -0
  17. package/lib/cjs/format.js.map +1 -0
  18. package/lib/cjs/index.d.ts +260 -21
  19. package/lib/cjs/index.d.ts.map +1 -1
  20. package/lib/cjs/index.js +207 -33
  21. package/lib/cjs/index.js.map +1 -1
  22. package/lib/cjs/perf.d.ts +109 -0
  23. package/lib/cjs/perf.d.ts.map +1 -0
  24. package/lib/cjs/perf.js +162 -0
  25. package/lib/cjs/perf.js.map +1 -0
  26. package/lib/cjs/persistence.d.ts +19 -0
  27. package/lib/cjs/persistence.d.ts.map +1 -0
  28. package/lib/cjs/persistence.js +137 -0
  29. package/lib/cjs/persistence.js.map +1 -0
  30. package/lib/cjs/serializers.d.ts +77 -0
  31. package/lib/cjs/serializers.d.ts.map +1 -0
  32. package/lib/cjs/serializers.js +215 -0
  33. package/lib/cjs/serializers.js.map +1 -0
  34. package/lib/mjs/BatchQueue.d.ts +127 -0
  35. package/lib/mjs/BatchQueue.d.ts.map +1 -0
  36. package/lib/mjs/BatchQueue.js +122 -0
  37. package/lib/mjs/BatchQueue.js.map +1 -0
  38. package/lib/mjs/filters/filter.d.ts +27 -0
  39. package/lib/mjs/filters/filter.d.ts.map +1 -0
  40. package/lib/mjs/filters/filter.js +16 -0
  41. package/lib/mjs/filters/filter.js.map +1 -0
  42. package/lib/mjs/filters/whenRepeated.d.ts +52 -0
  43. package/lib/mjs/filters/whenRepeated.d.ts.map +1 -0
  44. package/lib/mjs/filters/whenRepeated.js +95 -0
  45. package/lib/mjs/filters/whenRepeated.js.map +1 -0
  46. package/lib/mjs/format.d.ts +20 -0
  47. package/lib/mjs/format.d.ts.map +1 -0
  48. package/lib/mjs/format.js +72 -0
  49. package/lib/mjs/format.js.map +1 -0
  50. package/lib/mjs/index.d.ts +260 -21
  51. package/lib/mjs/index.d.ts.map +1 -1
  52. package/lib/mjs/index.js +201 -10
  53. package/lib/mjs/index.js.map +1 -1
  54. package/lib/mjs/perf.d.ts +109 -0
  55. package/lib/mjs/perf.d.ts.map +1 -0
  56. package/lib/mjs/perf.js +157 -0
  57. package/lib/mjs/perf.js.map +1 -0
  58. package/lib/mjs/persistence.d.ts +19 -0
  59. package/lib/mjs/persistence.d.ts.map +1 -0
  60. package/lib/mjs/persistence.js +132 -0
  61. package/lib/mjs/persistence.js.map +1 -0
  62. package/lib/mjs/serializers.d.ts +77 -0
  63. package/lib/mjs/serializers.d.ts.map +1 -0
  64. package/lib/mjs/serializers.js +208 -0
  65. package/lib/mjs/serializers.js.map +1 -0
  66. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  67. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  68. package/package.json +8 -9
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Browser-only runtime log-level persistence ( loglevel-style ). Lets a user's
3
+ * `setLevel(...)` choice survive page reloads via `localStorage`, with a
4
+ * `document.cookie` fallback for environments where storage throws ( eg. Safari
5
+ * private mode ). On Node ( no `window` ) every helper is a clean no-op.
6
+ *
7
+ * Kept dependency-free and free of any `node:*` imports so log-common stays
8
+ * browser-safe: the only globals touched are `window` / `document`, guarded by
9
+ * `typeof` checks.
10
+ */
11
+ const KEY_PREFIX = "spinajs:log:level:";
12
+ function storageKey(loggerName) {
13
+ return `${KEY_PREFIX}${loggerName}`;
14
+ }
15
+ /** True only in a browser-like environment with a usable localStorage. */
16
+ function hasWindow() {
17
+ return typeof window !== "undefined";
18
+ }
19
+ function writeCookie(key, value) {
20
+ if (typeof document === "undefined") {
21
+ return;
22
+ }
23
+ try {
24
+ // 1 year, path=/ so the value is visible across the app.
25
+ const maxAge = 60 * 60 * 24 * 365;
26
+ document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)};path=/;max-age=${maxAge}`;
27
+ }
28
+ catch {
29
+ // nothing else we can do - persistence is best-effort.
30
+ }
31
+ }
32
+ function readCookie(key) {
33
+ if (typeof document === "undefined") {
34
+ return undefined;
35
+ }
36
+ try {
37
+ const enc = encodeURIComponent(key);
38
+ const parts = document.cookie ? document.cookie.split(";") : [];
39
+ for (const part of parts) {
40
+ const [k, ...rest] = part.trim().split("=");
41
+ if (k === enc) {
42
+ return decodeURIComponent(rest.join("="));
43
+ }
44
+ }
45
+ }
46
+ catch {
47
+ // ignore
48
+ }
49
+ return undefined;
50
+ }
51
+ function expireCookie(key) {
52
+ if (typeof document === "undefined") {
53
+ return;
54
+ }
55
+ try {
56
+ document.cookie = `${encodeURIComponent(key)}=;path=/;max-age=0`;
57
+ }
58
+ catch {
59
+ // ignore
60
+ }
61
+ }
62
+ /**
63
+ * Persist `level` for `loggerName`. Browser only - writes `String(level)` to
64
+ * localStorage under `spinajs:log:level:<loggerName>`, falling back to a cookie
65
+ * when storage throws. No-op on Node.
66
+ */
67
+ export function persistLevel(loggerName, level) {
68
+ if (!hasWindow()) {
69
+ return;
70
+ }
71
+ const key = storageKey(loggerName);
72
+ const value = String(level);
73
+ try {
74
+ // window.localStorage access itself can throw ( disabled cookies / private mode ).
75
+ if (window.localStorage) {
76
+ window.localStorage.setItem(key, value);
77
+ return;
78
+ }
79
+ }
80
+ catch {
81
+ // fall through to the cookie fallback below.
82
+ }
83
+ writeCookie(key, value);
84
+ }
85
+ /**
86
+ * Read back the persisted level for `loggerName` ( localStorage then cookie ).
87
+ * Returns a finite {@link LogLevel} number, or `undefined` when nothing valid is
88
+ * stored. Always `undefined` on Node.
89
+ */
90
+ export function readPersistedLevel(loggerName) {
91
+ if (!hasWindow()) {
92
+ return undefined;
93
+ }
94
+ const key = storageKey(loggerName);
95
+ let raw;
96
+ try {
97
+ if (window.localStorage) {
98
+ raw = window.localStorage.getItem(key);
99
+ }
100
+ }
101
+ catch {
102
+ raw = undefined;
103
+ }
104
+ if (raw === null || raw === undefined) {
105
+ raw = readCookie(key);
106
+ }
107
+ if (raw === null || raw === undefined || raw === "") {
108
+ return undefined;
109
+ }
110
+ const parsed = Number(raw);
111
+ return Number.isFinite(parsed) ? parsed : undefined;
112
+ }
113
+ /**
114
+ * Remove any persisted level for `loggerName` ( localStorage + cookie ). No-op
115
+ * on Node.
116
+ */
117
+ export function clearPersistedLevel(loggerName) {
118
+ if (!hasWindow()) {
119
+ return;
120
+ }
121
+ const key = storageKey(loggerName);
122
+ try {
123
+ if (window.localStorage) {
124
+ window.localStorage.removeItem(key);
125
+ }
126
+ }
127
+ catch {
128
+ // ignore - fall through to also expire the cookie.
129
+ }
130
+ expireCookie(key);
131
+ }
132
+ //# sourceMappingURL=persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Pure, dependency-free serialization helpers used by the log targets.
3
+ *
4
+ * These functions are intentionally browser-safe: they use no Node-only APIs
5
+ * ( no `util`, no `Buffer` ), only plain ECMAScript. They are also written to
6
+ * be defensive - neither of them may ever throw, because a logger that crashes
7
+ * while trying to log an error is worse than useless.
8
+ */
9
+ /**
10
+ * Structured representation of an Error suitable for JSON serialization.
11
+ */
12
+ export interface ISerializedError {
13
+ name: string;
14
+ message: string;
15
+ stack?: string;
16
+ code?: string | number;
17
+ signal?: string;
18
+ }
19
+ /**
20
+ * Turn an `Error` into a plain, JSON-friendly record.
21
+ *
22
+ * - Returns `undefined` for anything that is not an `Error` ( callers only
23
+ * serialize actual errors ).
24
+ * - `stack` walks the `.cause` chain and any `AggregateError.errors`, appending
25
+ * each nested error under a `Caused by:` line ( bunyan-style ).
26
+ * - `code` / `signal` are included only when present ( common on Node system
27
+ * errors such as `ECONNREFUSED` / `SIGTERM` ).
28
+ * - Never throws.
29
+ */
30
+ export declare function serializeError(err: unknown): ISerializedError | undefined;
31
+ /**
32
+ * A serializer turns a raw log-variable value into a structured, log-friendly
33
+ * form. It receives the value stored under a given field name and returns its
34
+ * replacement. Returning `undefined` means "leave the original value alone"
35
+ * ( e.g. `serializeError` returns `undefined` for a non-Error ).
36
+ */
37
+ export type LogSerializer = (value: unknown) => unknown;
38
+ /**
39
+ * Registry of field-name -> serializer. Applied by {@link applySerializers} to
40
+ * every log entry's variables. Out of the box the SpinaJS `error` variable
41
+ * ( set by `createLogMessageObject` ) is serialized by {@link serializeError },
42
+ * so `error` becomes a plain `{ name, message, stack, code, signal }` record
43
+ * instead of an opaque `Error`.
44
+ */
45
+ export declare const serializers: Map<string, LogSerializer>;
46
+ /**
47
+ * Register ( or override ) the serializer used for a given log-variable field.
48
+ */
49
+ export declare function registerSerializer(field: string, fn: LogSerializer): void;
50
+ /**
51
+ * Apply the registered serializers to a log entry's variables, MUTATING `vars`
52
+ * in place.
53
+ *
54
+ * For each registered `[field, fn]`:
55
+ * - skip when `field` is absent or its value is `undefined` / `null`;
56
+ * - run `fn` inside a try/catch:
57
+ * - on success, overwrite `vars[field]` ONLY when the serializer returned
58
+ * a defined value, so a serializer that returns `undefined` for an
59
+ * unhandled value ( like `serializeError` on a non-Error ) leaves the
60
+ * original untouched;
61
+ * - on throw, replace the value with `{ serializerError: <message> }` so a
62
+ * broken serializer degrades gracefully and NEVER crashes the caller.
63
+ */
64
+ export declare function applySerializers(vars: Record<string, unknown>): void;
65
+ /**
66
+ * JSON-stringify any value without ever throwing.
67
+ *
68
+ * Three tiers:
69
+ * 1. plain `JSON.stringify` ( the common, fast path );
70
+ * 2. on throw ( typically circular references ) retry with a replacer that
71
+ * swaps already-seen objects for the string `"[Circular]"`, producing
72
+ * VALID JSON;
73
+ * 3. if that still throws ( e.g. a getter that throws while enumerating ),
74
+ * fall back to `String(value)`.
75
+ */
76
+ export declare function safeStringify(value: unknown, indent?: number): string;
77
+ //# sourceMappingURL=serializers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializers.d.ts","sourceRoot":"","sources":["../../src/serializers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA8ED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAiCzE;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,4BAA+E,CAAC;AAExG;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,GAAG,IAAI,CAEzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAoBpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA4BrE"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Pure, dependency-free serialization helpers used by the log targets.
3
+ *
4
+ * These functions are intentionally browser-safe: they use no Node-only APIs
5
+ * ( no `util`, no `Buffer` ), only plain ECMAScript. They are also written to
6
+ * be defensive - neither of them may ever throw, because a logger that crashes
7
+ * while trying to log an error is worse than useless.
8
+ */
9
+ /**
10
+ * Max depth we walk down the `.cause` chain. A self-referential cause
11
+ * ( `err.cause = err` ) would otherwise loop forever, so we cap the walk.
12
+ */
13
+ const MAX_CAUSE_DEPTH = 10;
14
+ /**
15
+ * Best-effort read of a property that might be defined via a throwing getter.
16
+ * Returns `undefined` instead of propagating the throw.
17
+ */
18
+ function safeGet(obj, key) {
19
+ try {
20
+ return obj[key];
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ }
26
+ /**
27
+ * Returns the most useful string form of an error for embedding in a stack:
28
+ * its `.stack` when available, otherwise its `.message`, otherwise `String()`.
29
+ */
30
+ function errorText(err) {
31
+ const stack = safeGet(err, "stack");
32
+ if (typeof stack === "string" && stack.length > 0) {
33
+ return stack;
34
+ }
35
+ const message = safeGet(err, "message");
36
+ if (typeof message === "string" && message.length > 0) {
37
+ return message;
38
+ }
39
+ try {
40
+ return String(err);
41
+ }
42
+ catch {
43
+ return "[unserializable error]";
44
+ }
45
+ }
46
+ /**
47
+ * Builds a combined stack string that walks the `.cause` chain and, for
48
+ * `AggregateError`, its inner `errors`. Mirrors bunyan's `getFullErrorStack`:
49
+ * each nested error is appended under a `Caused by:` line.
50
+ *
51
+ * `seen` guards against cycles ( shared cause objects ) and `depth` caps how
52
+ * far down the chain we recurse, so a self-referential cause cannot hang.
53
+ */
54
+ function buildFullStack(err, seen, depth) {
55
+ let out = errorText(err);
56
+ if (depth >= MAX_CAUSE_DEPTH || seen.has(err)) {
57
+ return out;
58
+ }
59
+ seen.add(err);
60
+ // Follow the standard `.cause` chain ( ES2022 error cause ).
61
+ const cause = safeGet(err, "cause");
62
+ if (cause instanceof Error && !seen.has(cause)) {
63
+ out += "\nCaused by: " + buildFullStack(cause, seen, depth + 1);
64
+ }
65
+ // AggregateError ( or any error carrying an `errors` array ) - surface each
66
+ // inner error under the same `Caused by:` style.
67
+ const errors = safeGet(err, "errors");
68
+ if (Array.isArray(errors)) {
69
+ for (const inner of errors) {
70
+ if (inner instanceof Error && !seen.has(inner)) {
71
+ out += "\nCaused by: " + buildFullStack(inner, seen, depth + 1);
72
+ }
73
+ }
74
+ }
75
+ return out;
76
+ }
77
+ /**
78
+ * Turn an `Error` into a plain, JSON-friendly record.
79
+ *
80
+ * - Returns `undefined` for anything that is not an `Error` ( callers only
81
+ * serialize actual errors ).
82
+ * - `stack` walks the `.cause` chain and any `AggregateError.errors`, appending
83
+ * each nested error under a `Caused by:` line ( bunyan-style ).
84
+ * - `code` / `signal` are included only when present ( common on Node system
85
+ * errors such as `ECONNREFUSED` / `SIGTERM` ).
86
+ * - Never throws.
87
+ */
88
+ export function serializeError(err) {
89
+ if (!(err instanceof Error)) {
90
+ return undefined;
91
+ }
92
+ try {
93
+ const name = typeof err.name === "string" ? err.name : "Error";
94
+ const message = typeof err.message === "string" ? err.message : "";
95
+ const result = { name, message };
96
+ const stack = buildFullStack(err, new Set(), 0);
97
+ if (stack.length > 0) {
98
+ result.stack = stack;
99
+ }
100
+ // Node system errors carry a `code` ( e.g. 'ECONNREFUSED' ) and sometimes a
101
+ // `signal` ( e.g. 'SIGTERM' ). Include them only when actually present.
102
+ const code = safeGet(err, "code");
103
+ if (typeof code === "string" || typeof code === "number") {
104
+ result.code = code;
105
+ }
106
+ const signal = safeGet(err, "signal");
107
+ if (typeof signal === "string") {
108
+ result.signal = signal;
109
+ }
110
+ return result;
111
+ }
112
+ catch {
113
+ // Absolute last-resort guard - serialization must never throw.
114
+ return { name: "Error", message: "[unserializable error]" };
115
+ }
116
+ }
117
+ /**
118
+ * Registry of field-name -> serializer. Applied by {@link applySerializers} to
119
+ * every log entry's variables. Out of the box the SpinaJS `error` variable
120
+ * ( set by `createLogMessageObject` ) is serialized by {@link serializeError },
121
+ * so `error` becomes a plain `{ name, message, stack, code, signal }` record
122
+ * instead of an opaque `Error`.
123
+ */
124
+ export const serializers = new Map([["error", serializeError]]);
125
+ /**
126
+ * Register ( or override ) the serializer used for a given log-variable field.
127
+ */
128
+ export function registerSerializer(field, fn) {
129
+ serializers.set(field, fn);
130
+ }
131
+ /**
132
+ * Apply the registered serializers to a log entry's variables, MUTATING `vars`
133
+ * in place.
134
+ *
135
+ * For each registered `[field, fn]`:
136
+ * - skip when `field` is absent or its value is `undefined` / `null`;
137
+ * - run `fn` inside a try/catch:
138
+ * - on success, overwrite `vars[field]` ONLY when the serializer returned
139
+ * a defined value, so a serializer that returns `undefined` for an
140
+ * unhandled value ( like `serializeError` on a non-Error ) leaves the
141
+ * original untouched;
142
+ * - on throw, replace the value with `{ serializerError: <message> }` so a
143
+ * broken serializer degrades gracefully and NEVER crashes the caller.
144
+ */
145
+ export function applySerializers(vars) {
146
+ for (const [field, fn] of serializers) {
147
+ if (!(field in vars)) {
148
+ continue;
149
+ }
150
+ const value = vars[field];
151
+ if (value === undefined || value === null) {
152
+ continue;
153
+ }
154
+ try {
155
+ const s = fn(value);
156
+ if (s !== undefined) {
157
+ vars[field] = s;
158
+ }
159
+ }
160
+ catch (e) {
161
+ vars[field] = { serializerError: e?.message ?? String(e) };
162
+ }
163
+ }
164
+ }
165
+ /**
166
+ * JSON-stringify any value without ever throwing.
167
+ *
168
+ * Three tiers:
169
+ * 1. plain `JSON.stringify` ( the common, fast path );
170
+ * 2. on throw ( typically circular references ) retry with a replacer that
171
+ * swaps already-seen objects for the string `"[Circular]"`, producing
172
+ * VALID JSON;
173
+ * 3. if that still throws ( e.g. a getter that throws while enumerating ),
174
+ * fall back to `String(value)`.
175
+ */
176
+ export function safeStringify(value, indent) {
177
+ try {
178
+ // Tier 1: the fast, common path.
179
+ return JSON.stringify(value, undefined, indent);
180
+ }
181
+ catch {
182
+ // Tier 2: handle circular references with a WeakSet of seen objects.
183
+ try {
184
+ const seen = new WeakSet();
185
+ const replacer = (_key, val) => {
186
+ if (val !== null && typeof val === "object") {
187
+ if (seen.has(val)) {
188
+ return "[Circular]";
189
+ }
190
+ seen.add(val);
191
+ }
192
+ return val;
193
+ };
194
+ return JSON.stringify(value, replacer, indent);
195
+ }
196
+ catch {
197
+ // Tier 3: something else threw ( e.g. a throwing getter ). Give up on
198
+ // structured output but still return *a* string.
199
+ try {
200
+ return String(value);
201
+ }
202
+ catch {
203
+ return "[unserializable value]";
204
+ }
205
+ }
206
+ }
207
+ }
208
+ //# sourceMappingURL=serializers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializers.js","sourceRoot":"","sources":["../../src/serializers.ts"],"names":[],"mappings":"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"}