@warlock.js/logger 4.0.174 → 4.1.1

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 (135) hide show
  1. package/README.md +145 -422
  2. package/cjs/index.cjs +1003 -0
  3. package/cjs/index.cjs.map +1 -0
  4. package/esm/channels/console-log.d.mts +40 -0
  5. package/esm/channels/console-log.d.mts.map +1 -0
  6. package/esm/channels/console-log.mjs +51 -0
  7. package/esm/channels/console-log.mjs.map +1 -0
  8. package/esm/channels/file-log.d.mts +194 -0
  9. package/esm/channels/file-log.d.mts.map +1 -0
  10. package/esm/channels/file-log.mjs +267 -0
  11. package/esm/channels/file-log.mjs.map +1 -0
  12. package/esm/channels/index.mjs +5 -0
  13. package/esm/channels/json-file-log.d.mts +33 -0
  14. package/esm/channels/json-file-log.d.mts.map +1 -0
  15. package/esm/channels/json-file-log.mjs +137 -0
  16. package/esm/channels/json-file-log.mjs.map +1 -0
  17. package/esm/index.d.mts +11 -0
  18. package/esm/index.mjs +13 -0
  19. package/esm/log-channel.d.mts +78 -0
  20. package/esm/log-channel.d.mts.map +1 -0
  21. package/esm/log-channel.mjs +75 -0
  22. package/esm/log-channel.mjs.map +1 -0
  23. package/esm/logger.d.mts +184 -0
  24. package/esm/logger.d.mts.map +1 -0
  25. package/esm/logger.mjs +282 -0
  26. package/esm/logger.mjs.map +1 -0
  27. package/esm/redact/redact.d.mts +25 -0
  28. package/esm/redact/redact.d.mts.map +1 -0
  29. package/esm/redact/redact.mjs +109 -0
  30. package/esm/redact/redact.mjs.map +1 -0
  31. package/esm/types.d.mts +129 -0
  32. package/esm/types.d.mts.map +1 -0
  33. package/esm/utils/capture-unhandled-errors.d.mts +16 -0
  34. package/esm/utils/capture-unhandled-errors.d.mts.map +1 -0
  35. package/esm/utils/capture-unhandled-errors.mjs +26 -0
  36. package/esm/utils/capture-unhandled-errors.mjs.map +1 -0
  37. package/esm/utils/clear-message.d.mts +8 -0
  38. package/esm/utils/clear-message.d.mts.map +1 -0
  39. package/esm/utils/clear-message.mjs +12 -0
  40. package/esm/utils/clear-message.mjs.map +1 -0
  41. package/esm/utils/index.mjs +5 -0
  42. package/esm/utils/safe-json-stringify.d.mts +14 -0
  43. package/esm/utils/safe-json-stringify.d.mts.map +1 -0
  44. package/esm/utils/safe-json-stringify.mjs +35 -0
  45. package/esm/utils/safe-json-stringify.mjs.map +1 -0
  46. package/llms-full.txt +1296 -0
  47. package/llms.txt +19 -0
  48. package/package.json +39 -39
  49. package/skills/capture-unhandled-errors/SKILL.md +103 -0
  50. package/skills/configure-logger/SKILL.md +105 -0
  51. package/skills/filter-log-entries/SKILL.md +120 -0
  52. package/skills/flush-logs-on-shutdown/SKILL.md +91 -0
  53. package/skills/logger-basics/SKILL.md +85 -0
  54. package/skills/overview/SKILL.md +86 -0
  55. package/skills/pick-log-channel/SKILL.md +139 -0
  56. package/skills/redact-sensitive-log-fields/SKILL.md +122 -0
  57. package/skills/test-logging-code/SKILL.md +169 -0
  58. package/skills/use-log-helpers/SKILL.md +66 -0
  59. package/skills/write-custom-log-channel/SKILL.md +160 -0
  60. package/cjs/channels/console-log.d.ts +0 -17
  61. package/cjs/channels/console-log.d.ts.map +0 -1
  62. package/cjs/channels/console-log.js +0 -47
  63. package/cjs/channels/console-log.js.map +0 -1
  64. package/cjs/channels/file-log.d.ts +0 -171
  65. package/cjs/channels/file-log.d.ts.map +0 -1
  66. package/cjs/channels/file-log.js +0 -293
  67. package/cjs/channels/file-log.js.map +0 -1
  68. package/cjs/channels/index.d.ts +0 -4
  69. package/cjs/channels/index.d.ts.map +0 -1
  70. package/cjs/channels/json-file-log.d.ts +0 -33
  71. package/cjs/channels/json-file-log.d.ts.map +0 -1
  72. package/cjs/channels/json-file-log.js +0 -164
  73. package/cjs/channels/json-file-log.js.map +0 -1
  74. package/cjs/index.d.ts +0 -6
  75. package/cjs/index.d.ts.map +0 -1
  76. package/cjs/index.js +0 -1
  77. package/cjs/index.js.map +0 -1
  78. package/cjs/log-channel.d.ts +0 -67
  79. package/cjs/log-channel.d.ts.map +0 -1
  80. package/cjs/log-channel.js +0 -88
  81. package/cjs/log-channel.js.map +0 -1
  82. package/cjs/logger.d.ts +0 -62
  83. package/cjs/logger.d.ts.map +0 -1
  84. package/cjs/logger.js +0 -124
  85. package/cjs/logger.js.map +0 -1
  86. package/cjs/types.d.ts +0 -104
  87. package/cjs/types.d.ts.map +0 -1
  88. package/cjs/utils/capture-unhandled-errors.d.ts +0 -2
  89. package/cjs/utils/capture-unhandled-errors.d.ts.map +0 -1
  90. package/cjs/utils/capture-unhandled-errors.js +0 -12
  91. package/cjs/utils/capture-unhandled-errors.js.map +0 -1
  92. package/cjs/utils/clear-message.d.ts +0 -5
  93. package/cjs/utils/clear-message.d.ts.map +0 -1
  94. package/cjs/utils/clear-message.js +0 -9
  95. package/cjs/utils/clear-message.js.map +0 -1
  96. package/cjs/utils/index.d.ts +0 -3
  97. package/cjs/utils/index.d.ts.map +0 -1
  98. package/esm/channels/console-log.d.ts +0 -17
  99. package/esm/channels/console-log.d.ts.map +0 -1
  100. package/esm/channels/console-log.js +0 -47
  101. package/esm/channels/console-log.js.map +0 -1
  102. package/esm/channels/file-log.d.ts +0 -171
  103. package/esm/channels/file-log.d.ts.map +0 -1
  104. package/esm/channels/file-log.js +0 -293
  105. package/esm/channels/file-log.js.map +0 -1
  106. package/esm/channels/index.d.ts +0 -4
  107. package/esm/channels/index.d.ts.map +0 -1
  108. package/esm/channels/json-file-log.d.ts +0 -33
  109. package/esm/channels/json-file-log.d.ts.map +0 -1
  110. package/esm/channels/json-file-log.js +0 -164
  111. package/esm/channels/json-file-log.js.map +0 -1
  112. package/esm/index.d.ts +0 -6
  113. package/esm/index.d.ts.map +0 -1
  114. package/esm/index.js +0 -1
  115. package/esm/index.js.map +0 -1
  116. package/esm/log-channel.d.ts +0 -67
  117. package/esm/log-channel.d.ts.map +0 -1
  118. package/esm/log-channel.js +0 -88
  119. package/esm/log-channel.js.map +0 -1
  120. package/esm/logger.d.ts +0 -62
  121. package/esm/logger.d.ts.map +0 -1
  122. package/esm/logger.js +0 -124
  123. package/esm/logger.js.map +0 -1
  124. package/esm/types.d.ts +0 -104
  125. package/esm/types.d.ts.map +0 -1
  126. package/esm/utils/capture-unhandled-errors.d.ts +0 -2
  127. package/esm/utils/capture-unhandled-errors.d.ts.map +0 -1
  128. package/esm/utils/capture-unhandled-errors.js +0 -12
  129. package/esm/utils/capture-unhandled-errors.js.map +0 -1
  130. package/esm/utils/clear-message.d.ts +0 -5
  131. package/esm/utils/clear-message.d.ts.map +0 -1
  132. package/esm/utils/clear-message.js +0 -9
  133. package/esm/utils/clear-message.js.map +0 -1
  134. package/esm/utils/index.d.ts +0 -3
  135. package/esm/utils/index.d.ts.map +0 -1
