@adviser/cement 0.4.58 → 0.4.60

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 (131) hide show
  1. package/cjs/base-sys-abstraction.d.ts +1 -1
  2. package/cjs/base-sys-abstraction.d.ts.map +1 -1
  3. package/cjs/future.cjs +2 -0
  4. package/cjs/future.cjs.map +1 -1
  5. package/cjs/future.d.ts +1 -0
  6. package/cjs/future.d.ts.map +1 -1
  7. package/cjs/future.test.cjs +5 -0
  8. package/cjs/future.test.cjs.map +1 -1
  9. package/cjs/on-func.test.cjs +1 -1
  10. package/cjs/on-func.test.cjs.map +1 -1
  11. package/cjs/poller.cjs +107 -18
  12. package/cjs/poller.cjs.map +1 -1
  13. package/cjs/poller.d.ts +27 -5
  14. package/cjs/poller.d.ts.map +1 -1
  15. package/cjs/poller.test.cjs +46 -2
  16. package/cjs/poller.test.cjs.map +1 -1
  17. package/cjs/timeouted.cjs +119 -0
  18. package/cjs/timeouted.cjs.map +1 -0
  19. package/cjs/timeouted.d.ts +45 -0
  20. package/cjs/timeouted.d.ts.map +1 -0
  21. package/cjs/timeouted.test.cjs +581 -0
  22. package/cjs/timeouted.test.cjs.map +1 -0
  23. package/cjs/timeouted.test.d.ts +2 -0
  24. package/cjs/timeouted.test.d.ts.map +1 -0
  25. package/cjs/utils/promise-sleep.cjs +27 -26
  26. package/cjs/utils/promise-sleep.cjs.map +1 -1
  27. package/cjs/utils/promise-sleep.d.ts +28 -2
  28. package/cjs/utils/promise-sleep.d.ts.map +1 -1
  29. package/cjs/utils/promise-sleep.test.cjs +13 -13
  30. package/cjs/utils/promise-sleep.test.cjs.map +1 -1
  31. package/cjs/version.cjs +1 -1
  32. package/deno.json +1 -1
  33. package/esm/base-sys-abstraction.d.ts +1 -1
  34. package/esm/base-sys-abstraction.d.ts.map +1 -1
  35. package/esm/future.d.ts +1 -0
  36. package/esm/future.d.ts.map +1 -1
  37. package/esm/future.js +2 -0
  38. package/esm/future.js.map +1 -1
  39. package/esm/future.test.js +5 -0
  40. package/esm/future.test.js.map +1 -1
  41. package/esm/on-func.test.js +1 -1
  42. package/esm/on-func.test.js.map +1 -1
  43. package/esm/poller.d.ts +27 -5
  44. package/esm/poller.d.ts.map +1 -1
  45. package/esm/poller.js +107 -18
  46. package/esm/poller.js.map +1 -1
  47. package/esm/poller.test.js +46 -2
  48. package/esm/poller.test.js.map +1 -1
  49. package/esm/timeouted.d.ts +45 -0
  50. package/esm/timeouted.d.ts.map +1 -0
  51. package/esm/timeouted.js +110 -0
  52. package/esm/timeouted.js.map +1 -0
  53. package/esm/timeouted.test.d.ts +2 -0
  54. package/esm/timeouted.test.d.ts.map +1 -0
  55. package/esm/timeouted.test.js +579 -0
  56. package/esm/timeouted.test.js.map +1 -0
  57. package/esm/utils/promise-sleep.d.ts +28 -2
  58. package/esm/utils/promise-sleep.d.ts.map +1 -1
  59. package/esm/utils/promise-sleep.js +27 -26
  60. package/esm/utils/promise-sleep.js.map +1 -1
  61. package/esm/utils/promise-sleep.test.js +13 -13
  62. package/esm/utils/promise-sleep.test.js.map +1 -1
  63. package/esm/version.js +1 -1
  64. package/package.json +8 -8
  65. package/src/base-sys-abstraction.ts +1 -1
  66. package/src/future.ts +5 -0
  67. package/src/poller.ts +159 -23
  68. package/src/timeouted.ts +186 -0
  69. package/src/utils/promise-sleep.ts +61 -31
  70. package/ts/cjs/base-sys-abstraction.d.ts +1 -1
  71. package/ts/cjs/base-sys-abstraction.d.ts.map +1 -1
  72. package/ts/cjs/future.d.ts +1 -0
  73. package/ts/cjs/future.d.ts.map +1 -1
  74. package/ts/cjs/future.js +2 -0
  75. package/ts/cjs/future.js.map +1 -1
  76. package/ts/cjs/future.test.js +5 -0
  77. package/ts/cjs/future.test.js.map +1 -1
  78. package/ts/cjs/on-func.test.js +1 -1
  79. package/ts/cjs/on-func.test.js.map +1 -1
  80. package/ts/cjs/poller.d.ts +27 -5
  81. package/ts/cjs/poller.d.ts.map +1 -1
  82. package/ts/cjs/poller.js +107 -18
  83. package/ts/cjs/poller.js.map +1 -1
  84. package/ts/cjs/poller.test.js +46 -2
  85. package/ts/cjs/poller.test.js.map +1 -1
  86. package/ts/cjs/timeouted.d.ts +45 -0
  87. package/ts/cjs/timeouted.d.ts.map +1 -0
  88. package/ts/cjs/timeouted.js +119 -0
  89. package/ts/cjs/timeouted.js.map +1 -0
  90. package/ts/cjs/timeouted.test.d.ts +2 -0
  91. package/ts/cjs/timeouted.test.d.ts.map +1 -0
  92. package/ts/cjs/timeouted.test.js +581 -0
  93. package/ts/cjs/timeouted.test.js.map +1 -0
  94. package/ts/cjs/utils/promise-sleep.d.ts +28 -2
  95. package/ts/cjs/utils/promise-sleep.d.ts.map +1 -1
  96. package/ts/cjs/utils/promise-sleep.js +27 -26
  97. package/ts/cjs/utils/promise-sleep.js.map +1 -1
  98. package/ts/cjs/utils/promise-sleep.test.js +13 -13
  99. package/ts/cjs/utils/promise-sleep.test.js.map +1 -1
  100. package/ts/cjs/version.js +1 -1
  101. package/ts/esm/base-sys-abstraction.d.ts +1 -1
  102. package/ts/esm/base-sys-abstraction.d.ts.map +1 -1
  103. package/ts/esm/future.d.ts +1 -0
  104. package/ts/esm/future.d.ts.map +1 -1
  105. package/ts/esm/future.js +2 -0
  106. package/ts/esm/future.js.map +1 -1
  107. package/ts/esm/future.test.js +5 -0
  108. package/ts/esm/future.test.js.map +1 -1
  109. package/ts/esm/on-func.test.js +1 -1
  110. package/ts/esm/on-func.test.js.map +1 -1
  111. package/ts/esm/poller.d.ts +27 -5
  112. package/ts/esm/poller.d.ts.map +1 -1
  113. package/ts/esm/poller.js +107 -18
  114. package/ts/esm/poller.js.map +1 -1
  115. package/ts/esm/poller.test.js +46 -2
  116. package/ts/esm/poller.test.js.map +1 -1
  117. package/ts/esm/timeouted.d.ts +45 -0
  118. package/ts/esm/timeouted.d.ts.map +1 -0
  119. package/ts/esm/timeouted.js +110 -0
  120. package/ts/esm/timeouted.js.map +1 -0
  121. package/ts/esm/timeouted.test.d.ts +2 -0
  122. package/ts/esm/timeouted.test.d.ts.map +1 -0
  123. package/ts/esm/timeouted.test.js +579 -0
  124. package/ts/esm/timeouted.test.js.map +1 -0
  125. package/ts/esm/utils/promise-sleep.d.ts +28 -2
  126. package/ts/esm/utils/promise-sleep.d.ts.map +1 -1
  127. package/ts/esm/utils/promise-sleep.js +27 -26
  128. package/ts/esm/utils/promise-sleep.js.map +1 -1
  129. package/ts/esm/utils/promise-sleep.test.js +13 -13
  130. package/ts/esm/utils/promise-sleep.test.js.map +1 -1
  131. package/ts/esm/version.js +1 -1
