@fgv/ts-utils 5.1.0-33 → 5.1.0-34

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 (58) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/index.js.map +1 -1
  3. package/dist/packlets/collections/index.js +1 -0
  4. package/dist/packlets/collections/index.js.map +1 -1
  5. package/dist/packlets/collections/readOnlyConvertingResultMap.js.map +1 -1
  6. package/dist/packlets/collections/retainingRingBuffer.js +159 -0
  7. package/dist/packlets/collections/retainingRingBuffer.js.map +1 -0
  8. package/dist/packlets/conversion/baseConverter.js +5 -2
  9. package/dist/packlets/conversion/baseConverter.js.map +1 -1
  10. package/dist/packlets/conversion/basicConverters.js +12 -4
  11. package/dist/packlets/conversion/basicConverters.js.map +1 -1
  12. package/dist/packlets/conversion/converter.js.map +1 -1
  13. package/dist/packlets/logging/logger.js +2 -10
  14. package/dist/packlets/logging/logger.js.map +1 -1
  15. package/dist/packlets/logging/retainingLogger.js +18 -65
  16. package/dist/packlets/logging/retainingLogger.js.map +1 -1
  17. package/dist/packlets/logging-interface/index.js +11 -0
  18. package/dist/packlets/logging-interface/index.js.map +1 -0
  19. package/dist/ts-utils.d.ts +173 -30
  20. package/lib/index.d.ts +2 -2
  21. package/lib/index.d.ts.map +1 -1
  22. package/lib/index.js +2 -1
  23. package/lib/index.js.map +1 -1
  24. package/lib/packlets/collections/index.d.ts +1 -0
  25. package/lib/packlets/collections/index.d.ts.map +1 -1
  26. package/lib/packlets/collections/index.js +1 -0
  27. package/lib/packlets/collections/index.js.map +1 -1
  28. package/lib/packlets/collections/readOnlyConvertingResultMap.d.ts +1 -1
  29. package/lib/packlets/collections/readOnlyConvertingResultMap.d.ts.map +1 -1
  30. package/lib/packlets/collections/readOnlyConvertingResultMap.js.map +1 -1
  31. package/lib/packlets/collections/retainingRingBuffer.d.ts +147 -0
  32. package/lib/packlets/collections/retainingRingBuffer.d.ts.map +1 -0
  33. package/lib/packlets/collections/retainingRingBuffer.js +163 -0
  34. package/lib/packlets/collections/retainingRingBuffer.js.map +1 -0
  35. package/lib/packlets/conversion/baseConverter.d.ts +4 -1
  36. package/lib/packlets/conversion/baseConverter.d.ts.map +1 -1
  37. package/lib/packlets/conversion/baseConverter.js +5 -2
  38. package/lib/packlets/conversion/baseConverter.js.map +1 -1
  39. package/lib/packlets/conversion/basicConverters.d.ts +3 -0
  40. package/lib/packlets/conversion/basicConverters.d.ts.map +1 -1
  41. package/lib/packlets/conversion/basicConverters.js +12 -4
  42. package/lib/packlets/conversion/basicConverters.js.map +1 -1
  43. package/lib/packlets/conversion/converter.d.ts +4 -1
  44. package/lib/packlets/conversion/converter.d.ts.map +1 -1
  45. package/lib/packlets/conversion/converter.js.map +1 -1
  46. package/lib/packlets/logging/logger.d.ts +2 -85
  47. package/lib/packlets/logging/logger.d.ts.map +1 -1
  48. package/lib/packlets/logging/logger.js +3 -12
  49. package/lib/packlets/logging/logger.js.map +1 -1
  50. package/lib/packlets/logging/retainingLogger.d.ts +8 -28
  51. package/lib/packlets/logging/retainingLogger.d.ts.map +1 -1
  52. package/lib/packlets/logging/retainingLogger.js +18 -65
  53. package/lib/packlets/logging/retainingLogger.js.map +1 -1
  54. package/lib/packlets/logging-interface/index.d.ts +87 -0
  55. package/lib/packlets/logging-interface/index.d.ts.map +1 -0
  56. package/lib/packlets/logging-interface/index.js +14 -0
  57. package/lib/packlets/logging-interface/index.js.map +1 -0
  58. package/package.json +3 -3