package/cjs/index.cjs ADDED
@@ -0,0 +1,1003 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let _mongez_copper = require("@mongez/copper");
30
+ let util = require("util");
31
+ let _warlock_js_fs = require("@warlock.js/fs");
32
+ let dayjs = require("dayjs");
33
+ dayjs = __toESM(dayjs, 1);
34
+ let fs = require("fs");
35
+ fs = __toESM(fs, 1);
36
+ let os = require("os");
37
+ let path = require("path");
38
+ path = __toESM(path, 1);
39
+ let safe_stable_stringify = require("safe-stable-stringify");
40
+ let _mongez_reinforcements = require("@mongez/reinforcements");
41
+
42
+ //#region ../../@warlock.js/logger/src/log-channel.ts
43
+ var LogChannel = class {
44
+ /**
45
+ * Constructor
46
+ */
47
+ constructor(configurations) {
48
+ this.terminal = false;
49
+ this.defaultConfigurations = {};
50
+ this.channelConfigurations = {};
51
+ this.isInitialized = false;
52
+ if (configurations) this.setConfigurations(configurations);
53
+ setTimeout(async () => {
54
+ if (this.init) await this.init();
55
+ this.isInitialized = true;
56
+ }, 0);
57
+ }
58
+ /**
59
+ * Get config value
60
+ */
61
+ config(key) {
62
+ return this.channelConfigurations[key] ?? (this.defaultConfigurations ?? {})[key];
63
+ }
64
+ /**
65
+ * Set configurations
66
+ */
67
+ setConfigurations(configurations) {
68
+ this.channelConfigurations = {
69
+ ...this.channelConfigurations,
70
+ ...configurations
71
+ };
72
+ return this;
73
+ }
74
+ /**
75
+ * Determine if the message should be logged
76
+ */
77
+ shouldBeLogged(data) {
78
+ const allowedLevels = this.config("levels");
79
+ if (allowedLevels?.length && !allowedLevels.includes(data.type)) return false;
80
+ const filter = this.config("filter");
81
+ if (filter) return filter(data);
82
+ return true;
83
+ }
84
+ /**
85
+ * Read the channel's redact config (if any). Used by `Logger` to apply
86
+ * per-channel additive redaction on top of the logger-wide floor.
87
+ * Subclasses normally don't override this — set `redact` in your channel
88
+ * configuration instead.
89
+ */
90
+ getRedactConfig() {
91
+ return this.config("redact");
92
+ }
93
+ /**
94
+ * Get date and time formats
95
+ */
96
+ getDateAndTimeFormat() {
97
+ const dateFormat = this.config("dateFormat");
98
+ return {
99
+ date: dateFormat?.date ?? "DD-MM-YYYY",
100
+ time: dateFormat?.time ?? "HH:mm:ss"
101
+ };
102
+ }
103
+ /**
104
+ * get basic configurations with the given ones
105
+ */
106
+ withBasicConfigurations(configurations) {
107
+ return {
108
+ filter: () => true,
109
+ ...configurations
110
+ };
111
+ }
112
+ };
113
+
114
+ //#endregion
115
+ //#region ../../@warlock.js/logger/src/channels/console-log.ts
116
+ var ConsoleLog = class extends LogChannel {
117
+ constructor(..._args) {
118
+ super(..._args);
119
+ this.name = "console";
120
+ this.terminal = true;
121
+ }
122
+ /**
123
+ * {@inheritdoc}
124
+ */
125
+ log(data) {
126
+ const { module, action, message, type: level } = data;
127
+ if (!this.shouldBeLogged(data)) return;
128
+ const date = (/* @__PURE__ */ new Date()).toISOString();
129
+ switch (level) {
130
+ case "debug":
131
+ console.log(_mongez_copper.colors.magentaBright("⚙"), _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), _mongez_copper.colors.magentaBright(message));
132
+ break;
133
+ case "info":
134
+ console.log(_mongez_copper.colors.blueBright("ℹ"), _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), _mongez_copper.colors.blueBright(message));
135
+ break;
136
+ case "warn":
137
+ console.log(_mongez_copper.colors.yellow("⚠"), _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), _mongez_copper.colors.yellowBright(message));
138
+ break;
139
+ case "error":
140
+ console.log(_mongez_copper.colors.red("✗"), _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), _mongez_copper.colors.redBright(message));
141
+ break;
142
+ case "success":
143
+ console.log(_mongez_copper.colors.green("✓"), _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), _mongez_copper.colors.greenBright(message));
144
+ break;
145
+ default: console.log("[log]", _mongez_copper.colors.yellow(`(${date})`), _mongez_copper.colors.cyan(`[${module}]`), _mongez_copper.colors.magenta(`[${action}]`), message);
146
+ }
147
+ if (typeof message === "object") console.log(message);
148
+ if (this.config("showContext") && data.context && Object.keys(data.context).length > 0) {
149
+ const depth = this.config("contextDepth") ?? 4;
150
+ console.log(_mongez_copper.colors.gray(" ↳"), (0, util.inspect)(data.context, {
151
+ colors: true,
152
+ depth,
153
+ breakLength: 80
154
+ }));
155
+ }
156
+ }
157
+ };
158
+
159
+ //#endregion
160
+ //#region ../../@warlock.js/logger/src/channels/file-log.ts
161
+ var FileLog = class extends LogChannel {
162
+ constructor(..._args) {
163
+ super(..._args);
164
+ this.name = "file";
165
+ this.messages = [];
166
+ this.groupedMessages = {};
167
+ this.defaultConfigurations = {
168
+ storagePath: process.cwd() + "/storage/logs",
169
+ rotate: true,
170
+ name: "app",
171
+ extension: "log",
172
+ chunk: "single",
173
+ maxMessagesToWrite: 100,
174
+ filter: () => true,
175
+ maxFileSize: 10 * 1024 * 1024,
176
+ get rotateFileName() {
177
+ return (0, dayjs.default)().format("DD-MM-YYYY");
178
+ },
179
+ dateFormat: {
180
+ date: "DD-MM-YYYY",
181
+ time: "HH:mm:ss"
182
+ }
183
+ };
184
+ this.lastWriteTime = Date.now();
185
+ this.isWriting = false;
186
+ }
187
+ /**
188
+ * Check file size for file rotation
189
+ */
190
+ async checkAndRotateFile(filePath = this.filePath) {
191
+ if (!this.config("rotate")) return;
192
+ try {
193
+ if ((await fs.default.promises.stat(filePath)).size >= this.config("maxFileSize")) await this.rotateLogFile();
194
+ } catch (error) {
195
+ if (error.code !== "ENOENT") console.error("Error checking log file:", error);
196
+ }
197
+ }
198
+ /**
199
+ * Rotate log file
200
+ */
201
+ async rotateLogFile() {
202
+ const fileName = `${this.fileName}-${this.config("rotateFileName")}-${Date.now()}`;
203
+ const extension = this.extension;
204
+ const rotatedFilePath = path.default.join(this.storagePath, `${fileName}.${extension}`);
205
+ await fs.default.promises.rename(this.filePath, rotatedFilePath).catch((error) => {
206
+ console.error("Error rotating file:", error);
207
+ });
208
+ }
209
+ /**
210
+ * Flush messages
211
+ *
212
+ * Starts a periodic re-check so low-traffic channels don't sit on buffered
213
+ * entries indefinitely. The handle is stored on the instance so `dispose()`
214
+ * can stop it — without this, every channel leaks a timer for the lifetime
215
+ * of the process.
216
+ */
217
+ initMessageFlush() {
218
+ this.flushIntervalHandle = setInterval(() => {
219
+ if (this.messages.length > 0 && (this.messages.length >= this.maxMessagesToWrite || Date.now() - this.lastWriteTime > 5e3)) this.writeMessagesToFile();
220
+ }, 5e3);
221
+ }
222
+ /**
223
+ * Stop the background flush interval and drain any buffered entries.
224
+ *
225
+ * Call this when discarding a channel (e.g. reconfiguring the logger at
226
+ * runtime) so the 5-second timer doesn't keep the event loop alive. Safe to
227
+ * call more than once.
228
+ */
229
+ dispose() {
230
+ if (this.flushIntervalHandle) {
231
+ clearInterval(this.flushIntervalHandle);
232
+ this.flushIntervalHandle = void 0;
233
+ }
234
+ this.flushSync();
235
+ }
236
+ /**
237
+ * Get file path
238
+ */
239
+ get filePath() {
240
+ const fileName = this.fileName;
241
+ const extension = this.extension;
242
+ return path.default.join(this.storagePath, `${fileName}.${extension}`);
243
+ }
244
+ /**
245
+ * Get max messages
246
+ */
247
+ get maxMessagesToWrite() {
248
+ return this.config("maxMessagesToWrite");
249
+ }
250
+ /**
251
+ * Get file name
252
+ */
253
+ get fileName() {
254
+ switch (this.config("chunk")) {
255
+ case "single":
256
+ default: return this.config("name");
257
+ case "daily": return (0, dayjs.default)().format("DD-MM-YYYY");
258
+ case "hourly": return (0, dayjs.default)().format("DD-MM-YYYY-HH-00-00-a");
259
+ }
260
+ }
261
+ /**
262
+ * Get file extension
263
+ */
264
+ get extension() {
265
+ return this.config("extension");
266
+ }
267
+ /**
268
+ * Get content
269
+ */
270
+ get content() {
271
+ return this.messages.map((message) => message.content).join(os.EOL) + os.EOL;
272
+ }
273
+ /**
274
+ * Get storage path
275
+ */
276
+ get storagePath() {
277
+ return this.config("storagePath");
278
+ }
279
+ /**
280
+ * {@inheritdoc}
281
+ */
282
+ async init() {
283
+ const logsDirectory = this.storagePath;
284
+ await (0, _warlock_js_fs.ensureDirectoryAsync)(logsDirectory);
285
+ this.initMessageFlush();
286
+ }
287
+ /**
288
+ * Synchronously flush messages
289
+ */
290
+ flushSync() {
291
+ if (this.messages.length === 0 && Object.keys(this.groupedMessages).length === 0) return;
292
+ if (this.messagedShouldBeGrouped) {
293
+ this.prepareGroupedMessages();
294
+ for (const key in this.groupedMessages) {
295
+ const directoryPath = path.default.join(this.storagePath, key);
296
+ fs.default.mkdirSync(directoryPath, { recursive: true });
297
+ const filePath = path.default.join(directoryPath, `${this.fileName}.${this.extension}`);
298
+ const content = this.groupedMessages[key].map((message) => message.content).join(os.EOL) + os.EOL;
299
+ fs.default.appendFileSync(filePath, content);
300
+ }
301
+ } else {
302
+ fs.default.mkdirSync(this.storagePath, { recursive: true });
303
+ fs.default.appendFileSync(this.filePath, this.content);
304
+ }
305
+ this.onSave();
306
+ }
307
+ /**
308
+ * {@inheritdoc}
309
+ */
310
+ async log(data) {
311
+ const { module, action, message, type: level, context } = data;
312
+ if (!this.shouldBeLogged(data)) return;
313
+ const { date: dateFormat, time } = this.getDateAndTimeFormat();
314
+ const date = (0, dayjs.default)().format(dateFormat + " " + time);
315
+ let content = `[${date}] [${level}] [${module}][${action}]: `;
316
+ let stack;
317
+ if (message instanceof Error) {
318
+ content += message.message + os.EOL;
319
+ content += `[trace]` + os.EOL;
320
+ content += message.stack;
321
+ stack = message.stack;
322
+ } else content += message;
323
+ this.messages.push({
324
+ content,
325
+ level,
326
+ date,
327
+ module,
328
+ action,
329
+ stack,
330
+ context,
331
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
332
+ });
333
+ await this.checkIfMessagesShouldBeWritten();
334
+ }
335
+ /**
336
+ * Check if messages should be written
337
+ */
338
+ async checkIfMessagesShouldBeWritten() {
339
+ if (this.messages.length >= this.maxMessagesToWrite || Date.now() - this.lastWriteTime > 5e3) await this.writeMessagesToFile();
340
+ }
341
+ /**
342
+ * Should be called after messages are saved
343
+ */
344
+ onSave() {
345
+ this.messages = [];
346
+ this.groupedMessages = {};
347
+ this.isWriting = false;
348
+ this.lastWriteTime = Date.now();
349
+ }
350
+ /**
351
+ * Check if messages should be grouped
352
+ */
353
+ get messagedShouldBeGrouped() {
354
+ return Number(this.config("groupBy")?.length) > 0;
355
+ }
356
+ /**
357
+ * Write messages to the file
358
+ */
359
+ async writeMessagesToFile() {
360
+ if (this.messages.length === 0 || this.isWriting || !this.isInitialized) return;
361
+ this.isWriting = true;
362
+ if (this.messagedShouldBeGrouped) return await this.writeGroupedMessagesToFile();
363
+ await this.checkAndRotateFile();
364
+ try {
365
+ await this.write(this.filePath, this.content);
366
+ this.onSave();
367
+ } catch (error) {
368
+ console.error("Failed to write log:", error);
369
+ this.isWriting = false;
370
+ }
371
+ }
372
+ /**
373
+ * Write grouped messages to the file
374
+ */
375
+ async writeGroupedMessagesToFile() {
376
+ this.prepareGroupedMessages();
377
+ for (const key in this.groupedMessages) {
378
+ const directoryPath = path.default.join(this.storagePath, key);
379
+ await (0, _warlock_js_fs.ensureDirectoryAsync)(directoryPath);
380
+ const filePath = path.default.join(directoryPath, `${this.fileName}.${this.extension}`);
381
+ await this.checkAndRotateFile(filePath);
382
+ const content = this.groupedMessages[key].map((message) => message.content).join(os.EOL) + os.EOL;
383
+ try {
384
+ await this.write(filePath, content);
385
+ } catch (error) {
386
+ console.error("Failed to write log:", error);
387
+ }
388
+ }
389
+ this.onSave();
390
+ this.isWriting = false;
391
+ }
392
+ /**
393
+ * Prepare grouped messages
394
+ */
395
+ prepareGroupedMessages() {
396
+ this.messages.forEach((message) => {
397
+ const key = this.config("groupBy").map((groupKey) => encodeURIComponent(message[groupKey])).join("/");
398
+ this.groupedMessages[key] = this.groupedMessages[key] || [];
399
+ this.groupedMessages[key].push(message);
400
+ });
401
+ }
402
+ /**
403
+ * Start writing to the file
404
+ */
405
+ async write(filePath, content) {
406
+ return new Promise((resolve, reject) => {
407
+ const writer = fs.default.createWriteStream(filePath, { flags: "a" });
408
+ writer.write(content, (error) => {
409
+ writer.end();
410
+ if (error) reject(error);
411
+ else resolve(true);
412
+ });
413
+ });
414
+ }
415
+ };
416
+
417
+ //#endregion
418
+ //#region ../../@warlock.js/logger/src/utils/safe-json-stringify.ts
419
+ /**
420
+ * Replacer that surfaces Error data — `name`, `message`, and `stack` are
421
+ * non-enumerable on `Error`, so neither default JSON serialization nor an
422
+ * object spread captures them (both produce `{}`). They are copied explicitly;
423
+ * the trailing spread then captures any additional enumerable props the caller
424
+ * (or a subclass) attached, such as a `code` field.
425
+ */
426
+ function errorReplacer(_key, value) {
427
+ if (value instanceof Error) return {
428
+ ...value,
429
+ name: value.name,
430
+ message: value.message,
431
+ stack: value.stack
432
+ };
433
+ return value;
434
+ }
435
+ /**
436
+ * JSON-serialize log payloads safely. Circular refs, BigInt, and repeated
437
+ * non-tree references are handled by `safe-stable-stringify`; functions and
438
+ * symbols are dropped (standard JSON behavior); Errors are expanded via
439
+ * `errorReplacer`. Class instances serialize as their enumerable props.
440
+ *
441
+ * @example
442
+ * await fs.promises.writeFile(filePath, safeJsonStringify(payload, 2));
443
+ */
444
+ function safeJsonStringify(value, space) {
445
+ return (0, safe_stable_stringify.stringify)(value, errorReplacer, space) ?? "";
446
+ }
447
+
448
+ //#endregion
449
+ //#region ../../@warlock.js/logger/src/channels/json-file-log.ts
450
+ var JSONFileLog = class extends FileLog {
451
+ constructor(..._args) {
452
+ super(..._args);
453
+ this.name = "fileJson";
454
+ }
455
+ /**
456
+ * Get file extension
457
+ */
458
+ get extension() {
459
+ return "json";
460
+ }
461
+ /**
462
+ * Synchronously flush messages
463
+ */
464
+ flushSync() {
465
+ if (this.messages.length === 0 && Object.keys(this.groupedMessages).length === 0) return;
466
+ if (this.messagedShouldBeGrouped) {
467
+ this.prepareGroupedMessages();
468
+ for (const key in this.groupedMessages) {
469
+ const directoryPath = path.default.join(this.storagePath, key);
470
+ fs.default.mkdirSync(directoryPath, { recursive: true });
471
+ const filePath = path.default.join(directoryPath, `${this.fileName}.${this.extension}`);
472
+ let fileContents = { messages: [] };
473
+ if (fs.default.existsSync(filePath)) try {
474
+ fileContents = JSON.parse(fs.default.readFileSync(filePath, "utf-8"));
475
+ if (!Array.isArray(fileContents.messages)) fileContents.messages = [];
476
+ } catch (e) {
477
+ fileContents = { messages: [] };
478
+ }
479
+ fileContents.messages.push(...this.groupedMessages[key]);
480
+ fs.default.writeFileSync(filePath, safeJsonStringify(fileContents, 2));
481
+ }
482
+ } else {
483
+ fs.default.mkdirSync(this.storagePath, { recursive: true });
484
+ let fileContents = { messages: [] };
485
+ if (fs.default.existsSync(this.filePath)) try {
486
+ fileContents = JSON.parse(fs.default.readFileSync(this.filePath, "utf-8"));
487
+ if (!Array.isArray(fileContents.messages)) fileContents.messages = [];
488
+ } catch (e) {
489
+ fileContents = { messages: [] };
490
+ }
491
+ fileContents.messages.push(...this.messages);
492
+ fs.default.writeFileSync(this.filePath, safeJsonStringify(fileContents, 2));
493
+ }
494
+ this.onSave();
495
+ }
496
+ /**
497
+ * {@inheritdoc}
498
+ */
499
+ async log(data) {
500
+ let stack;
501
+ if (data.message instanceof Error) {
502
+ stack = data.message.stack?.split("\n");
503
+ data.message = data.message.message;
504
+ }
505
+ const { module, action, message, type: level, context } = data;
506
+ if (!this.shouldBeLogged(data)) return;
507
+ const { date: dateFormat, time } = this.getDateAndTimeFormat();
508
+ const date = (0, dayjs.default)().format(dateFormat + " " + time);
509
+ this.messages.push({
510
+ content: message,
511
+ level,
512
+ date,
513
+ module,
514
+ action,
515
+ stack,
516
+ context,
517
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
518
+ });
519
+ await this.checkIfMessagesShouldBeWritten();
520
+ }
521
+ /**
522
+ * Write messages to the file
523
+ */
524
+ async writeMessagesToFile() {
525
+ if (this.messages.length === 0 || this.isWriting || !this.isInitialized) return;
526
+ this.isWriting = true;
527
+ if (this.messagedShouldBeGrouped) return await this.writeGroupedMessagesToFile();
528
+ await this.checkAndRotateFile();
529
+ let fileContents = { messages: [] };
530
+ if (await (0, _warlock_js_fs.fileExistsAsync)(this.filePath)) try {
531
+ fileContents = await (0, _warlock_js_fs.getJsonFileAsync)(this.filePath);
532
+ } catch (error) {
533
+ console.error("Error reading log file, reinitializing:", error);
534
+ fileContents = { messages: [] };
535
+ }
536
+ else fileContents = { messages: [] };
537
+ fileContents.messages.push(...this.messages);
538
+ try {
539
+ await fs.default.promises.writeFile(this.filePath, safeJsonStringify(fileContents, 2));
540
+ this.onSave();
541
+ } catch (error) {
542
+ console.error("Failed to write log:", error);
543
+ this.isWriting = false;
544
+ }
545
+ }
546
+ /**
547
+ * Write grouped messages to the file
548
+ */
549
+ async writeGroupedMessagesToFile() {
550
+ this.prepareGroupedMessages();
551
+ for (const key in this.groupedMessages) {
552
+ const directoryPath = path.default.join(this.storagePath, key);
553
+ await (0, _warlock_js_fs.ensureDirectoryAsync)(directoryPath);
554
+ const filePath = path.default.join(directoryPath, `${this.fileName}.${this.extension}`);
555
+ await this.checkAndRotateFile(filePath);
556
+ let fileContents = { messages: [] };
557
+ if (await (0, _warlock_js_fs.fileExistsAsync)(filePath)) try {
558
+ fileContents = await (0, _warlock_js_fs.getJsonFileAsync)(filePath);
559
+ } catch (error) {
560
+ console.error("Error reading log file, reinitializing:", error);
561
+ fileContents = { messages: [] };
562
+ }
563
+ else fileContents = { messages: [] };
564
+ fileContents.messages.push(...this.groupedMessages[key]);
565
+ try {
566
+ await fs.default.promises.writeFile(filePath, safeJsonStringify(fileContents, 2));
567
+ } catch (error) {
568
+ console.error("Failed to write log:", error);
569
+ this.isWriting = false;
570
+ }
571
+ }
572
+ this.onSave();
573
+ }
574
+ };
575
+
576
+ //#endregion
577
+ //#region ../../@warlock.js/logger/src/redact/redact.ts
578
+ /**
579
+ * Deep-clone a value with structural fidelity for log entries — handles plain
580
+ * objects, arrays, `Date`, `Error`, and primitives. Anything else is copied
581
+ * by reference (we only redact paths through plain objects/arrays anyway,
582
+ * and rebuilding e.g. a `Buffer` would change semantics).
583
+ *
584
+ * Purpose-built rather than reaching for `structuredClone`: `Error` instances
585
+ * lose their `message`/`stack` under `structuredClone` in some Node versions,
586
+ * and the logger pipeline carries them often.
587
+ */
588
+ function cloneEntry(value, seen = /* @__PURE__ */ new WeakMap()) {
589
+ if (value === null || typeof value !== "object") return value;
590
+ if (seen.has(value)) return seen.get(value);
591
+ if (value instanceof Date) return new Date(value.getTime());
592
+ if (value instanceof Error) {
593
+ const copy = new value.constructor(value.message);
594
+ copy.stack = value.stack;
595
+ copy.name = value.name;
596
+ return copy;
597
+ }
598
+ if (Array.isArray(value)) {
599
+ const arr = [];
600
+ seen.set(value, arr);
601
+ for (const item of value) arr.push(cloneEntry(item, seen));
602
+ return arr;
603
+ }
604
+ const out = {};
605
+ seen.set(value, out);
606
+ for (const key of Object.keys(value)) out[key] = cloneEntry(value[key], seen);
607
+ return out;
608
+ }
609
+ /**
610
+ * Apply a single censor decision to a value. String censors are returned
611
+ * verbatim; function censors receive the original value plus the dotted
612
+ * path so callers can implement value-aware redaction (mask all but the
613
+ * last 4 chars, hash, etc.).
614
+ */
615
+ function applyCensor(value, censor, path) {
616
+ if (typeof censor === "function") return censor(value, path.join("."));
617
+ return censor;
618
+ }
619
+ /**
620
+ * Walk `target` following the remaining `segments` of a path pattern,
621
+ * replacing matched leaves via `censor`. Operates in place — the caller
622
+ * is responsible for cloning before calling.
623
+ *
624
+ * Wildcards:
625
+ * - `*` matches exactly one segment (any key on a plain object, any index
626
+ * on an array — stringified for the path that's passed to a function
627
+ * censor).
628
+ * - `**` matches zero or more segments greedily; the rest of the pattern
629
+ * is then attempted at the current level and at every descendant.
630
+ */
631
+ function redactAtPath(target, segments, censor, pathTrail) {
632
+ if (target === null || typeof target !== "object") return;
633
+ if (segments.length === 0) return;
634
+ const [head, ...rest] = segments;
635
+ if (head === "**") {
636
+ if (rest.length > 0) redactAtPath(target, rest, censor, pathTrail);
637
+ const keys = Array.isArray(target) ? target.map((_, index) => String(index)) : Object.keys(target);
638
+ for (const key of keys) redactAtPath(target[key], segments, censor, [...pathTrail, key]);
639
+ return;
640
+ }
641
+ const keysToVisit = head === "*" ? Array.isArray(target) ? target.map((_, index) => String(index)) : Object.keys(target) : Array.isArray(target) ? /^\d+$/.test(head) && Number(head) < target.length ? [head] : [] : Object.prototype.hasOwnProperty.call(target, head) ? [head] : [];
642
+ for (const key of keysToVisit) if (rest.length === 0) target[key] = applyCensor(target[key], censor, [...pathTrail, key]);
643
+ else redactAtPath(target[key], rest, censor, [...pathTrail, key]);
644
+ }
645
+ /**
646
+ * Produce a new `LoggingData` with every path in `config.paths` replaced
647
+ * by `config.censor`. The original entry is never mutated — channels and
648
+ * other call sites can hold references to the input safely.
649
+ *
650
+ * No-op (returns the input by reference) when `config` is `undefined` or
651
+ * its `paths` array is empty, so the fast path stays fast.
652
+ */
653
+ function applyRedact(data, config) {
654
+ if (!config || config.paths.length === 0) return data;
655
+ const censor = config.censor ?? "[REDACTED]";
656
+ const cloned = cloneEntry(data);
657
+ for (const pattern of config.paths) {
658
+ const segments = pattern.split(".").filter((segment) => segment.length > 0);
659
+ if (segments.length === 0) continue;
660
+ redactAtPath(cloned, segments, censor, []);
661
+ }
662
+ return cloned;
663
+ }
664
+ /**
665
+ * Combine two redact configs into one effective config. Used to merge a
666
+ * channel's additive paths on top of the logger-wide floor.
667
+ *
668
+ * - `paths` are concatenated; duplicates are kept (the matcher tolerates
669
+ * them, and de-duping cross-config would mask a developer typo).
670
+ * - `censor` from the channel wins; falls back to the logger's; falls back
671
+ * to the default `"[REDACTED]"`.
672
+ */
673
+ function mergeRedact(base, extra) {
674
+ if (!base && !extra) return void 0;
675
+ if (!base) return extra;
676
+ if (!extra) return base;
677
+ return {
678
+ paths: [...base.paths, ...extra.paths],
679
+ censor: extra.censor ?? base.censor
680
+ };
681
+ }
682
+
683
+ //#endregion
684
+ //#region ../../@warlock.js/logger/src/utils/clear-message.ts
685
+ /**
686
+ * Clear message from any terminal codes
687
+ */
688
+ function clearMessage(message) {
689
+ if (typeof message !== "string") return message;
690
+ return message.replace(/\u001b[^m]*?m/g, "");
691
+ }
692
+
693
+ //#endregion
694
+ //#region ../../@warlock.js/logger/src/logger.ts
695
+ const SIGNAL_EVENTS = new Set([
696
+ "SIGINT",
697
+ "SIGTERM",
698
+ "SIGHUP",
699
+ "SIGBREAK",
700
+ "SIGUSR2"
701
+ ]);
702
+ /**
703
+ * Severity ranks used by `setMinLevel`. Higher number = more severe. The
704
+ * ordering matches conventional log-level hierarchies: `debug` is noisiest
705
+ * and easiest to drop; `error` is the loudest and never dropped by the
706
+ * minimum-level filter. `success` sits beside `info` — it's an informational
707
+ * outcome, not a warning.
708
+ */
709
+ const LEVEL_RANK = {
710
+ debug: 0,
711
+ info: 1,
712
+ success: 1,
713
+ warn: 2,
714
+ error: 3
715
+ };
716
+ var Logger = class {
717
+ constructor() {
718
+ this.channels = [];
719
+ this.id = "logger-" + _mongez_reinforcements.Random.string(32);
720
+ this.autoFlushHandlers = /* @__PURE__ */ new Map();
721
+ }
722
+ /**
723
+ * Add a new channel
724
+ */
725
+ addChannel(channel) {
726
+ this.channels.push(channel);
727
+ return this;
728
+ }
729
+ /**
730
+ * Set base configurations
731
+ */
732
+ configure(config) {
733
+ if (config.channels) this.channels = config.channels;
734
+ if (config.autoFlushOn) this.enableAutoFlush(config.autoFlushOn);
735
+ if (config.minLevel !== void 0) this.setMinLevel(config.minLevel);
736
+ if (config.redact !== void 0) this.setRedact(config.redact);
737
+ return this;
738
+ }
739
+ /**
740
+ * Set the logger-wide redaction floor. Applied to every entry before
741
+ * fan-out; channel configs add more paths on top, never fewer. Pass
742
+ * `undefined` to clear.
743
+ *
744
+ * @example
745
+ * log.setRedact({
746
+ * paths: ["context.password", "context.*.token"],
747
+ * censor: "[REDACTED]",
748
+ * });
749
+ */
750
+ setRedact(config) {
751
+ this.redactConfig = config;
752
+ return this;
753
+ }
754
+ /**
755
+ * Read the active logger-wide redact config (or `undefined`).
756
+ */
757
+ getRedact() {
758
+ return this.redactConfig;
759
+ }
760
+ /**
761
+ * Drop every entry whose severity is below `level` before fan-out. Cheaper
762
+ * than per-channel `levels` filters because the loop never runs and no
763
+ * channel receives the entry. Pass `undefined` to clear and accept all
764
+ * levels again.
765
+ *
766
+ * @example
767
+ * // production: silence debug noise everywhere at once
768
+ * logger.setMinLevel("info");
769
+ */
770
+ setMinLevel(level) {
771
+ this.minLevel = level;
772
+ return this;
773
+ }
774
+ /**
775
+ * Read the active minimum severity (or `undefined` when none is set).
776
+ */
777
+ getMinLevel() {
778
+ return this.minLevel;
779
+ }
780
+ /**
781
+ * Set channels
782
+ */
783
+ setChannels(channels) {
784
+ this.channels = channels;
785
+ return this;
786
+ }
787
+ /**
788
+ * Normalize log data to a single object
789
+ */
790
+ normalizeLogData(dataOrModule, action, message = "", level, context) {
791
+ if (typeof dataOrModule === "object") return {
792
+ type: level || dataOrModule.type || "info",
793
+ module: dataOrModule.module,
794
+ action: dataOrModule.action,
795
+ message: dataOrModule.message,
796
+ ...context ? { context } : dataOrModule.context ? { context: dataOrModule.context } : {}
797
+ };
798
+ return {
799
+ type: level || "info",
800
+ module: dataOrModule,
801
+ action,
802
+ message,
803
+ ...context ? { context } : {}
804
+ };
805
+ }
806
+ /**
807
+ * Make log
808
+ *
809
+ * Fans out a single log entry to every registered channel. Non-terminal
810
+ * channels receive a copy whose `message` has had ANSI color codes stripped
811
+ * — each channel sees its own shallow clone so one channel cannot observe
812
+ * another's mutations (e.g. a later terminal channel still sees the original
813
+ * colored message).
814
+ */
815
+ async log(data) {
816
+ if (this.minLevel && LEVEL_RANK[data.type] < LEVEL_RANK[this.minLevel]) return this;
817
+ const baseEntry = applyRedact(data, this.redactConfig);
818
+ for (const channel of this.channels) {
819
+ const channelRedact = channel.getRedactConfig?.();
820
+ const effectiveRedact = channelRedact ? mergeRedact(this.redactConfig, channelRedact) : void 0;
821
+ let payload = effectiveRedact ? applyRedact(data, effectiveRedact) : baseEntry;
822
+ if (channel.terminal === false) payload = {
823
+ ...payload,
824
+ message: clearMessage(payload.message)
825
+ };
826
+ channel.log(payload);
827
+ }
828
+ return this;
829
+ }
830
+ /**
831
+ * Make debug log
832
+ */
833
+ debug(dataOrModule, action, message = "", context) {
834
+ const data = this.normalizeLogData(dataOrModule, action, message, "debug", context);
835
+ return this.log(data);
836
+ }
837
+ /**
838
+ * Make info log
839
+ */
840
+ info(dataOrModule, action, message = "", context) {
841
+ const data = this.normalizeLogData(dataOrModule, action, message, "info", context);
842
+ return this.log(data);
843
+ }
844
+ /**
845
+ * Make warn log
846
+ */
847
+ warn(dataOrModule, action, message = "", context) {
848
+ const data = this.normalizeLogData(dataOrModule, action, message, "warn", context);
849
+ return this.log(data);
850
+ }
851
+ /**
852
+ * Make error log
853
+ */
854
+ error(dataOrModule, action, message = "", context) {
855
+ const data = this.normalizeLogData(dataOrModule, action, message, "error", context);
856
+ return this.log(data);
857
+ }
858
+ /**
859
+ * Make success log
860
+ */
861
+ success(dataOrModule, action, message = "", context) {
862
+ const data = this.normalizeLogData(dataOrModule, action, message, "success", context);
863
+ return this.log(data);
864
+ }
865
+ /**
866
+ * Log an `error` entry when `condition` is falsy. No-op otherwise — the
867
+ * entry is never built and channels are not invoked, so this is genuinely
868
+ * free in the happy path. Mirrors the spirit of `console.assert` but routes
869
+ * through the logger pipeline so persistent channels capture failures.
870
+ *
871
+ * @example
872
+ * log.assert(user !== null, "auth", "session", "user vanished mid-flight", { sessionId });
873
+ */
874
+ assert(condition, module, action, message, context) {
875
+ if (condition) return this;
876
+ return this.error(module, action, message, context);
877
+ }
878
+ /**
879
+ * Start a duration timer. The returned function emits an `info` entry
880
+ * with `completed in <ms>ms` and a `durationMs` field in `context` when
881
+ * called. Pass an object to `end()` to merge extra fields into context.
882
+ *
883
+ * @example
884
+ * const end = log.timer("db", "users.findById");
885
+ * const user = await usersRepo.findById(id);
886
+ * end({ id, found: !!user });
887
+ */
888
+ timer(module, action) {
889
+ const startedAt = Date.now();
890
+ return (extra) => {
891
+ const durationMs = Date.now() - startedAt;
892
+ return this.info(module, action, `completed in ${durationMs}ms`, {
893
+ durationMs,
894
+ ...extra ?? {}
895
+ });
896
+ };
897
+ }
898
+ /**
899
+ * Get channel by name
900
+ */
901
+ channel(name) {
902
+ return this.channels.find((channel) => channel.name === name);
903
+ }
904
+ /**
905
+ * Synchronously flush logs
906
+ */
907
+ flushSync() {
908
+ for (const channel of this.channels) if (channel.flushSync) channel.flushSync();
909
+ }
910
+ /**
911
+ * Register one process-level handler per event that calls `flushSync()`
912
+ * before the process terminates.
913
+ *
914
+ * For signal events (`SIGINT`, `SIGTERM`, `SIGHUP`, `SIGBREAK`, `SIGUSR2`)
915
+ * the handler flushes and then re-raises the signal so Node's default exit
916
+ * behavior runs. For `beforeExit`, the handler flushes in place — Node exits
917
+ * naturally afterwards.
918
+ *
919
+ * Idempotent: calling with the same events replaces the previous handlers.
920
+ * Call `disableAutoFlush()` to unregister.
921
+ *
922
+ * @example
923
+ * log.configure({
924
+ * channels: [new ConsoleLog(), new FileLog()],
925
+ * autoFlushOn: ["SIGINT", "SIGTERM", "beforeExit"],
926
+ * });
927
+ */
928
+ enableAutoFlush(events) {
929
+ this.disableAutoFlush();
930
+ for (const event of events) {
931
+ const handler = SIGNAL_EVENTS.has(event) ? () => {
932
+ this.flushSync();
933
+ process.off(event, handler);
934
+ process.kill(process.pid, event);
935
+ } : () => {
936
+ this.flushSync();
937
+ };
938
+ process.on(event, handler);
939
+ this.autoFlushHandlers.set(event, handler);
940
+ }
941
+ return this;
942
+ }
943
+ /**
944
+ * Remove every handler previously registered by `enableAutoFlush`.
945
+ * Safe to call when no handlers are registered.
946
+ */
947
+ disableAutoFlush() {
948
+ for (const [event, handler] of this.autoFlushHandlers) process.off(event, handler);
949
+ this.autoFlushHandlers.clear();
950
+ return this;
951
+ }
952
+ };
953
+ /**
954
+ * The package singleton. Use this for everyday logging — `log.info(...)`,
955
+ * `log.error(...)`, `log.configure(...)`. Custom logger instances can be
956
+ * created by instantiating `Logger` directly.
957
+ *
958
+ * The name is intentionally short: `log` reads naturally at the call site
959
+ * (`log.info("auth", "login", "ok")`) and matches the convention used in
960
+ * pino, bunyan, and most JS logging tutorials.
961
+ *
962
+ * Note that `log` is a `Logger` instance, **not** a function — the bare
963
+ * callable form was removed when the dual `log` / `logger` exports were
964
+ * collapsed into a single name. Use `log.info(...)` (or any other level
965
+ * shortcut) to emit entries.
966
+ */
967
+ const log = new Logger();
968
+
969
+ //#endregion
970
+ //#region ../../@warlock.js/logger/src/utils/capture-unhandled-errors.ts
971
+ /**
972
+ * Route Node's process-level failure events through the logger so they land in
973
+ * every configured channel with full stack context. Registers one listener for
974
+ * `unhandledRejection` and one for `uncaughtException`; call once at startup
975
+ * after channels are configured. Pair with `autoFlushOn: ["beforeExit"]` so the
976
+ * final entry survives the process exit that follows an uncaught exception.
977
+ *
978
+ * @example
979
+ * log.configure({ channels: [new ConsoleLog(), new FileLog()] });
980
+ * captureAnyUnhandledRejection();
981
+ */
982
+ function captureAnyUnhandledRejection() {
983
+ process.on("unhandledRejection", (reason) => {
984
+ log.error("app", "unhandledRejection", reason);
985
+ });
986
+ process.on("uncaughtException", (error) => {
987
+ log.error("app", "uncaughtException", error);
988
+ });
989
+ }
990
+
991
+ //#endregion
992
+ exports.ConsoleLog = ConsoleLog;
993
+ exports.FileLog = FileLog;
994
+ exports.JSONFileLog = JSONFileLog;
995
+ exports.LogChannel = LogChannel;
996
+ exports.Logger = Logger;
997
+ exports.applyRedact = applyRedact;
998
+ exports.captureAnyUnhandledRejection = captureAnyUnhandledRejection;
999
+ exports.clearMessage = clearMessage;
1000
+ exports.log = log;
1001
+ exports.mergeRedact = mergeRedact;
1002
+ exports.safeJsonStringify = safeJsonStringify;
1003
+ //# sourceMappingURL=index.cjs.map