@actuallab/core 12.3.14 → 12.3.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,340 @@
1
1
  // src/polyfills.ts
2
2
  Symbol.metadata ??= /* @__PURE__ */ Symbol("Symbol.metadata");
3
3
 
4
+ // src/disposable.ts
5
+ var DisposableBag = class {
6
+ _items = [];
7
+ _disposed = false;
8
+ get isDisposed() {
9
+ return this._disposed;
10
+ }
11
+ add(item) {
12
+ if (this._disposed)
13
+ throw new Error("DisposableBag is already disposed.");
14
+ this._items.push(item);
15
+ }
16
+ dispose() {
17
+ if (this._disposed) return;
18
+ this._disposed = true;
19
+ const items = this._items;
20
+ this._items = [];
21
+ for (let i = items.length - 1; i >= 0; i--) {
22
+ const item = items[i];
23
+ if ("dispose" in item) item.dispose();
24
+ }
25
+ }
26
+ async disposeAsync() {
27
+ if (this._disposed) return;
28
+ this._disposed = true;
29
+ const items = this._items;
30
+ this._items = [];
31
+ for (let i = items.length - 1; i >= 0; i--) {
32
+ const item = items[i];
33
+ if ("disposeAsync" in item) await item.disposeAsync();
34
+ else if ("dispose" in item) item.dispose();
35
+ }
36
+ }
37
+ };
38
+
39
+ // src/logging-init.ts
40
+ var GlobalThisKey = "logLevels";
41
+ var StorageKey = "logLevels";
42
+ var DateStorageKey = `${StorageKey}.date`;
43
+ var MaxStorageAge = 864e5 * 3;
44
+ var sessionStorage = typeof globalThis !== "undefined" && "sessionStorage" in globalThis ? globalThis.sessionStorage : null;
45
+ function initLogging() {
46
+ Log.defaultMinLevel = 3 /* Warn */;
47
+ const minLevels = Log.minLevels;
48
+ if (typeof globalThis !== "undefined")
49
+ globalThis[GlobalThisKey] = new LogLevelController(minLevels);
50
+ const wasRestored = restore(minLevels);
51
+ if (wasRestored)
52
+ console.log("Logging: logLevels are restored");
53
+ else {
54
+ console.log("Logging: logLevels are reset");
55
+ reset(minLevels);
56
+ }
57
+ }
58
+ var LogLevelController = class {
59
+ constructor(minLevels) {
60
+ this.minLevels = minLevels;
61
+ }
62
+ /** List the current set of overrides. */
63
+ list() {
64
+ return Object.fromEntries(this.minLevels);
65
+ }
66
+ /** Print every known scope's effective level to the console as a table.
67
+ * Shows: scope, effective level, the source ('override' / 'default-key' /
68
+ * 'package-default' / 'baseline'), and the package default for reference.
69
+ * Use this from the dev console to discover what to pass to override(). */
70
+ dump() {
71
+ const baseline = Log.defaultMinLevel;
72
+ const globalOverride = this.minLevels.get("default");
73
+ const allScopes = /* @__PURE__ */ new Set([
74
+ ...Log.knownScopes,
75
+ ...Log.scopeDefaults.keys(),
76
+ ...this.minLevels.keys()
77
+ ]);
78
+ allScopes.delete("default");
79
+ const rows = {};
80
+ const sorted = [...allScopes].sort();
81
+ for (const scope of sorted) {
82
+ const override = this.minLevels.get(scope);
83
+ const pkgDefault = Log.scopeDefaults.get(scope);
84
+ let level;
85
+ let source;
86
+ if (override !== void 0) {
87
+ level = override;
88
+ source = "override";
89
+ } else if (globalOverride !== void 0) {
90
+ level = globalOverride;
91
+ source = "minLevels.get('default')";
92
+ } else if (pkgDefault !== void 0) {
93
+ level = pkgDefault;
94
+ source = "package-default";
95
+ } else {
96
+ level = baseline;
97
+ source = "baseline";
98
+ }
99
+ rows[scope] = {
100
+ level: LogLevel[level],
101
+ source,
102
+ packageDefault: pkgDefault === void 0 ? "-" : LogLevel[pkgDefault]
103
+ };
104
+ }
105
+ console.table(rows);
106
+ console.log(
107
+ `Baseline: ${LogLevel[baseline]}` + (globalOverride === void 0 ? "" : `, default override: ${LogLevel[globalOverride]}`)
108
+ );
109
+ }
110
+ /** Override the level for a single scope. Persisted to sessionStorage. */
111
+ override(scope, newLevel) {
112
+ this.minLevels.set(scope, newLevel);
113
+ persist(this.minLevels);
114
+ }
115
+ /** Override the level for every scope whose name starts with scopePrefix
116
+ * (e.g. 'rpc.' to enable verbose RPC logging). Persisted. */
117
+ overrideAll(scopePrefix, newLevel) {
118
+ const matched = /* @__PURE__ */ new Set();
119
+ for (const [scope] of this.minLevels)
120
+ if (scope.startsWith(scopePrefix)) matched.add(scope);
121
+ for (const [scope] of Log.scopeDefaults)
122
+ if (scope.startsWith(scopePrefix)) matched.add(scope);
123
+ for (const scope of matched)
124
+ this.minLevels.set(scope, newLevel);
125
+ persist(this.minLevels);
126
+ }
127
+ /** Reset all overrides; package defaults take effect again. Persisted. */
128
+ reset() {
129
+ reset(this.minLevels);
130
+ persist(this.minLevels);
131
+ }
132
+ /** Clear all overrides (no global default unless `defaultLevel` is given). */
133
+ clear(defaultLevel) {
134
+ this.minLevels.clear();
135
+ if (defaultLevel !== void 0)
136
+ this.minLevels.set("default", defaultLevel);
137
+ persist(this.minLevels);
138
+ }
139
+ };
140
+ function restore(minLevels) {
141
+ if (!sessionStorage)
142
+ return false;
143
+ const dateJson = sessionStorage.getItem(DateStorageKey);
144
+ if (!dateJson)
145
+ return false;
146
+ if (Date.now() - JSON.parse(dateJson) > MaxStorageAge)
147
+ return false;
148
+ const readJson = sessionStorage.getItem(StorageKey);
149
+ if (!readJson)
150
+ return false;
151
+ const readMinLevels = new Map(JSON.parse(readJson));
152
+ if (typeof readMinLevels.size !== "number")
153
+ return false;
154
+ minLevels.clear();
155
+ readMinLevels.forEach((value, key) => minLevels.set(key, value));
156
+ return true;
157
+ }
158
+ function persist(minLevels) {
159
+ if (!sessionStorage)
160
+ return false;
161
+ sessionStorage.setItem(DateStorageKey, JSON.stringify(Date.now()));
162
+ sessionStorage.setItem(StorageKey, JSON.stringify(Array.from(minLevels.entries())));
163
+ return true;
164
+ }
165
+ function reset(minLevels) {
166
+ minLevels.clear();
167
+ persist(minLevels);
168
+ }
169
+
170
+ // src/logging.ts
171
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
172
+ LogLevel2[LogLevel2["Debug"] = 1] = "Debug";
173
+ LogLevel2[LogLevel2["Info"] = 2] = "Info";
174
+ LogLevel2[LogLevel2["Warn"] = 3] = "Warn";
175
+ LogLevel2[LogLevel2["Error"] = 4] = "Error";
176
+ LogLevel2[LogLevel2["None"] = 1e3] = "None";
177
+ return LogLevel2;
178
+ })(LogLevel || {});
179
+ var LogRefSet = class {
180
+ constructor(capacity) {
181
+ this.capacity = capacity;
182
+ }
183
+ items = [];
184
+ idSeed = 0;
185
+ ref(data) {
186
+ const itemIndex = this.items.findIndex((el) => el.ref.target === data);
187
+ if (itemIndex >= 0) {
188
+ const existing = this.items[itemIndex];
189
+ existing.touchedAt = Date.now();
190
+ return existing.ref;
191
+ }
192
+ const id = data.__logRefId ?? this.idSeed++;
193
+ const newRef = { target: data, id };
194
+ data.__logRefId = id;
195
+ if (this.items.length >= this.capacity)
196
+ this.removeOldest();
197
+ this.items.push({ ref: newRef, touchedAt: Date.now() });
198
+ return newRef;
199
+ }
200
+ removeOldest() {
201
+ let indexToEvict = 0;
202
+ let itemToEvict = this.items[0];
203
+ for (let i = 1; i < this.items.length; i++) {
204
+ const item = this.items[i];
205
+ if (item.touchedAt < itemToEvict.touchedAt) {
206
+ itemToEvict = item;
207
+ indexToEvict = i;
208
+ }
209
+ }
210
+ this.items.splice(indexToEvict, 1);
211
+ const ref = itemToEvict.ref;
212
+ ref.target = ref.target?.toString();
213
+ }
214
+ };
215
+ var Log = class _Log {
216
+ constructor(scope, level) {
217
+ this.scope = scope;
218
+ this.level = level;
219
+ const prefix = `[${scope}]`;
220
+ switch (level) {
221
+ case 1 /* Debug */:
222
+ this.log = (...data) => console.debug(prefix, ...data);
223
+ break;
224
+ case 2 /* Info */:
225
+ this.log = (...data) => console.log(prefix, ...data);
226
+ break;
227
+ case 3 /* Warn */:
228
+ this.log = (...data) => console.warn(prefix, ...data);
229
+ break;
230
+ case 4 /* Error */:
231
+ this.log = (...data) => console.error(prefix, ...data);
232
+ break;
233
+ case 1e3 /* None */:
234
+ throw new Error("LogLevel.None cannot be used here");
235
+ }
236
+ this.trace = (...data) => console.trace(prefix, ...data);
237
+ }
238
+ static isInitialized = false;
239
+ static logRefs = new LogRefSet(10);
240
+ /** User-set overrides (persisted to sessionStorage). Empty by default. */
241
+ static minLevels = /* @__PURE__ */ new Map();
242
+ /** Per-scope defaults registered by packages via createLogProvider(). */
243
+ static scopeDefaults = /* @__PURE__ */ new Map();
244
+ /** Every scope ever requested via Log.get(). Used by logLevels.dump()
245
+ * so devs can discover what's available to override at runtime. */
246
+ static knownScopes = /* @__PURE__ */ new Set();
247
+ /** Global baseline for any scope without a default or override. */
248
+ static defaultMinLevel = 3 /* Warn */;
249
+ static loggerFactory = (scope, level) => new _Log(scope, level);
250
+ log;
251
+ trace;
252
+ static get(scope) {
253
+ if (!this.isInitialized) {
254
+ this.isInitialized = true;
255
+ initLogging();
256
+ }
257
+ this.knownScopes.add(scope);
258
+ const minLevels = this.minLevels;
259
+ const minLevel = minLevels.get(scope) ?? minLevels.get("default") ?? this.scopeDefaults.get(scope) ?? this.defaultMinLevel;
260
+ const getLogger = (level) => level >= minLevel ? this.loggerFactory(scope, level) : null;
261
+ return {
262
+ logScope: scope,
263
+ debugLog: getLogger(1 /* Debug */),
264
+ infoLog: getLogger(2 /* Info */),
265
+ warnLog: getLogger(3 /* Warn */),
266
+ errorLog: getLogger(4 /* Error */)
267
+ };
268
+ }
269
+ static ref(data) {
270
+ if (!data)
271
+ return data;
272
+ return this.logRefs.ref(data);
273
+ }
274
+ assert(predicate, ...data) {
275
+ if (!predicate)
276
+ this.log(...data);
277
+ }
278
+ };
279
+ function createLogProvider(prefix, defaults) {
280
+ for (const [scope, level] of Object.entries(defaults)) {
281
+ const fullName = prefix + scope;
282
+ Log.scopeDefaults.set(fullName, level);
283
+ Log.knownScopes.add(fullName);
284
+ }
285
+ return (scope) => Log.get(prefix + scope);
286
+ }
287
+
288
+ // src/result.ts
289
+ var Result = class _Result {
290
+ hasValue;
291
+ hasError;
292
+ _value;
293
+ _error;
294
+ constructor(value, error) {
295
+ this.hasValue = error === void 0;
296
+ this.hasError = !this.hasValue;
297
+ this._value = value;
298
+ this._error = error;
299
+ }
300
+ get value() {
301
+ if (this.hasError) throw this._error;
302
+ return this._value;
303
+ }
304
+ get error() {
305
+ return this._error;
306
+ }
307
+ get valueOrUndefined() {
308
+ return this.hasValue ? this._value : void 0;
309
+ }
310
+ static ok(value) {
311
+ return new _Result(value);
312
+ }
313
+ static error(error) {
314
+ return new _Result(void 0, error);
315
+ }
316
+ };
317
+ function result(value, error) {
318
+ return new Result(value, error);
319
+ }
320
+ function errorResult(error) {
321
+ return Result.error(error);
322
+ }
323
+ function resultFrom(fn) {
324
+ try {
325
+ return result(fn());
326
+ } catch (e) {
327
+ return errorResult(e);
328
+ }
329
+ }
330
+ async function resultFromAsync(fn) {
331
+ try {
332
+ return result(await fn());
333
+ } catch (e) {
334
+ return errorResult(e);
335
+ }
336
+ }
337
+
4
338
  // src/async-context.ts
