@adviser/cement 0.5.2 → 0.5.3

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 (115) hide show
  1. package/cjs/keyed-ng.test.cjs +6 -5
  2. package/cjs/keyed-ng.test.cjs.map +1 -1
  3. package/cjs/on-func.cjs +15 -1
  4. package/cjs/on-func.cjs.map +1 -1
  5. package/cjs/on-func.d.ts +1 -0
  6. package/cjs/on-func.d.ts.map +1 -1
  7. package/cjs/on-func.test.cjs +34 -0
  8. package/cjs/on-func.test.cjs.map +1 -1
  9. package/cjs/resolve-once.cjs +58 -39
  10. package/cjs/resolve-once.cjs.map +1 -1
  11. package/cjs/resolve-once.d.ts +29 -19
  12. package/cjs/resolve-once.d.ts.map +1 -1
  13. package/cjs/resolve-once.test.cjs +50 -27
  14. package/cjs/resolve-once.test.cjs.map +1 -1
  15. package/cjs/result.cjs +6 -0
  16. package/cjs/result.cjs.map +1 -1
  17. package/cjs/result.d.ts +2 -0
  18. package/cjs/result.d.ts.map +1 -1
  19. package/cjs/timeouted.cjs +13 -18
  20. package/cjs/timeouted.cjs.map +1 -1
  21. package/cjs/timeouted.d.ts +23 -27
  22. package/cjs/timeouted.d.ts.map +1 -1
  23. package/cjs/timeouted.test.cjs +30 -0
  24. package/cjs/timeouted.test.cjs.map +1 -1
  25. package/cjs/utils/to-sorted.d.ts +1 -1
  26. package/cjs/utils/to-sorted.d.ts.map +1 -1
  27. package/cjs/version.cjs +1 -1
  28. package/deno.json +1 -1
  29. package/esm/keyed-ng.test.js +6 -5
  30. package/esm/keyed-ng.test.js.map +1 -1
  31. package/esm/on-func.d.ts +1 -0
  32. package/esm/on-func.d.ts.map +1 -1
  33. package/esm/on-func.js +15 -1
  34. package/esm/on-func.js.map +1 -1
  35. package/esm/on-func.test.js +34 -0
  36. package/esm/on-func.test.js.map +1 -1
  37. package/esm/resolve-once.d.ts +29 -19
  38. package/esm/resolve-once.d.ts.map +1 -1
  39. package/esm/resolve-once.js +58 -39
  40. package/esm/resolve-once.js.map +1 -1
  41. package/esm/resolve-once.test.js +50 -27
  42. package/esm/resolve-once.test.js.map +1 -1
  43. package/esm/result.d.ts +2 -0
  44. package/esm/result.d.ts.map +1 -1
  45. package/esm/result.js +6 -0
  46. package/esm/result.js.map +1 -1
  47. package/esm/timeouted.d.ts +23 -27
  48. package/esm/timeouted.d.ts.map +1 -1
  49. package/esm/timeouted.js +13 -18
  50. package/esm/timeouted.js.map +1 -1
  51. package/esm/timeouted.test.js +31 -1
  52. package/esm/timeouted.test.js.map +1 -1
  53. package/esm/utils/to-sorted.d.ts +1 -1
  54. package/esm/utils/to-sorted.d.ts.map +1 -1
  55. package/esm/version.js +1 -1
  56. package/package.json +2 -2
  57. package/src/on-func.ts +39 -1
  58. package/src/resolve-once.ts +189 -113
  59. package/src/result.ts +7 -0
  60. package/src/timeouted.ts +39 -65
  61. package/src/utils/to-sorted.ts +1 -1
  62. package/ts/cjs/keyed-ng.test.js +6 -5
  63. package/ts/cjs/keyed-ng.test.js.map +1 -1
  64. package/ts/cjs/on-func.d.ts +1 -0
  65. package/ts/cjs/on-func.d.ts.map +1 -1
  66. package/ts/cjs/on-func.js +15 -1
  67. package/ts/cjs/on-func.js.map +1 -1
  68. package/ts/cjs/on-func.test.js +34 -0
  69. package/ts/cjs/on-func.test.js.map +1 -1
  70. package/ts/cjs/resolve-once.d.ts +29 -19
  71. package/ts/cjs/resolve-once.d.ts.map +1 -1
  72. package/ts/cjs/resolve-once.js +58 -39
  73. package/ts/cjs/resolve-once.js.map +1 -1
  74. package/ts/cjs/resolve-once.test.js +50 -27
  75. package/ts/cjs/resolve-once.test.js.map +1 -1
  76. package/ts/cjs/result.d.ts +2 -0
  77. package/ts/cjs/result.d.ts.map +1 -1
  78. package/ts/cjs/result.js +6 -0
  79. package/ts/cjs/result.js.map +1 -1
  80. package/ts/cjs/timeouted.d.ts +23 -27
  81. package/ts/cjs/timeouted.d.ts.map +1 -1
  82. package/ts/cjs/timeouted.js +13 -18
  83. package/ts/cjs/timeouted.js.map +1 -1
  84. package/ts/cjs/timeouted.test.js +30 -0
  85. package/ts/cjs/timeouted.test.js.map +1 -1
  86. package/ts/cjs/utils/to-sorted.d.ts +1 -1
  87. package/ts/cjs/utils/to-sorted.d.ts.map +1 -1
  88. package/ts/cjs/version.js +1 -1
  89. package/ts/esm/keyed-ng.test.js +6 -5
  90. package/ts/esm/keyed-ng.test.js.map +1 -1
  91. package/ts/esm/on-func.d.ts +1 -0
  92. package/ts/esm/on-func.d.ts.map +1 -1
  93. package/ts/esm/on-func.js +15 -1
  94. package/ts/esm/on-func.js.map +1 -1
  95. package/ts/esm/on-func.test.js +34 -0
  96. package/ts/esm/on-func.test.js.map +1 -1
  97. package/ts/esm/resolve-once.d.ts +29 -19
  98. package/ts/esm/resolve-once.d.ts.map +1 -1
  99. package/ts/esm/resolve-once.js +58 -39
  100. package/ts/esm/resolve-once.js.map +1 -1
  101. package/ts/esm/resolve-once.test.js +50 -27
  102. package/ts/esm/resolve-once.test.js.map +1 -1
  103. package/ts/esm/result.d.ts +2 -0
  104. package/ts/esm/result.d.ts.map +1 -1
  105. package/ts/esm/result.js +6 -0
  106. package/ts/esm/result.js.map +1 -1
  107. package/ts/esm/timeouted.d.ts +23 -27
  108. package/ts/esm/timeouted.d.ts.map +1 -1
  109. package/ts/esm/timeouted.js +13 -18
  110. package/ts/esm/timeouted.js.map +1 -1
  111. package/ts/esm/timeouted.test.js +31 -1
  112. package/ts/esm/timeouted.test.js.map +1 -1
  113. package/ts/esm/utils/to-sorted.d.ts +1 -1
  114. package/ts/esm/utils/to-sorted.d.ts.map +1 -1
  115. package/ts/esm/version.js +1 -1