@@ -1,3 +1,29 @@
1
- import { Result } from "../result.js";
2
- export declare function sleep(ms: number, signal?: AbortSignal): Promise<Result<void>>;
1
+ export interface SleepBase {
2
+ readonly state: "sleeped" | "error" | "aborted";
3
+ readonly isOk: boolean;
4
+ readonly isErr: boolean;
5
+ readonly isAborted: boolean;
6
+ }
7
+ export interface SleepOk extends SleepBase {
8
+ readonly state: "sleeped";
9
+ readonly isOk: true;
10
+ readonly isErr: false;
11
+ readonly isAborted: false;
12
+ }
13
+ export interface SleepErr extends SleepBase {
14
+ readonly state: "error";
15
+ readonly error: Error;
16
+ readonly isOk: false;
17
+ readonly isErr: true;
18
+ readonly isAborted: false;
19
+ }
20
+ export interface SleepAbort extends SleepBase {
21
+ readonly state: "aborted";
22
+ readonly reason: Error;
23
+ readonly isOk: false;
24
+ readonly isErr: false;
25
+ readonly isAborted: true;
26
+ }
27
+ export type SleepResult = SleepOk | SleepErr | SleepAbort;
28
+ export declare function sleep(ms: number, signal?: AbortSignal): Promise<SleepResult>;
3
29
  //# sourceMappingURL=promise-sleep.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"promise-sleep.d.ts","sourceRoot":"","sources":["../../../../src/utils/promise-sleep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAUtC,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAgC7E"}