5
339
  var AsyncContextKey = class {
6
340
  id;
@@ -108,41 +442,6 @@ var AsyncLock = class {
108
442
  }
109
443
  };
110
444
 
111
- // src/disposable.ts
112
- var DisposableBag = class {
113
- _items = [];
114
- _disposed = false;
115
- get isDisposed() {
116
- return this._disposed;
117
- }
118
- add(item) {
119
- if (this._disposed)
120
- throw new Error("DisposableBag is already disposed.");
121
- this._items.push(item);
122
- }
123
- dispose() {
124
- if (this._disposed) return;
125
- this._disposed = true;
126
- const items = this._items;
127
- this._items = [];
128
- for (let i = items.length - 1; i >= 0; i--) {
129
- const item = items[i];
130
- if ("dispose" in item) item.dispose();
131
- }
132
- }
133
- async disposeAsync() {
134
- if (this._disposed) return;
135
- this._disposed = true;
136
- const items = this._items;
137
- this._items = [];
138
- for (let i = items.length - 1; i >= 0; i--) {
139
- const item = items[i];
140
- if ("disposeAsync" in item) await item.disposeAsync();
141
- else if ("dispose" in item) item.dispose();
142
- }
143
- }
144
- };
145
-
146
445
  // src/promise-source.ts