@@ -15,11 +15,13 @@
15
15
  */
16
16
 
17
17
  import { Future } from "./future.js";
18
- import { UnPromisify, isPromise } from "./is-promise.js";
18
+ import { isPromise } from "./is-promise.js";
19
19
  import { UnregFn } from "./lru-map-set.js";
20
20
  import { Result } from "./result.js";
21
21
  import { Option } from "./option.js";
22
22
  import { KeyedIf, KeyedNg, KeyedNgItem, KeyedNgItemWithoutValue, KeyedNgOptions } from "./keyed-ng.js";
23
+ import { runtimeFn } from "./runtime.js";
24
+ import { Writable } from "ts-essentials";
23
25
 
24
26
  /**
25
27
  * Internal item representing a queued function in a ResolveSeq sequence.
@@ -143,33 +145,58 @@ export class ResolveSeq<T, CTX extends NonNullable<object> = object> {
143
145
  type ResolveState = "initial" | "processed" | "waiting" | "processing";
144
146
 
145
147
  /**
146
- * Type helper that unwraps Promise types to their resolved value type.
148
+ * Type helper that awaits Promise types and passes through non-Promise types.
149
+ * This ensures that if a function returns a Promise<T>, the once method also returns Promise<T>,
150
+ * and if the function returns T (non-Promise), once returns T directly.
147
151
  *
148
- * @template R - The type to unwrap
152
+ * Uses the built-in Awaited utility type to properly handle nested Promises and thenable objects.
153
+ *
154
+ * @template R - The type to process
149
155
  *
150
156
  * @example
151
157
  * ```typescript
152
158
  * type A = ResultOnce<Promise<number>>; // Promise<number>
153
159
  * type B = ResultOnce<string>; // string
160
+ * type C = ResultOnce<number>; // number
161
+ * type D = ResultOnce<Promise<Promise<number>>>; // Promise<number>
154
162
  * ```
155
163
  */