1
+ {"version":3,"file":"promise-sleep.d.ts","sourceRoot":"","sources":["../../../../src/utils/promise-sleep.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;CAC3B;AAED,MAAM,WAAW,QAAS,SAAQ,SAAS;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;CAC3B;AAED,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAU1D,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CA8BlF"}
@@ -1,29 +1,30 @@
1
- import { Result } from "../result.js";
2
- export function sleep(ms, signal) {
3
- return new Promise((resolve) => {
4
- if (ms <= 0) {
5
- resolve(Result.Ok());
6
- return;
7
- }
8
- if (signal?.aborted) {
9
- const err = new Error("sleep aborted");
10
- resolve(Result.Err(err));
11
- return;
12
- }
13
- function cleanup() {
14
- clearTimeout(id);
15
- signal?.removeEventListener("abort", onAbort);
16
- }
17
- const id = setTimeout(() => {
18
- cleanup();
19
- resolve(Result.Ok());
20
- }, ms);
21
- const onAbort = () => {
22
- cleanup();
23
- const err = new Error("sleep aborted");
24
- resolve(Result.Err(err));
25
- };
26
- signal?.addEventListener("abort", onAbort, { once: true });
1
+ import { Future } from "../future.js";
2
+ export async function sleep(ms, signal) {
3
+ if (ms < 0) {
4
+ return { state: "sleeped", isOk: true, isErr: false, isAborted: false };
5
+ }
6
+ if (signal?.aborted) {
7
+ const err = new Error("sleep aborted");
8
+ return { state: "aborted", reason: err, isOk: false, isErr: false, isAborted: true };
9
+ }
10
+ const sleepFuture = new Future();
11
+ const id = setTimeout(() => {
12
+ sleepFuture.resolve({ state: "sleeped", isOk: true, isErr: false, isAborted: false });
13
+ }, ms);
14
+ const abortFuture = new Future();
15
+ function onAbort() {
16
+ abortFuture.resolve({
17
+ state: "aborted",
18
+ reason: new Error("sleep aborted"),
19
+ isOk: false,
20
+ isErr: false,
21
+ isAborted: true,
22
+ });
23
+ }
24
+ signal?.addEventListener("abort", onAbort, { once: true });
25
+ return Promise.race([abortFuture.asPromise(), sleepFuture.asPromise()]).finally(() => {
26
+ clearTimeout(id);
27
+ signal?.removeEventListener("abort", onAbort);
27
28
  });
28
29
  }
29
30
  //# sourceMappingURL=promise-sleep.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"promise-sleep.js","sourceRoot":"","sources":["../../../../src/utils/promise-sleep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAUtC,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB,EAAyB;IAC7E,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,EAAE,CAAC;QAC5C,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACZ,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;YAEvC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,OAAO;QACT,CAAC;QAED,SAAS,OAAO,GAAS;YACvB,YAAY,CAAC,EAAE,CAAC,CAAC;YACjB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAAA,CAC/C;QAED,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QAAA,CACtB,EAAE,EAAE,CAAC,CAAC;QAEP,MAAM,OAAO,GAAG,GAAS,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;YACV,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;YAEvC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAAA,CAC1B,CAAC;QAEF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAAA,CAC5D,CAAC,CAAC;AAAA,CACJ"}
1
+ {"version":3,"file":"promise-sleep.js","sourceRoot":"","sources":["../../../../src/utils/promise-sleep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AA0CtC,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB,EAAwB;IAClF,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC1E,CAAC;IACD,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QAEvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACvF,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,MAAM,EAAW,CAAC;IAC1C,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;QAE1B,WAAW,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAAA,CACvF,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,WAAW,GAAG,IAAI,MAAM,EAAc,CAAC;IAC7C,SAAS,OAAO,GAAS;QACvB,WAAW,CAAC,OAAO,CAAC;YAClB,KAAK,EAAE,SAAS;YAChB,MAAM,EAAE,IAAI,KAAK,CAAC,eAAe,CAAC;YAClC,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,KAAK;YACZ,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;IAAA,CACJ;IACD,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACpF,YAAY,CAAC,EAAE,CAAC,CAAC;QACjB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAAA,CAC/C,CAAC,CAAC;AAAA,CACJ"}
@@ -5,58 +5,58 @@ it("sleeps for the specified duration", async () => {
5
5
  const duration = performance.now() - start;
6
6
  expect(duration).toBeGreaterThanOrEqual(95);
7
7
  expect(duration).toBeLessThan(150);
8
- expect(result.isOk()).toBe(true);
9
- expect(result.unwrap()).toBeUndefined();
8
+ expect(result.isOk).toBe(true);
10
9
  });
11
10
  it("returns immediately for zero milliseconds", async () => {
12
11
  const start = performance.now();
13
12
  const result = await sleep(0);
14
13
  const duration = performance.now() - start;
15
14
  expect(duration).toBeLessThan(10);
16
- expect(result.isOk()).toBe(true);
15
+ expect(result.isOk).toBe(true);
17
16
  });
18
17
  it("returns immediately for negative milliseconds", async () => {
19
18
  const start = performance.now();
20
19
  const result = await sleep(-100);
21
20
  const duration = performance.now() - start;
22
21
  expect(duration).toBeLessThan(10);
23
- expect(result.isOk()).toBe(true);
22
+ expect(result.isOk).toBe(true);
24
23
  });
25
24
  it("returns error when aborted before sleep starts", async () => {
26
25
  const controller = new AbortController();
27
26
  controller.abort();
28
- const result = await sleep(100, controller.signal);
29
- expect(result.isOk()).toBe(false);
30
- expect(result.Err().message).toBe("sleep aborted");
27
+ const result = (await sleep(100, controller.signal));
28
+ expect(result.isOk).toBe(false);
29
+ expect(result.isAborted).toBe(true);
30
+ expect(result.reason.message).toBe("sleep aborted");
31
31
  });
32
32
  it("returns error when aborted during sleep", async () => {
33
33
  const controller = new AbortController();
34
34
  const start = performance.now();
35
35
  const sleepPromise = sleep(200, controller.signal);
36
36
  setTimeout(() => controller.abort(), 50);
37
- const result = await sleepPromise;
37
+ const result = (await sleepPromise);
38
38
  const duration = performance.now() - start;
39
39
  expect(duration).toBeGreaterThanOrEqual(45);
40
40
  expect(duration).toBeLessThan(150);
41
- expect(result.isOk()).toBe(false);
42
- expect(result.Err().message).toBe("sleep aborted");
41
+ expect(result.isOk).toBe(false);
42
+ expect(result.reason.message).toBe("sleep aborted");
43
43
  });
44
44
  it("completes successfully if not aborted", async () => {
45
45
  const controller = new AbortController();
46
46
  const result = await sleep(50, controller.signal);
47
- expect(result.isOk()).toBe(true);
47
+ expect(result.isOk).toBe(true);
48
48
  });
49
49
  it("cleans up timeout and event listener on abort", async () => {
50
50
  const controller = new AbortController();
51
51
  const sleepPromise = sleep(100, controller.signal);
52
52
  controller.abort();
53
53
  const result = await sleepPromise;
54
- expect(result.isOk()).toBe(false);
54
+ expect(result.isOk).toBe(false);
55
55
  });
56
56
  it("cleans up timeout and event listener on success", async () => {
57
57
  const controller = new AbortController();
58
58
  const result = await sleep(50, controller.signal);
59
- expect(result.isOk()).toBe(true);
59
+ expect(result.isOk).toBe(true);
60
60
  controller.abort();
61
61
  });
62
62
  //# sourceMappingURL=promise-sleep.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"promise-sleep.test.js","sourceRoot":"","sources":["../../../../src/utils/promise-sleep.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"promise-sleep.test.js","sourceRoot":"","sources":["../../../../src/utils/promise-sleep.test.ts"],"names":[],"mappings":"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"}
package/esm/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = "0.4.58";
1
+ export const VERSION = "0.4.60";
2
2
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adviser/cement",
3
- "version": "0.4.58",
3
+ "version": "0.4.60",
4
4
  "description": "better try/catch/finally handling",
5
5
  "main": "./cjs/index.js",
6
6
  "type": "module",
@@ -84,20 +84,20 @@
84
84
  "yaml": "^2.7.1"
85
85
  },
86
86
  "devDependencies": {
87
- "@cloudflare/vitest-pool-workers": "^0.9.1",
88
- "@eslint/js": "^9.20.0",
87
+ "@cloudflare/vitest-pool-workers": "^0.10.3",
88
+ "@eslint/js": "^9.39.1",
89
89
  "@types/deno": "^2.3.0",
90
90
  "@types/fs-extra": "^11.0.4",
91
91
  "@types/node": "^24.4.0",
92
92
  "@types/semver": "^7.7.1",
93
- "@typescript-eslint/eslint-plugin": "^8.7.0",
94
- "@typescript-eslint/parser": "^8.7.0",
95
- "@typescript/native-preview": "7.0.0-dev.20251027.1",
93
+ "@typescript-eslint/eslint-plugin": "^8.46.3",
94
+ "@typescript-eslint/parser": "^8.46.3",
95
+ "@typescript/native-preview": "7.0.0-dev.20251102.1",
96
96
  "@vitest/browser": "^3.2.4",
97
97
  "@vitest/runner": "^3.2.4",
98
98
  "cmd-ts": "^0.14.1",
99
99
  "deno": "^2.5.1",
100
- "eslint": "^9.35.0",
100
+ "eslint": "^9.39.1",
101
101
  "jscodeshift": "^17.3.0",
102
102
  "playwright": "^1.54.1",
103
103
  "prettier": "^3.6.2",
@@ -105,7 +105,7 @@
105
105
  "tsup": "^8.3.0",
106
106
  "tsx": "^4.19.1",
107
107
  "typescript": "^5.9.2",
108
- "typescript-eslint": "^8.44.0",
108
+ "typescript-eslint": "^8.46.3",
109
109
  "vite": "^7.0.4",
110
110
  "vite-tsconfig-paths": "^5.0.1",
111
111
  "vitest": "^3.2.4",
@@ -7,7 +7,7 @@ import {
7
7
  SystemService,
8
8
  VoidFunc,
9
9
  BasicSysAbstraction,
10
- BasicRuntimeService,
10
+ type BasicRuntimeService,
11
11
  } from "./sys-abstraction.js";
12
12
  import { Time } from "./time.js";
13
13
  import { TxtEnDecoder } from "./txt-en-decoder.js";
package/src/future.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Lazy } from "./resolve-once.js";
2
+
1
3
  export class Future<T, CTX = void> {
2
4
  // readonly id = Math.random();
3
5
  readonly #promise: Promise<T>;
@@ -17,6 +19,9 @@ export class Future<T, CTX = void> {
17
19
  });
18
20
  }
19
21
 
22
+ // the id is not cryptographically secure, but good enough for transaction id
23
+ readonly id: () => string = Lazy(() => Math.random().toString(36).substring(2) + Date.now().toString(36));
24
+
20
25
  asPromise(): Promise<T> {
21
26
  return this.#promise;
22
27
  }
package/src/poller.ts CHANGED
@@ -1,64 +1,172 @@
1
+ import { Future } from "./future.js";
1
2
  import { sleep } from "./utils/promise-sleep.js";
2
3
  import { Writable } from "ts-essentials";
3
4
 
4
- export interface PollWaitingActionResult {
5
+ export interface PollerStats {
6
+ readonly attempts: number;
7
+ readonly lastIntervalMs: number;
8
+ readonly totalElapsedMs: number;
9
+ }
10
+
11
+ interface PollWithStats {
12
+ readonly stats: PollerStats;
13
+ }
14
+
15
+ export interface PurPollWaitingActionResult {
5
16
  readonly state: "waiting";
6
17
  }
7
18
 
8
- export interface PollSuccessActionResult<T> {
19
+ export type PollWaitingActionResult = PurPollWaitingActionResult & PollWithStats;
20
+
21
+ export interface PurPollSuccessActionResult<T> {
9
22
  readonly state: "success";
10
23
  readonly result: T;
11
24
  }
12
25
 
13
- export interface PollErrorActionResult {
26
+ export type PollSuccessActionResult<T> = PurPollSuccessActionResult<T> & PollWithStats;
27
+
28
+ export interface PurPollErrorActionResult {
14
29
  readonly state: "error";
15
30
  readonly error: Error;
16
31
  }
17
32
 
18
- export type PollActionResult<T> = PollWaitingActionResult | PollSuccessActionResult<T> | PollErrorActionResult;
33
+ export type PollErrorActionResult = PurPollErrorActionResult & PollWithStats;
34
+
35
+ export interface PurPollTimeoutActionResult {
36
+ readonly state: "timeout";
37
+ }
38
+
39
+ export type PollTimeoutActionResult = PurPollTimeoutActionResult & PollWithStats;
40
+
41
+ export interface PurPollAbortActionResult {
42
+ readonly state: "aborted";
43
+ readonly reason: unknown;
44
+ }
45
+ export type PollAbortActionResult = PurPollAbortActionResult & PollWithStats;
46
+
47
+ export type PollActionResult<T> =
48
+ | PurPollWaitingActionResult
49
+ | PurPollSuccessActionResult<T>
50
+ | PurPollErrorActionResult
51
+ | PurPollTimeoutActionResult
52
+ | PurPollAbortActionResult;
19
53
 
20
54
  export const FOREVER = 2147483647; // Maximum setTimeout delay
21
55
  export interface PollerOptions {
22
56
  readonly intervalMs: number;
57
+ readonly actionTimeoutMs: number; // not -1 it means if a timeout occures the action is retried in the next interval
23
58
  readonly timeoutMs: number;
24
59
  readonly exponentialBackoff: boolean;
25
60
  readonly abortSignal?: AbortSignal;
26
61
  }
27
62
 
28
- export type PollerResult<T> = PollSuccessActionResult<T> | PollErrorActionResult;
63
+ export type PollerResult<T> = PollSuccessActionResult<T> | PollErrorActionResult | PollTimeoutActionResult | PollAbortActionResult;
64
+
65
+ function doneStats(stats: Writable<PollerStats> & { startTime: number }): PollerStats {
66
+ stats.totalElapsedMs = Date.now() - stats.startTime;
67
+ return {
68
+ attempts: stats.attempts,
69
+ lastIntervalMs: stats.lastIntervalMs,
70
+ totalElapsedMs: stats.totalElapsedMs,
71
+ };
72
+ }
29
73
 
30
74
  async function interPoller<T>(
31
75
  fn: (abortSignal?: AbortSignal) => Promise<PollActionResult<T>>,
32
- options: Writable<PollerOptions>,
76
+ options: Writable<Omit<PollerOptions, "abortSignal">>,
77
+ stats: Writable<PollerStats> & { readonly startTime: number },
78
+ abortController: AbortController,
33
79
  ): Promise<PollerResult<T>> {
34
80
  do {
35
- let result: PollActionResult<T>;
81
+ // let result: PollActionResult<T>;
36
82
  try {
37
- result = await fn(options.abortSignal);
83
+ stats.attempts += 1;
84
+
85
+ const abortCheck = new Future<PurPollAbortActionResult>();
86
+ function onAbort(): void {
87
+ abortCheck.resolve({
88
+ state: "aborted",
89
+ reason: abortController.signal.reason,
90
+ });
91
+ }
92
+ const fnAbortController = new AbortController();
93
+ fnAbortController.signal.addEventListener("abort", onAbort, { once: true });
94
+
95
+ const races = [
96
+ fn(fnAbortController.signal).finally(() => {
97
+ // abort all other waits
98
+ fnAbortController.abort();
99
+ }),
100
+ abortCheck.asPromise().finally(() => {
101
+ // abort all other waits
102
+ fnAbortController.abort();
103
+ }),
104
+ ];
105
+ if (options.actionTimeoutMs > 0) {
106
+ races.push(
107
+ sleep(options.actionTimeoutMs, fnAbortController.signal).then((res): PollActionResult<T> => {
108
+ // abort all other waits
109
+ fnAbortController.abort(new Error("poller action timeout"));
110
+ switch (res.state) {
111
+ case "sleeped":
112
+ // timeout occurred but we retry
113
+ return { state: "waiting" as const };
114
+ case "error":
115
+ return { state: "error" as const, error: res.error };
116
+ case "aborted":
117
+ return { state: "aborted" as const, reason: res.reason };
118
+ }
119
+ throw new Error("Unreachable code in poller action timeout");
120
+ }),
121
+ );
122
+ }
123
+ const result = await Promise.race<PollActionResult<T>>(races).finally(() => {
124
+ fnAbortController.signal.removeEventListener("abort", onAbort);
125
+ });
38
126
  switch (result.state) {
39
127
  case "waiting":
40
128
  {
41
129
  if (options.exponentialBackoff) {
42
130
  options.intervalMs = Math.min(options.intervalMs * 2, FOREVER);
43
131
  }
44
- const err = await sleep(options.intervalMs, options.abortSignal);
45
- if (err.isErr()) {
46
- return {
47
- state: "error",
48
- error: err.Err(),
49
- };
132
+ stats.lastIntervalMs = options.intervalMs;
133
+ const res = await sleep(options.intervalMs, abortController.signal);
134
+ switch (true) {
135
+ case res.isAborted:
136
+ return {
137
+ state: "aborted" as const,
138
+ reason: res.reason,
139
+ stats: doneStats(stats),
140
+ };
141
+ case res.isOk:
142
+ break;
143
+ case res.isErr:
144
+ return {
145
+ state: "error",
146
+ error: res.error,
147
+ stats: doneStats(stats),
148
+ };
149
+ default:
150
+ throw new Error("poller interrupted during sleep");
50
151
  }
51
152
  }
52
153
  break;
154
+ case "aborted":
155
+ return {
156
+ state: "aborted" as const,
157
+ reason: result.reason,
158
+ stats: doneStats(stats),
159
+ };
53
160
  case "success":
54
- return result;
161
+ return { ...result, stats: doneStats(stats) };
55
162
  case "error":
56
- return result;
163
+ return { ...result, stats: doneStats(stats) };
57
164
  }
58
165
  } catch (err) {
59
166
  return {
60
167
  state: "error",
61
168
  error: err as Error,
169
+ stats: doneStats(stats),
62
170
  };
63
171
  }
64
172
  // eslint-disable-next-line no-constant-condition
@@ -71,15 +179,43 @@ export async function poller<T>(
71
179
  ): Promise<PollerResult<T>> {
72
180
  const options = {
73
181
  intervalMs: 1000,
74
- timeoutMs: 30000,
182
+ timeoutMs: 30000, // -1 means forever
183
+ actionTimeoutMs: -1, // forever
75
184
  ...ioptions,
76
185
  exponentialBackoff:
77
186
  typeof ioptions.exponentialBackoff === "boolean" ? ioptions.exponentialBackoff : ioptions.timeoutMs === FOREVER,
78
187
  };
79
- return Promise.race([
80
- interPoller(fn, options),
81
- sleep(options.timeoutMs, options.abortSignal)
82
- .then(() => ({ state: "error" as const, error: new Error("Polling timed out") }))
83
- .catch((e: Error) => ({ state: "error" as const, error: e })),
84
- ]);
188
+ const stats = {
189
+ attempts: 0,
190
+ startTime: Date.now(),
191
+ lastIntervalMs: 0,
192
+ totalElapsedMs: 0,
193
+ };
194
+ const abortController = new AbortController();
195
+ const toRemoveEventListeners: (() => void)[] = [];
196
+ if (options.abortSignal) {
197
+ if (options.abortSignal.aborted) {
198
+ abortController.abort(options.abortSignal.reason);
199
+ } else {
200
+ function dispatchAbort(): void {
201
+ abortController.abort(options.abortSignal?.reason);
202
+ }
203
+ toRemoveEventListeners.push(() => {
204
+ options.abortSignal?.removeEventListener("abort", dispatchAbort);
205
+ });
206
+ options.abortSignal.addEventListener("abort", dispatchAbort, { once: true });
207
+ }
208
+ }
209
+ const races = [interPoller(fn, options, stats, abortController)];
210
+ if (options.timeoutMs > 0) {
211
+ races.push(
212
+ sleep(options.timeoutMs, abortController.signal)
213
+ .then(() => ({ state: "timeout" as const, stats: doneStats(stats) }))
214
+ .catch((e: Error) => ({ state: "error" as const, error: e, stats: doneStats(stats) })),
215
+ );
216
+ }
217
+ return Promise.race(races).finally(() => {
218
+ toRemoveEventListeners.forEach((fn) => fn());
219
+ toRemoveEventListeners.length = 0;
220
+ });
85
221
  }