147
446
  var PromiseSource = class {
148
447
  promise;
@@ -202,55 +501,97 @@ var EventHandlerSet = class {
202
501
  }
203
502
  };
204
503
 
205
- // src/result.ts
206
- var Result = class _Result {
207
- hasValue;
208
- hasError;
209
- _value;
210
- _error;
211
- constructor(value, error) {
212
- this.hasValue = error === void 0;
213
- this.hasError = !this.hasValue;
214
- this._value = value;
215
- this._error = error;
216
- }
217
- get value() {
218
- if (this.hasError) throw this._error;
219
- return this._value;
220
- }
221
- get error() {
222
- return this._error;
223
- }
224
- get valueOrUndefined() {
225
- return this.hasValue ? this._value : void 0;
226
- }
227
- static ok(value) {
228
- return new _Result(value);
504
+ // src/ring-buffer.ts
505
+ var RingBuffer = class {
506
+ _buffer;
507
+ _start = 0;
508
+ _end = 0;
509
+ _count = 0;
510
+ capacity;
511
+ get count() {
512
+ return this._count;
513
+ }
514
+ get isEmpty() {
515
+ return this._count === 0;
516
+ }
517
+ get isFull() {
518
+ return this._count === this.capacity;
519
+ }
520
+ get remainingCapacity() {
521
+ return this.capacity - this._count;
522
+ }
523
+ get hasRemainingCapacity() {
524
+ return this._count < this.capacity;
525
+ }
526
+ constructor(capacity) {
527
+ if (capacity < 1)
528
+ throw new RangeError(`RingBuffer capacity must be >= 1 (was ${capacity}).`);
529
+ this.capacity = capacity;
530
+ this._buffer = new Array(capacity);
531
+ }
532
+ /** Read the item at `index` (0-indexed, from head). */
533
+ get(index) {
534
+ if (index < 0 || index >= this._count)
535
+ throw new RangeError(`Index ${index} out of range [0, ${this._count}).`);
536
+ return this._buffer[(this._start + index) % this.capacity];
537
+ }
538
+ /** Add an item at the tail. Throws if the buffer is full. */
539
+ pushTail(item) {
540
+ if (this._count >= this.capacity)
541
+ throw new Error("RingBuffer is full.");
542
+ this._buffer[this._end] = item;
543
+ this._end = (this._end + 1) % this.capacity;
544
+ this._count++;
545
+ }
546
+ /** Add an item at the tail, evicting the head item if the buffer is full. */
547
+ pushTailAndMoveHeadIfFull(item) {
548
+ if (this._count >= this.capacity) {
549
+ this._buffer[this._start] = void 0;
550
+ this._start = (this._start + 1) % this.capacity;
551
+ this._count--;
552
+ }
553
+ this.pushTail(item);
554
+ }
555
+ /** Remove the head item. Throws if the buffer is empty. */
556
+ pullHead() {
557
+ if (this._count === 0)
558
+ throw new Error("RingBuffer is empty.");
559
+ const head = this._buffer[this._start];
560
+ this._buffer[this._start] = void 0;
561
+ this._start = (this._start + 1) % this.capacity;
562
+ this._count--;
563
+ return head;
564
+ }
565
+ /**
566
+ * Advance the head by `skipCount` slots, releasing references to skipped
567
+ * items so they can be garbage-collected.
568
+ */
569
+ moveHead(skipCount) {
570
+ if (skipCount === 0) return;
571
+ if (skipCount < 0 || skipCount > this._count)
572
+ throw new RangeError(`skipCount ${skipCount} out of range [0, ${this._count}].`);
573
+ for (let k = 0; k < skipCount; k++) {
574
+ this._buffer[(this._start + k) % this.capacity] = void 0;
575
+ }
576
+ this._start = (this._start + skipCount) % this.capacity;
577
+ this._count -= skipCount;
229
578
  }
230
- static error(error) {
231
- return new _Result(void 0, error);
579
+ /** Remove all items. */
580
+ clear() {
581
+ for (let i = 0; i < this.capacity; i++) this._buffer[i] = void 0;
582
+ this._start = 0;
583
+ this._end = 0;
584
+ this._count = 0;
585
+ }
586
+ /** Copy the buffer's contents to a new array, head-first. */
587
+ toArray() {
588
+ const out = new Array(this._count);
589
+ for (let i = 0; i < this._count; i++) {
590
+ out[i] = this._buffer[(this._start + i) % this.capacity];
591
+ }
592
+ return out;
232
593
  }
233
594
  };
234
- function result(value, error) {
235
- return new Result(value, error);
236
- }
237
- function errorResult(error) {
238
- return Result.error(error);
239
- }
240
- function resultFrom(fn) {
241
- try {
242
- return result(fn());
243
- } catch (e) {
244
- return errorResult(e);
245
- }
246
- }
247
- async function resultFromAsync(fn) {
248
- try {
249
- return result(await fn());
250
- } catch (e) {
251
- return errorResult(e);
252
- }
253
- }
254
595
 
255
596
  // src/retry-delay-seq.ts
256
597
  var DefaultSpread = 0.1;
@@ -356,14 +697,20 @@ export {
356
697
  AsyncLock,
357
698
  DisposableBag,
358
699
  EventHandlerSet,
700
+ Log,
701
+ LogLevel,
702
+ LogLevelController,
359
703
  PromiseSource,
360
704
  Result,
361
705
  RetryDelayLimitExceeded,
362
706
  RetryDelayNone,
363
707
  RetryDelaySeq,
364
708
  RetryDelayer,
709
+ RingBuffer,
365
710
  abortSignalKey,
711
+ createLogProvider,
366
712
  errorResult,
713
+ initLogging,
367
714
  resolvedVoidPromise,
368
715
  result,
369
716
  resultFrom,