@@ -62,40 +62,25 @@ export interface IGetRecordsOptions {
62
62
  * @public
63
63
  */
64
64
  export declare class RetainingLogger extends LoggerBase {
65
- /**
66
- * The fixed ring capacity — the maximum number of records retained before the
67
- * oldest is overwritten. A positive integer (see the constructor normalization).
68
- * @internal
69
- */
70
- private readonly _capacity;
71
65
  /**
72
66
  * Injected clock used to timestamp records.
73
67
  * @internal
74
68
  */
75
69
  private readonly _now;
76
70
  /**
77
- * The backing store, used as a circular buffer. Grows lazily up to `_capacity`,
78
- * after which records overwrite the oldest slot in place eviction is O(1), with
79
- * no `shift()` re-indexing regardless of capacity.
80
- * @internal
81
- */
82
- private _buffer;
83
- /**
84
- * Index of the oldest retained record within `_buffer` once the ring is full.
71
+ * The monotonic sequence counter. The logger owns `seq` assignment and
72
+ * increments this before each push so the buffer receives strictly increasing
73
+ * sequence numbers.
85
74
  * @internal
86
75
  */
87
- private _head;
76
+ private _nextSeq;
88
77
  /**
89
- * The number of valid records currently retained (`<= _capacity`).
78
+ * The backing ring buffer. Retains up to `maxRecords` log records, evicting
79
+ * the oldest when full. The buffer is a pure seq-ring — it does not assign
80
+ * `seq`; the logger does.
90
81
  * @internal
91
82
  */
92
- private _count;
93
- /**
94
- * The most recently assigned sequence number; monotonic, stable across eviction
95
- * and {@link Logging.RetainingLogger.clear | clear()}.
96
- * @internal
97
- */
98
- private _lastSeq;
83
+ private readonly _ring;
99
84
  /**
100
85
  * Creates a new retaining logger.
101
86
  * @param logLevel - The level of logging to retain. Defaults to `'detail'` to capture
@@ -124,11 +109,6 @@ export declare class RetainingLogger extends LoggerBase {
124
109
  * holding a `sinceSeq` cursor never re-sees a sequence number.
125
110
  */
126
111
  clear(): void;
127
- /**
128
- * Materializes the ring into a plain oldest-first array.
129
- * @internal
130
- */
131
- private _toOrderedArray;
132
112
  /**
133
113
  * {@inheritDoc Logging.LoggerBase._logStructured}
134
114
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"retainingLogger.d.ts","sourceRoot":"","sources":["../../../src/packlets/logging/retainingLogger.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAW,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAa,MAAM,UAAU,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IAEpC;;;;;OAKG;IACH,OAAO,CAAC,OAAO,CAAoB;IAEnC;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAa;IAE1B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAa;IAE3B;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAa;IAE7B;;;;;;OAMG;gBAED,QAAQ,GAAE,gBAA2B,EACrC,UAAU,GAAE,MAAa,EACzB,GAAG,GAAE,MAAM,MAAyB;IAUtC;;OAEG;IACH,IAAW,OAAO,IAAI,aAAa,CAAC,UAAU,CAAC,CAE9C;IAED;;;OAGG;IACH,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED;;;;OAIG;IACI,UAAU,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,aAAa,CAAC,UAAU,CAAC;IAgB1E;;;OAGG;IACI,KAAK,IAAI,IAAI;IAMpB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAQvB;;;OAGG;IACH,SAAS,CAAC,cAAc,CACtB,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,SAAS,OAAO,EAAE,GAC7B,IAAI;IAoBP;;;OAGG;IACH,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAGvF"}
1
+ {"version":3,"file":"retainingLogger.d.ts","sourceRoot":"","sources":["../../../src/packlets/logging/retainingLogger.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAW,MAAM,SAAS,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAa,MAAM,UAAU,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC7C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IAEpC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAa;IAE7B;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IAExD;;;;;;OAMG;gBAED,QAAQ,GAAE,gBAA2B,EACrC,UAAU,GAAE,MAAa,EACzB,GAAG,GAAE,MAAM,MAAyB;IAOtC;;OAEG;IACH,IAAW,OAAO,IAAI,aAAa,CAAC,UAAU,CAAC,CAE9C;IAED;;;OAGG;IACH,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED;;;;OAIG;IACI,UAAU,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,aAAa,CAAC,UAAU,CAAC;IAS1E;;;OAGG;IACI,KAAK,IAAI,IAAI;IAIpB;;;OAGG;IACH,SAAS,CAAC,cAAc,CACtB,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,SAAS,OAAO,EAAE,GAC7B,IAAI;IAYP;;;OAGG;IACH,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAGvF"}
@@ -23,6 +23,7 @@ exports.RetainingLogger = void 0;
23
23
  * SOFTWARE.
24
24
  */
25
25
  const base_1 = require("../base");
26
+ const collections_1 = require("../collections");
26
27
  const logger_1 = require("./logger");
27
28
  /**
28
29
  * An {@link Logging.ILogger | ILogger} that retains structured log records in a bounded
@@ -48,46 +49,27 @@ class RetainingLogger extends logger_1.LoggerBase {
48
49
  constructor(logLevel = 'detail', maxRecords = 1000, now = () => Date.now()) {
49
50
  super(logLevel);
50
51
  /**
51
- * The backing store, used as a circular buffer. Grows lazily up to `_capacity`,
52
- * after which records overwrite the oldest slot in place eviction is O(1), with
53
- * no `shift()` re-indexing regardless of capacity.
52
+ * The monotonic sequence counter. The logger owns `seq` assignment and
53
+ * increments this before each push so the buffer receives strictly increasing
54
+ * sequence numbers.
54
55
  * @internal
55
56
  */
56
- this._buffer = [];
57
- /**
58
- * Index of the oldest retained record within `_buffer` once the ring is full.
59
- * @internal
60
- */
61
- this._head = 0;
62
- /**
63
- * The number of valid records currently retained (`<= _capacity`).
64
- * @internal
65
- */
66
- this._count = 0;
67
- /**
68
- * The most recently assigned sequence number; monotonic, stable across eviction
69
- * and {@link Logging.RetainingLogger.clear | clear()}.
70
- * @internal
71
- */
72
- this._lastSeq = 0;
73
- // The ring requires a positive integer capacity to be well-defined; a non-finite
74
- // or sub-1 value would make the modular index arithmetic meaningless, so floor it
75
- // to a sane minimum of 1 rather than crash on degenerate input.
76
- this._capacity = Number.isFinite(maxRecords) && maxRecords >= 1 ? Math.floor(maxRecords) : 1;
57
+ this._nextSeq = 0;
77
58
  this._now = now;
59
+ this._ring = new collections_1.RetainingRingBuffer({ maxRecords });
78
60
  }
79
61
  /**
80
62
  * The retained records, oldest-first.
81
63
  */
82
64
  get records() {
83
- return this._toOrderedArray();
65
+ return this._ring.records;
84
66
  }
85
67
  /**
86
68
  * The most recently assigned sequence number. A client can hold this value and
87
69
  * pass it as `sinceSeq` to page only records logged afterward.
88
70
  */
89
71
  get lastSeq() {
90
- return this._lastSeq;
72
+ return this._ring.lastSeq;
91
73
  }
92
74
  /**
93
75
  * Returns retained records, oldest-first, optionally filtered.
@@ -95,63 +77,34 @@ class RetainingLogger extends logger_1.LoggerBase {
95
77
  * @returns The matching records, oldest-first.
96
78
  */
97
79
  getRecords(options) {
98
- let result = this._toOrderedArray();
99
- if ((options === null || options === void 0 ? void 0 : options.minLevel) !== undefined) {
100
- const minLevel = options.minLevel;
101
- result = result.filter((r) => (0, logger_1.shouldLog)(r.level, minLevel));
102
- }
103
- if ((options === null || options === void 0 ? void 0 : options.sinceSeq) !== undefined) {
104
- const sinceSeq = options.sinceSeq;
105
- result = result.filter((r) => r.seq > sinceSeq);
106
- }
107
- if ((options === null || options === void 0 ? void 0 : options.limit) !== undefined && result.length > options.limit) {
108
- result = result.slice(result.length - options.limit);
109
- }
110
- return result;
80
+ const minLevel = options === null || options === void 0 ? void 0 : options.minLevel;
81
+ return this._ring.query({
82
+ sinceSeq: options === null || options === void 0 ? void 0 : options.sinceSeq,
83
+ filter: minLevel !== undefined ? (r) => (0, logger_1.shouldLog)(r.level, minLevel) : undefined,
84
+ limit: options === null || options === void 0 ? void 0 : options.limit
85
+ });
111
86
  }
112
87
  /**
113
88
  * Clears all retained records. Does NOT reset the sequence counter, so a client
114
89
  * holding a `sinceSeq` cursor never re-sees a sequence number.
115
90
  */
116
91
  clear() {
117
- this._buffer = [];
118
- this._head = 0;
119
- this._count = 0;
120
- }
121
- /**
122
- * Materializes the ring into a plain oldest-first array.
123
- * @internal
124
- */
125
- _toOrderedArray() {
126
- const result = [];
127
- for (let i = 0; i < this._count; i++) {
128
- result.push(this._buffer[(this._head + i) % this._capacity]);
129
- }
130
- return result;
92
+ this._ring.clear();
131
93
  }
132
94
  /**
133
95
  * {@inheritDoc Logging.LoggerBase._logStructured}
134
96
  * @internal
135
97
  */
136
98
  _logStructured(level, formatted, message, parameters) {
137
- this._lastSeq += 1;
99
+ this._nextSeq += 1;
138
100
  const record = {
139
- seq: this._lastSeq,
101
+ seq: this._nextSeq,
140
102
  timestamp: this._now(),
141
103
  level,
142
104
  message: formatted,
143
105
  args: [message, ...parameters]
144
106
  };
145
- if (this._count < this._capacity) {
146
- // Still filling: append to the next free slot (head stays 0 during this phase).
147
- this._buffer.push(record);
148
- this._count += 1;
149
- }
150
- else {
151
- // Full: overwrite the oldest record in place and advance the head.
152
- this._buffer[this._head] = record;
153
- this._head = (this._head + 1) % this._capacity;
154
- }
107
+ this._ring.push(record);
155
108
  }
156
109
  /**
157
110
  * {@inheritDoc Logging.LoggerBase._log}
@@ -1 +1 @@
1
- {"version":3,"file":"retainingLogger.js","sourceRoot":"","sources":["../../../src/packlets/logging/retainingLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2020 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nimport { MessageLogLevel, Success, succeed } from '../base';\nimport { LoggerBase, ReporterLogLevel, shouldLog } from './logger';\n\n/**\n * A retained log record. Preserves the level and an ordering cursor so consumers\n * can filter by severity and page incrementally.\n * @public\n */\nexport interface ILogRecord {\n /**\n * Monotonic 1-based sequence number, stable across ring eviction.\n */\n readonly seq: number;\n /**\n * Milliseconds since epoch when the record was logged (from the injected clock).\n */\n readonly timestamp: number;\n /**\n * The level the record was logged at.\n */\n readonly level: MessageLogLevel;\n /**\n * The formatted message (same formatting {@link Logging.LoggerBase._format | LoggerBase._format} produces).\n */\n readonly message: string;\n /**\n * The raw structured inputs `[message, ...parameters]` before formatting.\n */\n readonly args?: readonly unknown[];\n}\n\n/**\n * Options for {@link Logging.RetainingLogger.getRecords | RetainingLogger.getRecords}.\n * @public\n */\nexport interface IGetRecordsOptions {\n /**\n * If supplied, only records whose level would be emitted at this threshold\n * (per {@link Logging.shouldLog | shouldLog}) are returned.\n */\n readonly minLevel?: ReporterLogLevel;\n /**\n * If supplied, only records with `seq > sinceSeq` are returned, enabling\n * incremental paging from a previously-held cursor.\n */\n readonly sinceSeq?: number;\n /**\n * If supplied, returns at most this many records — the most recent N (tail),\n * still ordered oldest-first.\n */\n readonly limit?: number;\n}\n\n/**\n * An {@link Logging.ILogger | ILogger} that retains structured log records in a bounded\n * most-recent-N ring, with a query API supporting min-severity filtering and\n * since-cursor incremental paging.\n *\n * @remarks\n * Records are captured via the {@link Logging.LoggerBase._logStructured | _logStructured} hook,\n * so the full structured form (`level` + formatted `message` + raw `args`) is retained.\n * The logger emits nowhere itself — pair it with a {@link Logging.MultiLogger | MultiLogger}\n * to also feed a {@link Logging.ConsoleLogger | ConsoleLogger} or other durable sink.\n *\n * @public\n */\nexport class RetainingLogger extends LoggerBase {\n /**\n * The fixed ring capacity — the maximum number of records retained before the\n * oldest is overwritten. A positive integer (see the constructor normalization).\n * @internal\n */\n private readonly _capacity: number;\n\n /**\n * Injected clock used to timestamp records.\n * @internal\n */\n private readonly _now: () => number;\n\n /**\n * The backing store, used as a circular buffer. Grows lazily up to `_capacity`,\n * after which records overwrite the oldest slot in place — eviction is O(1), with\n * no `shift()` re-indexing regardless of capacity.\n * @internal\n */\n private _buffer: ILogRecord[] = [];\n\n /**\n * Index of the oldest retained record within `_buffer` once the ring is full.\n * @internal\n */\n private _head: number = 0;\n\n /**\n * The number of valid records currently retained (`<= _capacity`).\n * @internal\n */\n private _count: number = 0;\n\n /**\n * The most recently assigned sequence number; monotonic, stable across eviction\n * and {@link Logging.RetainingLogger.clear | clear()}.\n * @internal\n */\n private _lastSeq: number = 0;\n\n /**\n * Creates a new retaining logger.\n * @param logLevel - The level of logging to retain. Defaults to `'detail'` to capture\n * broadly and filter at query time.\n * @param maxRecords - The maximum number of records to retain. Defaults to `1000`.\n * @param now - Injected clock returning milliseconds since epoch. Defaults to `Date.now`.\n */\n public constructor(\n logLevel: ReporterLogLevel = 'detail',\n maxRecords: number = 1000,\n now: () => number = () => Date.now()\n ) {\n super(logLevel);\n // The ring requires a positive integer capacity to be well-defined; a non-finite\n // or sub-1 value would make the modular index arithmetic meaningless, so floor it\n // to a sane minimum of 1 rather than crash on degenerate input.\n this._capacity = Number.isFinite(maxRecords) && maxRecords >= 1 ? Math.floor(maxRecords) : 1;\n this._now = now;\n }\n\n /**\n * The retained records, oldest-first.\n */\n public get records(): ReadonlyArray<ILogRecord> {\n return this._toOrderedArray();\n }\n\n /**\n * The most recently assigned sequence number. A client can hold this value and\n * pass it as `sinceSeq` to page only records logged afterward.\n */\n public get lastSeq(): number {\n return this._lastSeq;\n }\n\n /**\n * Returns retained records, oldest-first, optionally filtered.\n * @param options - {@link Logging.IGetRecordsOptions | Filtering and paging options}.\n * @returns The matching records, oldest-first.\n */\n public getRecords(options?: IGetRecordsOptions): ReadonlyArray<ILogRecord> {\n let result: ReadonlyArray<ILogRecord> = this._toOrderedArray();\n if (options?.minLevel !== undefined) {\n const minLevel = options.minLevel;\n result = result.filter((r) => shouldLog(r.level, minLevel));\n }\n if (options?.sinceSeq !== undefined) {\n const sinceSeq = options.sinceSeq;\n result = result.filter((r) => r.seq > sinceSeq);\n }\n if (options?.limit !== undefined && result.length > options.limit) {\n result = result.slice(result.length - options.limit);\n }\n return result;\n }\n\n /**\n * Clears all retained records. Does NOT reset the sequence counter, so a client\n * holding a `sinceSeq` cursor never re-sees a sequence number.\n */\n public clear(): void {\n this._buffer = [];\n this._head = 0;\n this._count = 0;\n }\n\n /**\n * Materializes the ring into a plain oldest-first array.\n * @internal\n */\n private _toOrderedArray(): ILogRecord[] {\n const result: ILogRecord[] = [];\n for (let i = 0; i < this._count; i++) {\n result.push(this._buffer[(this._head + i) % this._capacity]);\n }\n return result;\n }\n\n /**\n * {@inheritDoc Logging.LoggerBase._logStructured}\n * @internal\n */\n protected _logStructured(\n level: MessageLogLevel,\n formatted: string,\n message: unknown,\n parameters: readonly unknown[]\n ): void {\n this._lastSeq += 1;\n const record: ILogRecord = {\n seq: this._lastSeq,\n timestamp: this._now(),\n level,\n message: formatted,\n args: [message, ...parameters]\n };\n if (this._count < this._capacity) {\n // Still filling: append to the next free slot (head stays 0 during this phase).\n this._buffer.push(record);\n this._count += 1;\n } else {\n // Full: overwrite the oldest record in place and advance the head.\n this._buffer[this._head] = record;\n this._head = (this._head + 1) % this._capacity;\n }\n }\n\n /**\n * {@inheritDoc Logging.LoggerBase._log}\n * @internal\n */\n protected _log(message: string, __level: MessageLogLevel): Success<string | undefined> {\n return succeed(message);\n }\n}\n"]}
1
+ {"version":3,"file":"retainingLogger.js","sourceRoot":"","sources":["../../../src/packlets/logging/retainingLogger.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,kCAA4D;AAC5D,gDAAqD;AACrD,qCAAmE;AAoDnE;;;;;;;;;;;;GAYG;AACH,MAAa,eAAgB,SAAQ,mBAAU;IAuB7C;;;;;;OAMG;IACH,YACE,WAA6B,QAAQ,EACrC,aAAqB,IAAI,EACzB,MAAoB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QAEpC,KAAK,CAAC,QAAQ,CAAC,CAAC;QA5BlB;;;;;WAKG;QACK,aAAQ,GAAW,CAAC,CAAC;QAuB3B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,KAAK,GAAG,IAAI,iCAAmB,CAAa,EAAE,UAAU,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;OAEG;IACH,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACI,UAAU,CAAC,OAA4B;QAC5C,MAAM,QAAQ,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,CAAC;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;YACtB,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ;YAC3B,MAAM,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,kBAAS,EAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;YAChF,KAAK,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK;SACtB,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACI,KAAK;QACV,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED;;;OAGG;IACO,cAAc,CACtB,KAAsB,EACtB,SAAiB,EACjB,OAAgB,EAChB,UAA8B;QAE9B,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnB,MAAM,MAAM,GAAe;YACzB,GAAG,EAAE,IAAI,CAAC,QAAQ;YAClB,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE;YACtB,KAAK;YACL,OAAO,EAAE,SAAS;YAClB,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC;SAC/B,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACO,IAAI,CAAC,OAAe,EAAE,OAAwB;QACtD,OAAO,IAAA,cAAO,EAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;CACF;AAzGD,0CAyGC","sourcesContent":["/*\n * Copyright (c) 2020 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nimport { MessageLogLevel, Success, succeed } from '../base';\nimport { RetainingRingBuffer } from '../collections';\nimport { LoggerBase, ReporterLogLevel, shouldLog } from './logger';\n\n/**\n * A retained log record. Preserves the level and an ordering cursor so consumers\n * can filter by severity and page incrementally.\n * @public\n */\nexport interface ILogRecord {\n /**\n * Monotonic 1-based sequence number, stable across ring eviction.\n */\n readonly seq: number;\n /**\n * Milliseconds since epoch when the record was logged (from the injected clock).\n */\n readonly timestamp: number;\n /**\n * The level the record was logged at.\n */\n readonly level: MessageLogLevel;\n /**\n * The formatted message (same formatting {@link Logging.LoggerBase._format | LoggerBase._format} produces).\n */\n readonly message: string;\n /**\n * The raw structured inputs `[message, ...parameters]` before formatting.\n */\n readonly args?: readonly unknown[];\n}\n\n/**\n * Options for {@link Logging.RetainingLogger.getRecords | RetainingLogger.getRecords}.\n * @public\n */\nexport interface IGetRecordsOptions {\n /**\n * If supplied, only records whose level would be emitted at this threshold\n * (per {@link Logging.shouldLog | shouldLog}) are returned.\n */\n readonly minLevel?: ReporterLogLevel;\n /**\n * If supplied, only records with `seq > sinceSeq` are returned, enabling\n * incremental paging from a previously-held cursor.\n */\n readonly sinceSeq?: number;\n /**\n * If supplied, returns at most this many records — the most recent N (tail),\n * still ordered oldest-first.\n */\n readonly limit?: number;\n}\n\n/**\n * An {@link Logging.ILogger | ILogger} that retains structured log records in a bounded\n * most-recent-N ring, with a query API supporting min-severity filtering and\n * since-cursor incremental paging.\n *\n * @remarks\n * Records are captured via the {@link Logging.LoggerBase._logStructured | _logStructured} hook,\n * so the full structured form (`level` + formatted `message` + raw `args`) is retained.\n * The logger emits nowhere itself — pair it with a {@link Logging.MultiLogger | MultiLogger}\n * to also feed a {@link Logging.ConsoleLogger | ConsoleLogger} or other durable sink.\n *\n * @public\n */\nexport class RetainingLogger extends LoggerBase {\n /**\n * Injected clock used to timestamp records.\n * @internal\n */\n private readonly _now: () => number;\n\n /**\n * The monotonic sequence counter. The logger owns `seq` assignment and\n * increments this before each push so the buffer receives strictly increasing\n * sequence numbers.\n * @internal\n */\n private _nextSeq: number = 0;\n\n /**\n * The backing ring buffer. Retains up to `maxRecords` log records, evicting\n * the oldest when full. The buffer is a pure seq-ring — it does not assign\n * `seq`; the logger does.\n * @internal\n */\n private readonly _ring: RetainingRingBuffer<ILogRecord>;\n\n /**\n * Creates a new retaining logger.\n * @param logLevel - The level of logging to retain. Defaults to `'detail'` to capture\n * broadly and filter at query time.\n * @param maxRecords - The maximum number of records to retain. Defaults to `1000`.\n * @param now - Injected clock returning milliseconds since epoch. Defaults to `Date.now`.\n */\n public constructor(\n logLevel: ReporterLogLevel = 'detail',\n maxRecords: number = 1000,\n now: () => number = () => Date.now()\n ) {\n super(logLevel);\n this._now = now;\n this._ring = new RetainingRingBuffer<ILogRecord>({ maxRecords });\n }\n\n /**\n * The retained records, oldest-first.\n */\n public get records(): ReadonlyArray<ILogRecord> {\n return this._ring.records;\n }\n\n /**\n * The most recently assigned sequence number. A client can hold this value and\n * pass it as `sinceSeq` to page only records logged afterward.\n */\n public get lastSeq(): number {\n return this._ring.lastSeq;\n }\n\n /**\n * Returns retained records, oldest-first, optionally filtered.\n * @param options - {@link Logging.IGetRecordsOptions | Filtering and paging options}.\n * @returns The matching records, oldest-first.\n */\n public getRecords(options?: IGetRecordsOptions): ReadonlyArray<ILogRecord> {\n const minLevel = options?.minLevel;\n return this._ring.query({\n sinceSeq: options?.sinceSeq,\n filter: minLevel !== undefined ? (r) => shouldLog(r.level, minLevel) : undefined,\n limit: options?.limit\n });\n }\n\n /**\n * Clears all retained records. Does NOT reset the sequence counter, so a client\n * holding a `sinceSeq` cursor never re-sees a sequence number.\n */\n public clear(): void {\n this._ring.clear();\n }\n\n /**\n * {@inheritDoc Logging.LoggerBase._logStructured}\n * @internal\n */\n protected _logStructured(\n level: MessageLogLevel,\n formatted: string,\n message: unknown,\n parameters: readonly unknown[]\n ): void {\n this._nextSeq += 1;\n const record: ILogRecord = {\n seq: this._nextSeq,\n timestamp: this._now(),\n level,\n message: formatted,\n args: [message, ...parameters]\n };\n this._ring.push(record);\n }\n\n /**\n * {@inheritDoc Logging.LoggerBase._log}\n * @internal\n */\n protected _log(message: string, __level: MessageLogLevel): Success<string | undefined> {\n return succeed(message);\n }\n}\n"]}
@@ -0,0 +1,87 @@
1
+ import { MessageLogLevel, Success } from '../base';
2
+ /**
3
+ * The level of logging to be used.
4
+ * @public
5
+ */
6
+ export type ReporterLogLevel = 'all' | 'detail' | 'info' | 'warning' | 'error' | 'silent';
7
+ /**
8
+ * Generic Result-aware logger interface with multiple levels of logging.
9
+ * @public
10
+ */
11
+ export interface ILogger {
12
+ /**
13
+ * The level of logging to be used.
14
+ */
15
+ readonly logLevel: ReporterLogLevel;
16
+ /**
17
+ * Logs a message at the given level.
18
+ * @param level - The level of the message.
19
+ * @param message - The message to log.
20
+ * @param parameters - The parameters to log.
21
+ * @returns `Success` with the logged message if the level is enabled, or
22
+ * `Success` with `undefined` if the message is suppressed.
23
+ */
24
+ log(level: MessageLogLevel, message?: unknown, ...parameters: unknown[]): Success<string | undefined>;
25
+ /**
26
+ * Logs a detail message.
27
+ * @param message - The message to log.
28
+ * @param parameters - The parameters to log.
29
+ * @returns `Success` with the logged message if the level is enabled, or
30
+ * `Success` with `undefined` if the message is suppressed.
31
+ */
32
+ detail(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;
33
+ /**
34
+ * Logs an info message.
35
+ * @param message - The message to log.
36
+ * @param parameters - The parameters to log.
37
+ * @returns `Success` with the logged message if the level is enabled, or
38
+ * `Success` with `undefined` if the message is suppressed.
39
+ */
40
+ info(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;
41
+ /**
42
+ * Logs a warning message.
43
+ * @param message - The message to log.
44
+ * @param parameters - The parameters to log.
45
+ * @returns `Success` with the logged message if the level is enabled, or
46
+ * `Success` with `undefined` if the message is suppressed.
47
+ */
48
+ warn(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;
49
+ /**
50
+ * Logs an error message.
51
+ * @param message - The message to log.
52
+ * @param parameters - The parameters to log.
53
+ * @returns `Success` with the logged message if the level is enabled, or
54
+ * `Success` with `undefined` if the message is suppressed.
55
+ */
56
+ error(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;
57
+ }
58
+ /**
59
+ * Extended logger interface that supports logging a short summary message at a
60
+ * primary level (error/warn) while emitting the full detail at `detail` level.
61
+ *
62
+ * The detail is suppressed by default (requires log level `'detail'` or `'all'`),
63
+ * keeping the primary log clean while preserving the full context for debugging.
64
+ * @public
65
+ */
66
+ export interface IDetailLogger extends ILogger {
67
+ /**
68
+ * Logs a short error summary at `error` level, then emits `detail` at `detail` level.
69
+ * @param message - Short human-readable summary.
70
+ * @param detail - Full detail (e.g. raw converter error) logged at `detail` level.
71
+ */
72
+ errorWithDetail(message: string, detail: unknown): Success<string | undefined>;
73
+ /**
74
+ * Logs a short warning summary at `warning` level, then emits `detail` at `detail` level.
75
+ * @param message - Short human-readable summary.
76
+ * @param detail - Full detail logged at `detail` level.
77
+ */
78
+ warnWithDetail(message: string, detail: unknown): Success<string | undefined>;
79
+ }
80
+ /**
81
+ * Type guard that checks whether a logger implements {@link IDetailLogger}.
82
+ * @param logger - The logger to check.
83
+ * @returns `true` if the logger implements `IDetailLogger`.
84
+ * @public
85
+ */
86
+ export declare function isDetailLogger(logger: ILogger): logger is IDetailLogger;
87
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/logging-interface/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE1F;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAEpC;;;;;;;OAOG;IACH,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEtG;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEjF;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE/E;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE/E;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACjF;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAc,SAAQ,OAAO;IAC5C;;;;OAIG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE/E;;;;OAIG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC/E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,aAAa,CAKvE"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDetailLogger = isDetailLogger;
4
+ /**
5
+ * Type guard that checks whether a logger implements {@link IDetailLogger}.
6
+ * @param logger - The logger to check.
7
+ * @returns `true` if the logger implements `IDetailLogger`.
8
+ * @public
9
+ */
10
+ function isDetailLogger(logger) {
11
+ return (typeof logger.errorWithDetail === 'function' &&
12
+ typeof logger.warnWithDetail === 'function');
13
+ }
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/logging-interface/index.ts"],"names":[],"mappings":";;AAoHA,wCAKC;AAXD;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,MAAe;IAC5C,OAAO,CACL,OAAQ,MAAwB,CAAC,eAAe,KAAK,UAAU;QAC/D,OAAQ,MAAwB,CAAC,cAAc,KAAK,UAAU,CAC/D,CAAC;AACJ,CAAC","sourcesContent":["/*\n * Copyright (c) 2020 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nimport { MessageLogLevel, Success } from '../base';\n\n/**\n * The level of logging to be used.\n * @public\n */\nexport type ReporterLogLevel = 'all' | 'detail' | 'info' | 'warning' | 'error' | 'silent';\n\n/**\n * Generic Result-aware logger interface with multiple levels of logging.\n * @public\n */\nexport interface ILogger {\n /**\n * The level of logging to be used.\n */\n readonly logLevel: ReporterLogLevel;\n\n /**\n * Logs a message at the given level.\n * @param level - The level of the message.\n * @param message - The message to log.\n * @param parameters - The parameters to log.\n * @returns `Success` with the logged message if the level is enabled, or\n * `Success` with `undefined` if the message is suppressed.\n */\n log(level: MessageLogLevel, message?: unknown, ...parameters: unknown[]): Success<string | undefined>;\n\n /**\n * Logs a detail message.\n * @param message - The message to log.\n * @param parameters - The parameters to log.\n * @returns `Success` with the logged message if the level is enabled, or\n * `Success` with `undefined` if the message is suppressed.\n */\n detail(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;\n\n /**\n * Logs an info message.\n * @param message - The message to log.\n * @param parameters - The parameters to log.\n * @returns `Success` with the logged message if the level is enabled, or\n * `Success` with `undefined` if the message is suppressed.\n */\n info(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;\n\n /**\n * Logs a warning message.\n * @param message - The message to log.\n * @param parameters - The parameters to log.\n * @returns `Success` with the logged message if the level is enabled, or\n * `Success` with `undefined` if the message is suppressed.\n */\n warn(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;\n\n /**\n * Logs an error message.\n * @param message - The message to log.\n * @param parameters - The parameters to log.\n * @returns `Success` with the logged message if the level is enabled, or\n * `Success` with `undefined` if the message is suppressed.\n */\n error(message?: unknown, ...parameters: unknown[]): Success<string | undefined>;\n}\n\n/**\n * Extended logger interface that supports logging a short summary message at a\n * primary level (error/warn) while emitting the full detail at `detail` level.\n *\n * The detail is suppressed by default (requires log level `'detail'` or `'all'`),\n * keeping the primary log clean while preserving the full context for debugging.\n * @public\n */\nexport interface IDetailLogger extends ILogger {\n /**\n * Logs a short error summary at `error` level, then emits `detail` at `detail` level.\n * @param message - Short human-readable summary.\n * @param detail - Full detail (e.g. raw converter error) logged at `detail` level.\n */\n errorWithDetail(message: string, detail: unknown): Success<string | undefined>;\n\n /**\n * Logs a short warning summary at `warning` level, then emits `detail` at `detail` level.\n * @param message - Short human-readable summary.\n * @param detail - Full detail logged at `detail` level.\n */\n warnWithDetail(message: string, detail: unknown): Success<string | undefined>;\n}\n\n/**\n * Type guard that checks whether a logger implements {@link IDetailLogger}.\n * @param logger - The logger to check.\n * @returns `true` if the logger implements `IDetailLogger`.\n * @public\n */\nexport function isDetailLogger(logger: ILogger): logger is IDetailLogger {\n return (\n typeof (logger as IDetailLogger).errorWithDetail === 'function' &&\n typeof (logger as IDetailLogger).warnWithDetail === 'function'\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-utils",
3
- "version": "5.1.0-33",
3
+ "version": "5.1.0-34",
4
4
  "description": "Assorted Typescript Utilities",
5
5
  "main": "lib/index.js",
6
6
  "module": "dist/index.js",
@@ -54,8 +54,8 @@
54
54
  "@rushstack/heft-jest-plugin": "1.2.6",
55
55
  "eslint-plugin-tsdoc": "~0.5.2",
56
56
  "typedoc": "~0.28.16",
57
- "@fgv/heft-dual-rig": "5.1.0-33",
58
- "@fgv/typedoc-compact-theme": "5.1.0-33"
57
+ "@fgv/heft-dual-rig": "5.1.0-34",
58
+ "@fgv/typedoc-compact-theme": "5.1.0-34"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",