156
- export type ResultOnce<R> = R extends Promise<infer T> ? Promise<T> : R;
164
+ export type ResultOnce<R> = R extends Promise<unknown> ? Promise<Awaited<R>> : R;
165
+
166
+ export interface OnceActionArg<R, CTX> {
167
+ readonly ctx: CTX;
168
+ readonly self: ResolveOnceIf<R, CTX>;
169
+ }
157
170
 
171
+ // export type OnceAction<R, CTX, RET> = (arg: OnceActionArg<R, CTX>) => RET extends Promise<R> ? Promise<R> : R;
158
172
  /**
159
173
  * Interface defining the contract for ResolveOnce-like objects.
160
174
  * @template R - The return type
161
175
  * @template CTX - Optional context type
162
176
  */
163
- export interface ResolveOnceIf<R, CTX = void> {
177
+ export interface ResolveOnceIf<R, CTX> {
164
178
  get ready(): boolean;
165
- get value(): UnPromisify<R> | undefined;
179
+ get value(): R | undefined;
166
180
  get error(): Error | undefined;
167
181
  get state(): ResolveState;
168
182
 
169
- once<R>(fn: (c?: CTX) => R): ResultOnce<R>;
170
- reset<R>(fn?: (c?: CTX) => R): ResultOnce<R>;
183
+ setResetAfter(ms?: number): void;
184
+
185
+ once<RET extends R | Promise<R>>(fn: (arg: OnceActionArg<R, CTX>) => RET): ResultOnce<RET>;
186
+ reset<RET extends R | Promise<R>>(fn?: (arg: OnceActionArg<R, CTX>) => RET): ResultOnce<RET>;
187
+
188
+ setProcessed(state: StateInstance): void;
171
189
  }
172
190
 
191
+ export interface SyncOrAsyncIf<T> {
192
+ get value(): T | undefined;
193
+ get error(): Error | undefined;
194
+ get queueLength(): number;
195
+
196
+ resolve<RET extends T | Promise<T>>(fn: () => RET): ResultOnce<RET>;
197
+ }
198
+ export type SyncOrAsync<T> = Option<SyncOrAsyncIf<T>>;
199
+
173
200
  /**
174
201
  * Synchronous version of ResolveOnce for functions that return non-promise values.
175
202
  *
@@ -180,7 +207,7 @@ export interface ResolveOnceIf<R, CTX = void> {
180
207
  * @template CTX - Optional context type
181
208
  * @internal
182
209
  */
183
- export class SyncResolveOnce<T, CTX = void> {
210
+ export class SyncResolveOnce<T, CTX> implements SyncOrAsyncIf<T> {
184
211
  #value?: T;
185
212
  #error?: Error;
186
213
 
@@ -223,10 +250,10 @@ export class SyncResolveOnce<T, CTX = void> {
223
250
  * @returns The result of the function
224
251
  * @throws Error if the function returned a promise (use AsyncResolveOnce instead)
225
252
  */
226
- resolve(fn: (ctx?: CTX) => T): T {
253
+ resolve<RET extends T | Promise<T>>(fn: () => RET): ResultOnce<RET> {
227
254
  if (this.#state.isProcessing()) {
228
255
  try {
229
- this.#value = fn(this.#rOnce._ctx);
256
+ this.#value = fn() as unknown as T;
230
257
  } catch (e) {
231
258
  this.#error = e as Error;
232
259
  } finally {
@@ -240,24 +267,24 @@ export class SyncResolveOnce<T, CTX = void> {
240
267
  if (this.#error) {
241
268
  throw this.#error;
242
269
  }
243
- return this.#value as T;
270
+ return this.#value as ResultOnce<RET>;
244
271
  }
245
272
 
246
- /**
247
- * Resets the cached state, allowing the function to be executed again.
248
- *
249
- * @param fn - Optional function to execute immediately after reset
250
- * @returns The result if fn provided, undefined otherwise
251
- */
252
- reset(fn?: (c?: CTX) => T): T | undefined {
253
- this.#value = undefined;
254
- this.#error = undefined;
255
- if (fn) {
256
- this.#state.setProcessing();
257
- return this.resolve(fn);
258
- }
259
- return undefined as T;
260
- }
273
+ // /**
274
+ // * Resets the cached state, allowing the function to be executed again.
275
+ // *
276
+ // * @param fn - Optional function to execute immediately after reset
277
+ // * @returns The result if fn provided, undefined otherwise
278
+ // */
279
+ // reset(fn?: () => RET): T | undefined {
280
+ // this.#value = undefined;
281
+ // this.#error = undefined;
282
+ // if (fn) {
283
+ // this.#state.setProcessing();
284
+ // return this.resolve(fn);
285
+ // }
286
+ // return undefined as T;
287
+ // }
261
288
  }
262
289
 
263
290
  /**
@@ -267,19 +294,19 @@ export class SyncResolveOnce<T, CTX = void> {
267
294
  */
268
295
  class AsyncResolveItem<T, CTX> {
269
296
  readonly id: number = Math.random();
270
- readonly #toResolve: Promise<UnPromisify<T>>;
271
- #value: Option<UnPromisify<T>> = Option.None();
297
+ readonly #toResolve: Promise<T>;
298
+ #value: Option<T> = Option.None();
272
299
  #error?: Error;
273
300
  readonly #state: StateInstance;
274
- readonly #rOnce: ResolveOnce<T, CTX>;
301
+ readonly #rOnce: ResolveOnceIf<T, CTX>;
275
302
 
276
- constructor(fn: Promise<UnPromisify<T>>, rOnce: ResolveOnce<T, CTX>, state: StateInstance) {
303
+ constructor(fn: Promise<T>, rOnce: ResolveOnceIf<T, CTX>, state: StateInstance) {
277
304
  this.#toResolve = fn;
278
305
  this.#state = state;
279
306
  this.#rOnce = rOnce;
280
307
  }
281
308
 
282
- get value(): UnPromisify<T> | undefined {
309
+ get value(): T | undefined {
283
310
  return this.#value.IsSome() ? this.#value.unwrap() : undefined;
284
311
  }
285
312
 
@@ -287,7 +314,7 @@ class AsyncResolveItem<T, CTX> {
287
314
  return this.#error;
288
315
  }
289
316
 
290
- readonly #queue: Future<UnPromisify<T>>[] = [];
317
+ readonly #queue: Future<T>[] = [];
291
318
 
292
319
  get queuelength(): number {
293
320
  return this.#queue.length;
@@ -300,7 +327,7 @@ class AsyncResolveItem<T, CTX> {
300
327
  return this.#state.isProcessed() && this.#queue.length === 0;
301
328
  }
302
329
 
303
- #resolveFuture(future?: Future<UnPromisify<T>>): void {
330
+ #resolveFuture(future?: Future<T>): void {
304
331
  if (!future) {
305
332
  return;
306
333
  }
@@ -313,7 +340,7 @@ class AsyncResolveItem<T, CTX> {
313
340
  }
314
341
  }
315
342
 
316
- #promiseResult(): Promise<UnPromisify<T>> {
343
+ #promiseResult(): Promise<T> {
317
344
  if (this.#error) {
318
345
  return Promise.reject(this.#error);
319
346
  }
@@ -326,9 +353,9 @@ class AsyncResolveItem<T, CTX> {
326
353
  /**
327
354
  * Resolves the async operation, queuing the request if already in progress.
328
355
  */
329
- resolve(): T {
356
+ resolve<RET extends T | Promise<T>>(_fn: () => RET): ResultOnce<RET> {
330
357
  if (this.#state.isWaiting()) {
331
- const future = new Future<UnPromisify<T>>();
358
+ const future = new Future<T>();
332
359
  this.#queue.push(future);
333
360
  this.#toResolve
334
361
  .then((value) => {
@@ -344,11 +371,11 @@ class AsyncResolveItem<T, CTX> {
344
371
  this.#resolveFuture(this.#queue.shift());
345
372
  }
346
373
  });
347
- return future.asPromise() as T;
374
+ return future.asPromise() as ResultOnce<RET>;
348
375
  }
349
376
 
350
377
  if (this.#state.isProcessed()) {
351
- return this.#promiseResult() as T;
378
+ return this.#promiseResult() as ResultOnce<RET>;
352
379
  }
353
380
  // if (this.#state.isWaiting()) {
354
381
  // const future = new Future<UnPromisify<T>>();
@@ -371,23 +398,23 @@ class AsyncResolveItem<T, CTX> {
371
398
  * @internal
372
399
  */
373
400
 
374
- function isAsyncResolveOnce<T, CTX>(obj: SyncOrAsync<T, CTX>): obj is Option<AsyncResolveOnce<T, CTX>> {
401
+ function isAsyncResolveOnce<T, CTX>(obj: SyncOrAsync<T>): obj is Option<AsyncResolveOnce<T, CTX>> {
375
402
  return obj.IsSome() && obj.Unwrap() instanceof AsyncResolveOnce;
376
403
  }
377
404
 
378
- export class AsyncResolveOnce<T, CTX = void> {
405
+ export class AsyncResolveOnce<T, CTX> implements SyncOrAsyncIf<T> {
379
406
  // #state: ResolveState = "initial";
380
407
  readonly #state: StateInstance;
381
408
 
382
409
  readonly #queue: AsyncResolveItem<T, CTX>[];
383
410
 
384
- readonly #rOnce: ResolveOnce<T, CTX>;
385
- //readonly #ctx?: CTX;
386
- constructor(rOnce: ResolveOnce<T, CTX>, state: StateInstance, prev: SyncOrAsync<T, CTX>) {
411
+ readonly #rOnce: ResolveOnceIf<T, CTX>;
412
+ //readonly #ctx?: RET;
413
+ constructor(rOnce: ResolveOnceIf<T, CTX>, state: StateInstance, prev: SyncOrAsync<T>) {
387
414
  this.#state = state;
388
415
  this.#rOnce = rOnce;
389
416
  if (isAsyncResolveOnce(prev)) {
390
- this.#queue = [...prev.unwrap().#queue];
417
+ this.#queue = [...(prev.unwrap().#queue as AsyncResolveItem<T, CTX>[])];
391
418
  } else {
392
419
  this.#queue = [];
393
420
  }
@@ -411,7 +438,7 @@ export class AsyncResolveOnce<T, CTX = void> {
411
438
  /**
412
439
  * Gets the cached resolved value if available.
413
440
  */
414
- get value(): UnPromisify<T> | undefined {
441
+ get value(): T | undefined {
415
442
  if (this.#state.isInitial()) {
416
443
  return undefined;
417
444
  }
@@ -435,16 +462,16 @@ export class AsyncResolveOnce<T, CTX = void> {
435
462
  * @param fn - The async function to execute
436
463
  * @returns A promise that resolves to the function's result
437
464
  */
438
- resolve(fn: (ctx?: CTX) => T): T {
465
+ resolve<RET extends T | Promise<T>>(fn: () => RET): ResultOnce<RET> {
439
466
  if (this.#state.isProcessing()) {
440
467
  this.#state.setWaiting();
441
- let promiseResult: Promise<UnPromisify<T>>;
468
+ let promiseResult: Promise<T>;
442
469
  try {
443
- const couldBePromise = fn(this.#rOnce._ctx);
470
+ const couldBePromise = fn();
444
471
  if (!isPromise(couldBePromise)) {
445
- promiseResult = Promise.resolve(couldBePromise as UnPromisify<T>);
472
+ promiseResult = Promise.resolve(couldBePromise) as Promise<T>;
446
473
  } else {
447
- promiseResult = couldBePromise as Promise<UnPromisify<T>>;
474
+ promiseResult = couldBePromise as Promise<T>;
448
475
  }
449
476
  } catch (e) {
450
477
  promiseResult = Promise.reject(e as Error);
@@ -459,22 +486,22 @@ export class AsyncResolveOnce<T, CTX = void> {
459
486
  .reverse()
460
487
  .forEach((idx) => this.#queue.splice(idx, 1));
461
488
 
462
- return this.#active().resolve();
489
+ return this.#active().resolve(fn);
463
490
  }
464
491
 
465
- /**
466
- * Resets the cached state, allowing the function to be executed again.
467
- *
468
- * @param fn - Optional function to execute immediately after reset
469
- * @returns The result if fn provided, undefined otherwise
470
- */
471
- reset(fn?: (c?: CTX) => T): T {
472
- this.#state.setProcessing();
473
- if (fn) {
474
- return this.resolve(fn);
475
- }
476
- return undefined as T;
477
- }
492
+ // /**
493
+ // * Resets the cached state, allowing the function to be executed again.
494
+ // *
495
+ // * @param fn - Optional function to execute immediately after reset
496
+ // * @returns The result if fn provided, undefined otherwise
497
+ // */
498
+ // reset(fn?: () => ResultOnce<T>): T {
499
+ // this.#state.setProcessing();
500
+ // if (fn) {
501
+ // return this.resolve(fn);
502
+ // }
503
+ // return undefined as T;
504
+ // }
478
505
  }
479
506
 
480
507
  /**
@@ -549,20 +576,24 @@ class StateInstance {
549
576
  }
550
577
  }
551
578
 
552
- type SyncOrAsync<T, CTX> = Option<SyncResolveOnce<T, CTX> | AsyncResolveOnce<T, CTX>>;
579
+ // type SyncOrAsync<T, CTX> = Option<SyncResolveOnce<T, CTX> | AsyncResolveOnce<T, CTX>>;
553
580
 
554
581
  export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
555
582
  #state = new StateInstance();
556
583
 
557
- #syncOrAsync: SyncOrAsync<T, CTX> = Option.None();
584
+ #syncOrAsync: SyncOrAsync<T> = Option.None();
558
585
 
559
- readonly #opts: ResolveOnceOpts;
586
+ readonly #opts: Writable<ResolveOnceOpts>;
560
587
  resetAfterTimer?: ReturnType<typeof setTimeout>;
561
588
 
562
- readonly _ctx?: CTX;
589
+ readonly _onceArg: OnceActionArg<T, CTX>;
590
+
563
591
  constructor(ctx?: CTX, opts?: ResolveOnceOpts) {
564
- this._ctx = ctx;
565
- this.#opts = opts ?? {};
592
+ this.#opts = { ...(opts ?? {}) };
593
+ this._onceArg = {
594
+ ctx: ctx as CTX,
595
+ self: this,
596
+ };
566
597
  }
567
598
 
568
599
  get state(): ResolveState {
@@ -584,15 +615,47 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
584
615
  this.#state.setProcessed();
585
616
  if (typeof this.#opts.resetAfter === "number" && this.#opts.resetAfter > 0) {
586
617
  this.resetAfterTimer = setTimeout(() => {
587
- this.reset();
618
+ void this.reset();
588
619
  }, this.#opts.resetAfter);
589
- if (!this.#opts.skipUnref) {
590
- const hasUnref = this.resetAfterTimer as unknown as { unref?: () => void };
591
- if (typeof hasUnref === "object" && typeof hasUnref.unref === "function") {
592
- hasUnref.unref();
593
- } else if (typeof globalThis.Deno === "object") {
594
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
595
- globalThis.Deno.unrefTimer(this.resetAfterTimer as any);
620
+ if (!this.#opts.skipUnref && this.resetAfterTimer) {
621
+ // node solution
622
+ const runtime = runtimeFn();
623
+ switch (true) {
624
+ case runtime.isDeno:
625
+ {
626
+ let id = this.resetAfterTimer as unknown as number;
627
+ if (typeof Deno.unrefTimer === "function") {
628
+ if (typeof this.resetAfterTimer === "number") {
629
+ id = this.resetAfterTimer;
630
+ } else {
631
+ try {
632
+ const ret = Reflect.ownKeys(this.resetAfterTimer).find((key) => {
633
+ return key.toString().includes("timerId");
634
+ });
635
+ if (ret) {
636
+ id = this.resetAfterTimer[ret as keyof typeof this.resetAfterTimer] as unknown as number;
637
+ // eslint-disable-next-line no-console
638
+ console.warn("Deno.unrefTimer timerId from struct:", id, "version:", globalThis.Deno?.version);
639
+ }
640
+ } catch (e) {
641
+ // eslint-disable-next-line no-console
642
+ console.warn(
643
+ "Deno.unrefTimer failed to get timerId",
644
+ e,
645
+ "id:",
646
+ this.resetAfterTimer,
647
+ "version:",
648
+ globalThis.Deno?.version,
649
+ );
650
+ }
651
+ }
652
+ Deno.unrefTimer(id);
653
+ }
654
+ }
655
+ break;
656
+ case runtime.isNodeIsh:
657
+ (this.resetAfterTimer as unknown as { unref: () => void }).unref();
658
+ break;
596
659
  }
597
660
  }
598
661
  }
@@ -603,11 +666,11 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
603
666
  return !this.#state.isInitial();
604
667
  }
605
668
 
606
- get value(): UnPromisify<T> | undefined {
669
+ get value(): T | undefined {
607
670
  if (this.#state.isInitial()) {
608
671
  return undefined;
609
672
  }
610
- return this.#syncOrAsync.Unwrap().value as UnPromisify<T>;
673
+ return this.#syncOrAsync.Unwrap().value;
611
674
  }
612
675
 
613
676
  get queueLength(): number {
@@ -644,58 +707,69 @@ export class ResolveOnce<T, CTX = void> implements ResolveOnceIf<T, CTX> {
644
707
  // this.#state = value;
645
708
  // }
646
709
 
647
- once<R>(fn: (c: CTX, prev?: T) => R): ResultOnce<R> {
648
- let resultFn: (ctx: CTX) => R;
710
+ once<RET extends T | Promise<T>>(fn: (arg: OnceActionArg<T, CTX>) => RET): ResultOnce<RET> {
711
+ let resultFn: () => RET;
649
712
  if (this.#state.isInitial()) {
650
713
  const state = this.#state;
651
714
  try {
652
715
  state.setProcessing();
653
- let prev: T | undefined = undefined;
654
- if (this.#syncOrAsync.IsSome()) {
655
- prev = this.#syncOrAsync.Unwrap().value as T;
656
- }
657
- const isSyncOrAsync = fn(this._ctx ?? ({} as CTX), prev);
716
+ // let prev: T | undefined = undefined;
717
+ // if (this.#syncOrAsync.IsSome()) {
718
+ // prev = this.#syncOrAsync.Unwrap().value as T;
719
+ // }
720
+ const isSyncOrAsync = fn(this._onceArg);
658
721
  if (isPromise(isSyncOrAsync)) {
659
722
  this.#syncOrAsync = Option.Some(new AsyncResolveOnce<T, CTX>(this, state, this.#syncOrAsync));
660
723
  } else {
661
724
  this.#syncOrAsync = Option.Some(new SyncResolveOnce<T, CTX>(this, state));
662
725
  }
663
- resultFn = (): R => isSyncOrAsync;
726
+ resultFn = (): RET => isSyncOrAsync;
664
727
  } catch (e) {
665
728
  this.#syncOrAsync = Option.Some(new SyncResolveOnce<T, CTX>(this, state));
666
- resultFn = (): R => {
729
+ resultFn = (): RET => {
667
730
  throw e;
668
731
  };
669
732
  }
670
733
  } else {
671
- resultFn = fn;
734
+ resultFn = (): RET => fn(this._onceArg);
672
735
  }
673
736
  if (!this.#syncOrAsync) {
674
737
  throw new Error(`ResolveOnce.once impossible: state=${this.#state.getResolveState()}`);
675
738
  }
676
- return this.#syncOrAsync.Unwrap().resolve(resultFn as (c?: CTX) => never) as ResultOnce<R>;
739
+ return this.#syncOrAsync.Unwrap().resolve(resultFn);
677
740
  }
678
741
 
679
- reset<R>(fn?: (c: CTX) => R): ResultOnce<R> {
742
+ reset<RET extends T | Promise<T>>(fn?: (arg: OnceActionArg<T, CTX>) => RET): ResultOnce<RET> {
680
743
  if (this.#state.isInitial()) {
681
744
  if (!fn) {
682
- return undefined as ResultOnce<R>;
745
+ return undefined as ResultOnce<RET>;
683
746
  }
684
- return this.once(fn as (c: CTX) => R);
747
+ return this.once(fn);
685
748
  }
686
749
  if (this.#state.isProcessing()) {
687
750
  // eslint-disable-next-line no-console
688
751
  console.warn("ResolveOnce.reset dropped was called while processing");
689
- return undefined as ResultOnce<R>;
752
+ return undefined as ResultOnce<RET>;
690
753
  }
691
- let ret = undefined as ResultOnce<R>;
754
+ let ret = undefined as ResultOnce<RET>;
692
755
  this.#state = new StateInstance();
693
756
  if (fn) {
694
- ret = this.once(fn as (c: CTX) => R);
757
+ ret = this.once(fn);
695
758
  // ret = this.#syncOrAsync.Unwrap().reset(fn as (c?: CTX) => never) as ResultOnce<R>
696
759
  }
697
760
  return ret;
698
761
  }
762
+
763
+ setResetAfter(ms?: number): void {
764
+ if (this.resetAfterTimer) {
765
+ clearTimeout(this.resetAfterTimer);
766
+ }
767
+ if (typeof ms === "number" && ms > 0) {
768
+ this.#opts.resetAfter = ms;
769
+ } else {
770
+ this.#opts.resetAfter = undefined;
771
+ }
772
+ }
699
773
  }
700
774
 
701
775
  // /**
@@ -798,19 +872,21 @@ export interface KeyedResolveOnceItem<K, T, CTX extends NonNullable<object>> {
798
872
  * .once(({ givenKey, ctx }) => fetchUser(givenKey, ctx));
799
873
  * ```
800
874
  */
801
- export class KeyedResolvOnce<T extends WithOptionalReset<PT>, K = string, CTX extends NonNullable<object> = object, PT = T>
802
- implements
803
- Omit<
804
- // KeyedIf<ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>, WithOptionalReset<T>, K>
805
- KeyedIf<
806
- KeyedNgItem<K, ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>, CTX>,
807
- ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>,
808
- K,
809
- CTX
810
- >,
811
- "entries" | "forEach" | "onSet" | "onDelete" | "values" | "setParam"
812
- >
813
- {
875
+ export class KeyedResolvOnce<
876
+ T extends WithOptionalReset<PT>,
877
+ K = string,
878
+ CTX extends NonNullable<object> = object,
879
+ PT = T,
880
+ > implements Omit<
881
+ // KeyedIf<ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>, WithOptionalReset<T>, K>
882
+ KeyedIf<
883
+ KeyedNgItem<K, ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>, CTX>,
884
+ ResolveOnce<T, KeyedNgItemWithoutValue<K, CTX>>,
885
+ K,
886
+ CTX
887
+ >,
888
+ "entries" | "forEach" | "onSet" | "onDelete" | "values" | "setParam"
889
+ > {
814
890
  /** @internal */
815
891
  readonly _keyed: KeyedNg<K, ResolveOnce<WithOptionalReset<T>, KeyedNgItemWithoutValue<K, CTX>>, CTX>;
816
892
 
@@ -991,7 +1067,7 @@ export class KeyedResolvOnce<T extends WithOptionalReset<PT>, K = string, CTX ex
991
1067
  */
992
1068
  unget(key: K): void {
993
1069
  const item = this._keyed.getItem(key);
994
- item.value.reset?.();
1070
+ void item.value.reset?.();
995
1071
  return this._keyed.delete(item.givenKey);
996
1072
  }
997
1073
 
@@ -1003,7 +1079,7 @@ export class KeyedResolvOnce<T extends WithOptionalReset<PT>, K = string, CTX ex
1003
1079
  */
1004
1080
  reset(): void {
1005
1081
  for (const v of this._keyed.values()) {
1006
- v.value.reset?.();
1082
+ void v.value.reset?.();
1007
1083
  }
1008
1084
  }
1009
1085
 
package/src/result.ts CHANGED
@@ -57,6 +57,13 @@ export abstract class Result<T, E = Error> {
57
57
  return false;
58
58
  }
59
59
 
60
+ static AsyncOk<T = void, E = Error>(...args: T[]): Promise<Result<T, E>> {
61
+ return Promise.resolve(Result.Ok<T, E>(...args));
62
+ }
63
+ static AsyncErr<T, E extends Error = Error>(t: E | string | Result<unknown, E>): Promise<Result<T, E>> {
64
+ return Promise.resolve(Result.Err<T, E>(t));
65
+ }
66
+
60
67
  isOk(): boolean {
61
68
  return this.is_ok();
62
69
  }