hanzio 1.2.0 → 2.1.0

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 (155) hide show
  1. package/README.md +786 -239
  2. package/dist/api-wrapper/builders.d.ts +4 -3
  3. package/dist/api-wrapper/create-client.d.ts +1 -1
  4. package/dist/api-wrapper/describe.d.ts +16 -0
  5. package/dist/api-wrapper/endpoint.d.ts +18 -0
  6. package/dist/api-wrapper/errors.d.ts +39 -2
  7. package/dist/api-wrapper/index.d.ts +5 -0
  8. package/dist/api-wrapper/otel.d.ts +44 -0
  9. package/dist/api-wrapper/paginate.d.ts +12 -0
  10. package/dist/api-wrapper/redaction.d.ts +2 -0
  11. package/dist/api-wrapper/shared.d.ts +16 -2
  12. package/dist/api-wrapper/testing.d.ts +23 -0
  13. package/dist/api-wrapper/transport.d.ts +4 -5
  14. package/dist/api-wrapper/types.d.ts +103 -18
  15. package/dist/array/index.d.ts +50 -4
  16. package/dist/cache/createCache.d.ts +31 -0
  17. package/dist/cache/index.d.ts +19 -2
  18. package/dist/color/contrast.d.ts +40 -0
  19. package/dist/color/index.d.ts +2 -0
  20. package/dist/{math → color}/metricsSeriesColors.d.ts +14 -7
  21. package/dist/cool-console-log/index.d.ts +34 -5
  22. package/dist/crypto/encoding.d.ts +18 -0
  23. package/dist/crypto/hash.d.ts +33 -0
  24. package/dist/crypto/index.d.ts +4 -0
  25. package/dist/crypto/sealer.d.ts +25 -0
  26. package/dist/crypto/webhook.d.ts +20 -0
  27. package/dist/date/index.d.ts +46 -2
  28. package/dist/emitter/index.d.ts +21 -0
  29. package/dist/error/index.d.ts +12 -0
  30. package/dist/format/index.d.ts +102 -0
  31. package/dist/function/index.d.ts +60 -0
  32. package/dist/guard/index.d.ts +20 -0
  33. package/dist/i18n/index.d.ts +37 -0
  34. package/dist/index-0zvtcbzy.js +224 -0
  35. package/dist/index-8r2vdzjg.js +87 -0
  36. package/dist/index-hy7kbb99.js +157 -0
  37. package/dist/index-hyt6c56h.js +290 -0
  38. package/dist/{src/secrets/infisical.js → index-j1ybktbr.js} +500 -538
  39. package/dist/index-k9yx6bne.js +89 -0
  40. package/dist/index-kj1phgrx.js +169 -0
  41. package/dist/index-ktynw3vs.js +37 -0
  42. package/dist/index-mnkcfyx8.js +78 -0
  43. package/dist/{p-queue/index.js → index-pwt0dz63.js} +7 -11
  44. package/dist/index-rp5pqghz.js +157 -0
  45. package/dist/index-w882zry3.js +29 -0
  46. package/dist/index.d.ts +7 -7
  47. package/dist/jwt/index.d.ts +50 -2
  48. package/dist/math/index.d.ts +2 -2
  49. package/dist/math/linearRegressionTrend.d.ts +14 -1
  50. package/dist/math/scale.d.ts +8 -0
  51. package/dist/object/index.d.ts +19 -0
  52. package/dist/p-queue/index.d.ts +1 -1
  53. package/dist/promise/index.d.ts +97 -2
  54. package/dist/secrets/core.d.ts +7 -0
  55. package/dist/secrets/index.d.ts +3 -1
  56. package/dist/secrets/public-config.d.ts +7 -0
  57. package/dist/secrets/vite.d.ts +1 -0
  58. package/dist/secrets/worker.d.ts +1 -0
  59. package/dist/sitemap/index.d.ts +48 -6
  60. package/dist/src/api-wrapper/index.js +60 -1130
  61. package/dist/src/api-wrapper/testing.js +20 -0
  62. package/dist/{cool-console-log → src/cool-console-log}/index.js +80 -33
  63. package/dist/src/crypto/index.js +195 -0
  64. package/dist/src/format/index.js +211 -0
  65. package/dist/src/i18n/index.js +36 -0
  66. package/dist/src/index.js +739 -3145
  67. package/dist/src/jwt/index.js +138 -92
  68. package/dist/src/p-queue/index.js +9 -437
  69. package/dist/src/secrets/index.js +50 -1428
  70. package/dist/src/secrets/vite.js +10 -39
  71. package/dist/src/secrets/worker.js +14 -273
  72. package/dist/src/sitemap/index.js +183 -511
  73. package/dist/src/storage/index.js +119 -0
  74. package/dist/src/zod/index.js +340 -167
  75. package/dist/state/index.d.ts +21 -0
  76. package/dist/storage/index.d.ts +58 -0
  77. package/dist/string/index.d.ts +75 -2
  78. package/dist/typedswitch/index.d.ts +31 -24
  79. package/dist/types/index.d.ts +11 -0
  80. package/dist/url/index.d.ts +50 -1
  81. package/dist/zod/index.d.ts +32 -3
  82. package/dist/zod/introspect.d.ts +19 -0
  83. package/dist/zod/jsonToZodSchemaMapper.d.ts +3 -1
  84. package/dist/zod/zodMinMaxFilter.d.ts +22 -3
  85. package/dist/zod/zodToTypeString.d.ts +8 -3
  86. package/package.json +78 -7
  87. package/src/api-wrapper/actions-impl.ts +11 -72
  88. package/src/api-wrapper/builders.ts +32 -25
  89. package/src/api-wrapper/create-client.ts +171 -41
  90. package/src/api-wrapper/describe.ts +157 -0
  91. package/src/api-wrapper/endpoint.ts +26 -0
  92. package/src/api-wrapper/error-reporting.ts +7 -1
  93. package/src/api-wrapper/errors.ts +107 -2
  94. package/src/api-wrapper/headers.ts +11 -6
  95. package/src/api-wrapper/index.ts +5 -0
  96. package/src/api-wrapper/otel.ts +139 -0
  97. package/src/api-wrapper/paginate.ts +28 -0
  98. package/src/api-wrapper/redaction.ts +42 -0
  99. package/src/api-wrapper/shared.ts +21 -2
  100. package/src/api-wrapper/testing.ts +48 -0
  101. package/src/api-wrapper/transport.ts +41 -43
  102. package/src/api-wrapper/types.ts +185 -18
  103. package/src/array/index.ts +195 -42
  104. package/src/cache/createCache.ts +157 -0
  105. package/src/cache/index.ts +132 -147
  106. package/src/color/contrast.ts +163 -0
  107. package/src/color/index.ts +22 -0
  108. package/src/{math → color}/metricsSeriesColors.ts +47 -49
  109. package/src/cool-console-log/index.ts +128 -41
  110. package/src/crypto/encoding.ts +83 -0
  111. package/src/crypto/hash.ts +170 -0
  112. package/src/crypto/index.ts +26 -0
  113. package/src/crypto/sealer.ts +168 -0
  114. package/src/crypto/webhook.ts +86 -0
  115. package/src/date/index.ts +109 -34
  116. package/src/emitter/index.ts +82 -0
  117. package/src/error/index.ts +63 -0
  118. package/src/format/index.ts +389 -0
  119. package/src/function/index.ts +201 -0
  120. package/src/guard/index.ts +80 -0
  121. package/src/i18n/index.ts +125 -0
  122. package/src/index.ts +11 -7
  123. package/src/jwt/index.ts +199 -125
  124. package/src/math/index.ts +5 -10
  125. package/src/math/linearRegressionTrend.ts +33 -8
  126. package/src/math/scale.ts +17 -0
  127. package/src/object/index.ts +99 -0
  128. package/src/p-queue/index.ts +2 -0
  129. package/src/promise/index.ts +304 -9
  130. package/src/secrets/core.ts +72 -16
  131. package/src/secrets/index.ts +16 -4
  132. package/src/secrets/public-config.ts +47 -0
  133. package/src/secrets/vite.ts +2 -0
  134. package/src/secrets/worker.ts +2 -0
  135. package/src/sitemap/index.ts +293 -130
  136. package/src/state/index.ts +133 -81
  137. package/src/storage/index.ts +187 -0
  138. package/src/string/index.ts +261 -23
  139. package/src/typedswitch/index.ts +58 -38
  140. package/src/types/index.ts +14 -0
  141. package/src/url/index.ts +146 -1
  142. package/src/zod/index.ts +105 -9
  143. package/src/zod/introspect.ts +103 -0
  144. package/src/zod/jsonToZodSchemaMapper.ts +44 -21
  145. package/src/zod/zodMinMaxFilter.ts +37 -13
  146. package/src/zod/zodToTypeString.ts +184 -181
  147. package/dist/api-wrapper/index.js +0 -250
  148. package/dist/gzip/index.d.ts +0 -2
  149. package/dist/gzip/index.js +0 -16
  150. package/dist/index.js +0 -1823
  151. package/dist/jwt/index.js +0 -19
  152. package/dist/sitemap/index.js +0 -552
  153. package/dist/src/gzip/index.js +0 -16
  154. package/dist/src/secrets/loaders.js +0 -1529
  155. package/dist/zod/index.js +0 -210
@@ -1,110 +1,156 @@
1
+ import {
2
+ utf8Encode2,
3
+ utf8Decode2,
4
+ encodeBase64Url2,
5
+ decodeBase64Url2,
6
+ getSubtleCrypto
7
+ } from "../../index-rp5pqghz.js";
8
+ import {
9
+ isRecord2
10
+ } from "../../index-8r2vdzjg.js";
11
+
1
12
  // src/jwt/index.ts
2
- var BYTE_CHUNK_SIZE = 32768;
3
- var textEncoder = new TextEncoder;
4
- var textDecoder = new TextDecoder;
5
- async function jwtSign(payload, secret) {
6
- const header = encodeJson({ alg: "HS256" });
7
- const body = encodeJson({
8
- ...payload,
9
- iat: Math.floor(Date.now() / 1000)
10
- });
11
- const data = `${header}.${body}`;
12
- const signature = await sign(data, secret);
13
- return `${data}.${encodeBase64Url(signature)}`;
13
+ class JwtVerifyError extends Error {
14
+ code;
15
+ constructor(code) {
16
+ super(`JWT verification failed: ${code}`);
17
+ this.name = "JwtVerifyError";
18
+ this.code = code;
19
+ }
14
20
  }
15
- async function jwtVerify(token, secret) {
21
+ var HASHES = {
22
+ HS256: "SHA-256",
23
+ HS384: "SHA-384",
24
+ HS512: "SHA-512"
25
+ };
26
+ var ALGORITHMS = Object.keys(HASHES);
27
+ var BASE64URL = /^[A-Za-z0-9_-]*$/;
28
+ var KEY_CACHE_LIMIT = 100;
29
+ async function jwtSign(payload, secret, options = {}) {
30
+ const {
31
+ expiresIn,
32
+ notBefore,
33
+ issuer,
34
+ audience,
35
+ algorithm = "HS256"
36
+ } = options;
37
+ if (!Object.hasOwn(HASHES, algorithm)) {
38
+ throw new TypeError(`Unsupported JWT algorithm: ${algorithm}`);
39
+ }
40
+ const now = Math.floor(Date.now() / 1000);
41
+ const claims = { ...payload, iat: now };
42
+ if (expiresIn !== undefined)
43
+ claims.exp = now + toSeconds(expiresIn);
44
+ if (notBefore !== undefined)
45
+ claims.nbf = now + toSeconds(notBefore);
46
+ if (issuer !== undefined)
47
+ claims.iss = issuer;
48
+ if (audience !== undefined)
49
+ claims.aud = audience;
50
+ const data = `${encodeJson({ alg: algorithm, typ: "JWT" })}.${encodeJson(claims)}`;
51
+ const key = await getKey(secret, algorithm, "sign");
52
+ const signature = await getSubtleCrypto().sign("HMAC", key, utf8Encode2(data));
53
+ return `${data}.${encodeBase64Url2(signature)}`;
54
+ }
55
+ async function jwtVerify(token, secret, options) {
16
56
  try {
17
- const parts = token.split(".");
18
- if (parts.length !== 3)
19
- return null;
20
- const [encodedHeader, encodedPayload, encodedSignature] = parts;
21
- const header = decodeJson(encodedHeader);
22
- if (!isJwtHeader(header))
23
- return null;
24
- const data = `${encodedHeader}.${encodedPayload}`;
25
- const signature = decodeBase64Url(encodedSignature);
26
- const isValid = await verify(data, signature, secret);
27
- if (!isValid)
28
- return null;
29
- const payload = decodeJson(encodedPayload);
30
- if (!isJwtPayload(payload) || !isTimeValid(payload))
31
- return null;
32
- return payload;
57
+ const result = await jwtVerifyResult(token, secret, options);
58
+ return result.ok ? result.data : null;
33
59
  } catch (_error) {
34
60
  return null;
35
61
  }
36
62
  }
37
- async function sign(data, secret) {
38
- const key = await getKey(secret, ["sign"]);
39
- return await getSubtleCrypto().sign("HMAC", key, encodeText(data));
40
- }
41
- async function verify(data, signature, secret) {
42
- const key = await getKey(secret, ["verify"]);
43
- return await getSubtleCrypto().verify("HMAC", key, signature, encodeText(data));
44
- }
45
- async function getKey(secret, usages) {
46
- return await getSubtleCrypto().importKey("raw", encodeText(secret), {
47
- name: "HMAC",
48
- hash: "SHA-256"
49
- }, false, usages);
50
- }
51
- function encodeJson(value) {
52
- return encodeBase64Url(encodeText(JSON.stringify(value)));
53
- }
54
- function decodeJson(value) {
55
- return JSON.parse(textDecoder.decode(decodeBase64Url(value)));
56
- }
57
- function encodeBase64Url(value) {
58
- const bytes = value instanceof ArrayBuffer ? new Uint8Array(value) : value;
59
- return btoa(bytesToBinaryString(bytes)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
60
- }
61
- function decodeBase64Url(value) {
62
- const base64 = value.replaceAll("-", "+").replaceAll("_", "/");
63
- const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
64
- return binaryStringToBytes(atob(padded)).buffer;
65
- }
66
- function encodeText(value) {
67
- return toArrayBuffer(textEncoder.encode(value));
68
- }
69
- function toArrayBuffer(bytes) {
70
- return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
71
- }
72
- function bytesToBinaryString(bytes) {
73
- let binary = "";
74
- for (let offset = 0;offset < bytes.length; offset += BYTE_CHUNK_SIZE) {
75
- binary += String.fromCharCode(...bytes.subarray(offset, offset + BYTE_CHUNK_SIZE));
63
+ async function jwtVerifyResult(token, secret, options = {}) {
64
+ const { leewaySec = 0, issuer, audience, algorithms = ALGORITHMS } = options;
65
+ const decoded = jwtDecode(token);
66
+ if (!decoded)
67
+ return fail("malformed");
68
+ const { alg } = decoded.header;
69
+ if (!Object.hasOwn(HASHES, alg) || !algorithms.includes(alg)) {
70
+ return fail("unsupported_alg");
76
71
  }
77
- return binary;
78
- }
79
- function binaryStringToBytes(binary) {
80
- const bytes = new Uint8Array(binary.length);
81
- for (let index = 0;index < binary.length; index += 1) {
82
- bytes[index] = binary.charCodeAt(index);
72
+ const lastDot = token.lastIndexOf(".");
73
+ let signature;
74
+ try {
75
+ signature = decodeBase64Url2(token.slice(lastDot + 1));
76
+ } catch (_error) {
77
+ return fail("malformed");
78
+ }
79
+ const key = await getKey(secret, alg, "verify");
80
+ const isValid = await getSubtleCrypto().verify("HMAC", key, signature, utf8Encode2(token.slice(0, lastDot)));
81
+ if (!isValid)
82
+ return fail("invalid_signature");
83
+ const { payload } = decoded;
84
+ const { exp, nbf } = payload;
85
+ if (exp !== undefined && typeof exp !== "number")
86
+ return fail("malformed");
87
+ if (nbf !== undefined && typeof nbf !== "number")
88
+ return fail("malformed");
89
+ const now = Math.floor(Date.now() / 1000);
90
+ if (exp !== undefined && now >= exp + leewaySec)
91
+ return fail("expired");
92
+ if (nbf !== undefined && now + leewaySec < nbf)
93
+ return fail("not_yet_valid");
94
+ if (issuer !== undefined && payload.iss !== issuer) {
95
+ return fail("invalid_issuer");
83
96
  }
84
- return bytes;
97
+ if (audience !== undefined) {
98
+ const { aud } = payload;
99
+ const matches = Array.isArray(aud) ? aud.includes(audience) : aud === audience;
100
+ if (!matches)
101
+ return fail("invalid_audience");
102
+ }
103
+ return { ok: true, data: payload, error: null };
85
104
  }
86
- function getSubtleCrypto() {
87
- const subtle = globalThis.crypto?.subtle;
88
- if (!subtle) {
89
- throw new Error("Web Crypto is not available in this runtime");
105
+ function jwtDecode(token) {
106
+ const parts = token.split(".");
107
+ if (parts.length !== 3 || !parts.every((part) => BASE64URL.test(part))) {
108
+ return null;
109
+ }
110
+ try {
111
+ const header = decodeJson(parts[0]);
112
+ const payload = decodeJson(parts[1]);
113
+ if (!isRecord2(header) || typeof header.alg !== "string")
114
+ return null;
115
+ if (!isRecord2(payload))
116
+ return null;
117
+ return { header, payload };
118
+ } catch (_error) {
119
+ return null;
90
120
  }
91
- return subtle;
92
121
  }
93
- function isJwtHeader(value) {
94
- return typeof value === "object" && value !== null && "alg" in value && value.alg === "HS256";
122
+ function fail(code) {
123
+ return { ok: false, data: null, error: new JwtVerifyError(code) };
95
124
  }
96
- function isJwtPayload(value) {
97
- return typeof value === "object" && value !== null && !Array.isArray(value);
125
+ function toSeconds(value) {
126
+ if (!Number.isFinite(value)) {
127
+ throw new TypeError(`Expected a finite number of seconds, got ${value}`);
128
+ }
129
+ return Math.floor(value);
130
+ }
131
+ var keyCache = new Map;
132
+ function getKey(secret, algorithm, usage) {
133
+ const cacheKey = `${algorithm}:${usage}:${secret}`;
134
+ const cached = keyCache.get(cacheKey);
135
+ if (cached)
136
+ return cached;
137
+ if (keyCache.size >= KEY_CACHE_LIMIT)
138
+ keyCache.clear();
139
+ const key = getSubtleCrypto().importKey("raw", utf8Encode2(secret), { name: "HMAC", hash: HASHES[algorithm] }, false, [usage]);
140
+ keyCache.set(cacheKey, key);
141
+ key.catch(() => keyCache.delete(cacheKey));
142
+ return key;
98
143
  }
99
- function isTimeValid(payload) {
100
- const now = Math.floor(Date.now() / 1000);
101
- if (typeof payload.exp === "number" && now >= payload.exp)
102
- return false;
103
- if (typeof payload.nbf === "number" && now < payload.nbf)
104
- return false;
105
- return true;
144
+ function encodeJson(value) {
145
+ return encodeBase64Url2(utf8Encode2(JSON.stringify(value)));
146
+ }
147
+ function decodeJson(value) {
148
+ return JSON.parse(utf8Decode2(decodeBase64Url2(value)));
106
149
  }
107
150
  export {
151
+ JwtVerifyError,
152
+ jwtDecode,
108
153
  jwtSign,
109
- jwtVerify
154
+ jwtVerify,
155
+ jwtVerifyResult
110
156
  };
@@ -1,439 +1,11 @@
1
- // src/p-queue/index.ts
2
- class TimeoutError extends Error {
3
- constructor(message) {
4
- super(message);
5
- this.name = "TimeoutError";
6
- }
7
- }
8
-
9
- class PriorityQueue {
10
- #queue = [];
11
- enqueue(run, options = {}) {
12
- const element = {
13
- priority: options.priority ?? 0,
14
- id: options.id,
15
- run
16
- };
17
- const index = this.#queue.findIndex((item) => item.priority < element.priority);
18
- if (index === -1) {
19
- this.#queue.push(element);
20
- return;
21
- }
22
- this.#queue.splice(index, 0, element);
23
- }
24
- dequeue() {
25
- return this.#queue.shift()?.run;
26
- }
27
- filter(options) {
28
- return this.#queue.filter((item) => Object.entries(options).every(([key, value]) => item[key] === value)).map((item) => item.run);
29
- }
30
- setPriority(id, priority) {
31
- const index = this.#queue.findIndex((item) => item.id === id);
32
- if (index === -1) {
33
- throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
34
- }
35
- const [item] = this.#queue.splice(index, 1);
36
- this.enqueue(item.run, { ...item, priority });
37
- }
38
- remove(id) {
39
- const index = this.#queue.findIndex((item) => item.id === id);
40
- if (index !== -1) {
41
- this.#queue.splice(index, 1);
42
- }
43
- }
44
- get size() {
45
- return this.#queue.length;
46
- }
47
- }
48
-
49
- class PQueue {
50
- #listeners = new Map;
51
- #queue;
52
- #queueClass;
53
- #pending = 0;
54
- #concurrency;
55
- #isPaused;
56
- #intervalCap;
57
- #interval;
58
- #carryoverIntervalCount;
59
- #strict;
60
- #intervalCount = 0;
61
- #intervalEnd = 0;
62
- #intervalTimer;
63
- #strictTimestamps = [];
64
- #rateLimited = false;
65
- #idCounter = 1n;
66
- #runningTasks = new Map;
67
- timeout;
68
- constructor(options = {}) {
69
- const {
70
- concurrency = Number.POSITIVE_INFINITY,
71
- autoStart = true,
72
- queueClass = PriorityQueue,
73
- intervalCap = Number.POSITIVE_INFINITY,
74
- interval = 0,
75
- carryoverIntervalCount,
76
- carryoverConcurrencyCount,
77
- strict = false,
78
- timeout
79
- } = options;
80
- if (!(typeof concurrency === "number" && concurrency >= 1)) {
81
- throw new TypeError("Expected `concurrency` to be a number from 1 and up");
82
- }
83
- if (!(typeof intervalCap === "number" && intervalCap >= 1)) {
84
- throw new TypeError("Expected `intervalCap` to be a number from 1 and up");
85
- }
86
- if (!(typeof interval === "number" && Number.isFinite(interval) && interval >= 0)) {
87
- throw new TypeError("Expected `interval` to be a finite number >= 0");
88
- }
89
- if (strict && interval === 0) {
90
- throw new TypeError("The `strict` option requires a non-zero `interval`");
91
- }
92
- if (strict && intervalCap === Number.POSITIVE_INFINITY) {
93
- throw new TypeError("The `strict` option requires a finite `intervalCap`");
94
- }
95
- if (timeout !== undefined && !(Number.isFinite(timeout) && timeout > 0)) {
96
- throw new TypeError("Expected `timeout` to be a positive finite number");
97
- }
98
- this.#queueClass = queueClass;
99
- this.#queue = new queueClass;
100
- this.#concurrency = concurrency;
101
- this.#isPaused = !autoStart;
102
- this.#intervalCap = intervalCap;
103
- this.#interval = interval;
104
- this.#carryoverIntervalCount = carryoverIntervalCount ?? carryoverConcurrencyCount ?? false;
105
- this.#strict = strict;
106
- this.timeout = timeout;
107
- }
108
- on(event, listener) {
109
- const listeners = this.#listeners.get(event) ?? new Set;
110
- listeners.add(listener);
111
- this.#listeners.set(event, listeners);
112
- return this;
113
- }
114
- off(event, listener) {
115
- this.#listeners.get(event)?.delete(listener);
116
- return this;
117
- }
118
- emit(event, ...arguments_) {
119
- const listeners = this.#listeners.get(event);
120
- if (!listeners || listeners.size === 0) {
121
- return false;
122
- }
123
- for (const listener of [...listeners]) {
124
- listener(...arguments_);
125
- }
126
- return true;
127
- }
128
- get concurrency() {
129
- return this.#concurrency;
130
- }
131
- set concurrency(newConcurrency) {
132
- if (!(typeof newConcurrency === "number" && newConcurrency >= 1)) {
133
- throw new TypeError("Expected `concurrency` to be a number from 1 and up");
134
- }
135
- this.#concurrency = newConcurrency;
136
- this.#processQueue();
137
- }
138
- get size() {
139
- return this.#queue.size;
140
- }
141
- sizeBy(options) {
142
- return this.#queue.filter(options).length;
143
- }
144
- get pending() {
145
- return this.#pending;
146
- }
147
- get isPaused() {
148
- return this.#isPaused;
149
- }
150
- get isRateLimited() {
151
- this.#updateRateLimitState();
152
- return this.#rateLimited;
153
- }
154
- get isSaturated() {
155
- return this.#pending >= this.#concurrency && this.#queue.size > 0 || this.isRateLimited && this.#queue.size > 0;
156
- }
157
- get runningTasks() {
158
- return [...this.#runningTasks.values()].map((task) => ({ ...task }));
159
- }
160
- setPriority(id, priority) {
161
- if (typeof priority !== "number" || !Number.isFinite(priority)) {
162
- throw new TypeError("Expected `priority` to be a finite number");
163
- }
164
- this.#queue.setPriority(id, priority);
165
- }
166
- async add(function_, options = {}) {
167
- const taskOptions = {
168
- timeout: this.timeout,
169
- ...options,
170
- id: options.id ?? (this.#idCounter++).toString()
171
- };
172
- return new Promise((resolve, reject) => {
173
- const taskSymbol = Symbol(taskOptions.id);
174
- let didRun = false;
175
- let queuedAbortHandler;
176
- let runningAbortHandler;
177
- const cleanupQueuedAbort = () => {
178
- if (queuedAbortHandler) {
179
- taskOptions.signal?.removeEventListener("abort", queuedAbortHandler);
180
- queuedAbortHandler = undefined;
181
- }
182
- };
183
- const run = async () => {
184
- didRun = true;
185
- cleanupQueuedAbort();
186
- this.#pending++;
187
- this.#runningTasks.set(taskSymbol, {
188
- id: taskOptions.id,
189
- priority: taskOptions.priority ?? 0,
190
- startTime: Date.now(),
191
- timeout: taskOptions.timeout
192
- });
193
- try {
194
- taskOptions.signal?.throwIfAborted();
195
- const operation = Promise.resolve(function_({ signal: taskOptions.signal }));
196
- const result = await this.#withTimeoutAndAbort(operation, taskOptions, (listener) => {
197
- runningAbortHandler = listener;
198
- });
199
- resolve(result);
200
- this.emit("completed", result);
201
- } catch (error) {
202
- reject(error);
203
- this.emit("error", error);
204
- } finally {
205
- if (runningAbortHandler) {
206
- taskOptions.signal?.removeEventListener("abort", runningAbortHandler);
207
- }
208
- this.#runningTasks.delete(taskSymbol);
209
- queueMicrotask(() => {
210
- this.#next();
211
- });
212
- }
213
- };
214
- if (taskOptions.signal?.aborted) {
215
- reject(taskOptions.signal.reason);
216
- return;
217
- }
218
- if (taskOptions.signal) {
219
- queuedAbortHandler = () => {
220
- if (didRun) {
221
- return;
222
- }
223
- this.#queue.remove?.(taskOptions.id);
224
- reject(taskOptions.signal?.reason);
225
- this.emit("next");
226
- this.#tryToStartAnother();
227
- };
228
- taskOptions.signal.addEventListener("abort", queuedAbortHandler, {
229
- once: true
230
- });
231
- }
232
- this.#queue.enqueue(run, taskOptions);
233
- this.emit("add");
234
- this.#processQueue();
235
- });
236
- }
237
- async addAll(functions, options) {
238
- return Promise.all(functions.map(async (function_) => this.add(function_, options)));
239
- }
240
- start() {
241
- if (!this.#isPaused) {
242
- return this;
243
- }
244
- this.#isPaused = false;
245
- this.#processQueue();
246
- return this;
247
- }
248
- pause() {
249
- this.#isPaused = true;
250
- }
251
- clear() {
252
- this.#queue = new this.#queueClass;
253
- this.#clearIntervalTimer();
254
- this.#updateRateLimitState();
255
- this.emit("empty");
256
- if (this.#pending === 0) {
257
- this.emit("idle");
258
- }
259
- this.emit("next");
260
- }
261
- async onEmpty() {
262
- if (this.#queue.size === 0) {
263
- return;
264
- }
265
- await this.#onEvent("empty");
266
- }
267
- async onIdle() {
268
- if (this.#queue.size === 0 && this.#pending === 0) {
269
- return;
270
- }
271
- await this.#onEvent("idle");
272
- }
273
- async onPendingZero() {
274
- if (this.#pending === 0) {
275
- return;
276
- }
277
- await this.#onEvent("pendingZero");
278
- }
279
- async onRateLimit() {
280
- if (this.isRateLimited) {
281
- return;
282
- }
283
- await this.#onEvent("rateLimit");
284
- }
285
- async onRateLimitCleared() {
286
- if (!this.isRateLimited) {
287
- return;
288
- }
289
- await this.#onEvent("rateLimitCleared");
290
- }
291
- onError() {
292
- return new Promise((_resolve, reject) => {
293
- const listener = (error) => {
294
- this.off("error", listener);
295
- reject(error);
296
- };
297
- this.on("error", listener);
298
- });
299
- }
300
- async onSizeLessThan(limit) {
301
- if (this.#queue.size < limit) {
302
- return;
303
- }
304
- await this.#onEvent("next", () => this.#queue.size < limit);
305
- }
306
- async#onEvent(event, filter) {
307
- return new Promise((resolve) => {
308
- const listener = () => {
309
- if (filter && !filter()) {
310
- return;
311
- }
312
- this.off(event, listener);
313
- resolve();
314
- };
315
- this.on(event, listener);
316
- });
317
- }
318
- async#withTimeoutAndAbort(operation, options, setAbortListener) {
319
- const races = [operation];
320
- let timeoutId;
321
- if (options.timeout) {
322
- races.push(new Promise((_resolve, reject) => {
323
- timeoutId = setTimeout(() => {
324
- reject(new TimeoutError(`Task timed out after ${options.timeout}ms`));
325
- }, options.timeout);
326
- }));
327
- }
328
- if (options.signal) {
329
- races.push(new Promise((_resolve, reject) => {
330
- const listener = () => {
331
- reject(options.signal?.reason);
332
- };
333
- setAbortListener(listener);
334
- options.signal?.addEventListener("abort", listener, { once: true });
335
- }));
336
- }
337
- try {
338
- return await Promise.race(races);
339
- } finally {
340
- if (timeoutId) {
341
- clearTimeout(timeoutId);
342
- }
343
- }
344
- }
345
- #next() {
346
- this.#pending--;
347
- if (this.#pending === 0) {
348
- this.emit("pendingZero");
349
- }
350
- this.#processQueue();
351
- this.emit("next");
352
- }
353
- #processQueue() {
354
- while (this.#tryToStartAnother()) {}
355
- this.#updateRateLimitState();
356
- }
357
- #tryToStartAnother() {
358
- if (this.#queue.size === 0) {
359
- this.#clearIntervalTimer();
360
- this.emit("empty");
361
- if (this.#pending === 0) {
362
- this.emit("idle");
363
- }
364
- return false;
365
- }
366
- if (this.#isPaused || this.#pending >= this.#concurrency || !this.#doesIntervalAllowAnother()) {
367
- return false;
368
- }
369
- const job = this.#queue.dequeue();
370
- if (!job) {
371
- return false;
372
- }
373
- this.#consumeIntervalSlot();
374
- this.emit("active");
375
- job();
376
- return true;
377
- }
378
- #doesIntervalAllowAnother() {
379
- if (this.#intervalCap === Number.POSITIVE_INFINITY || this.#interval === 0) {
380
- return true;
381
- }
382
- const now = Date.now();
383
- if (this.#strict) {
384
- this.#strictTimestamps = this.#strictTimestamps.filter((timestamp) => now - timestamp < this.#interval);
385
- if (this.#strictTimestamps.length < this.#intervalCap) {
386
- return true;
387
- }
388
- this.#scheduleIntervalResume(this.#interval - (now - this.#strictTimestamps[0]));
389
- return false;
390
- }
391
- if (this.#intervalEnd === 0 || now >= this.#intervalEnd) {
392
- this.#intervalCount = this.#carryoverIntervalCount ? this.#pending : 0;
393
- this.#intervalEnd = now + this.#interval;
394
- }
395
- if (this.#intervalCount < this.#intervalCap) {
396
- return true;
397
- }
398
- this.#scheduleIntervalResume(this.#intervalEnd - now);
399
- return false;
400
- }
401
- #consumeIntervalSlot() {
402
- if (this.#intervalCap === Number.POSITIVE_INFINITY || this.#interval === 0) {
403
- return;
404
- }
405
- if (this.#strict) {
406
- this.#strictTimestamps.push(Date.now());
407
- return;
408
- }
409
- this.#intervalCount++;
410
- }
411
- #scheduleIntervalResume(delay) {
412
- if (this.#intervalTimer) {
413
- return;
414
- }
415
- this.#intervalTimer = setTimeout(() => {
416
- this.#intervalTimer = undefined;
417
- this.#processQueue();
418
- }, Math.max(0, delay));
419
- }
420
- #clearIntervalTimer() {
421
- if (this.#intervalTimer) {
422
- clearTimeout(this.#intervalTimer);
423
- this.#intervalTimer = undefined;
424
- }
425
- }
426
- #updateRateLimitState() {
427
- const previous = this.#rateLimited;
428
- const isRateLimited = this.#queue.size > 0 && this.#intervalCap !== Number.POSITIVE_INFINITY && this.#interval > 0 && !this.#doesIntervalAllowAnother();
429
- this.#rateLimited = isRateLimited;
430
- if (previous !== isRateLimited) {
431
- this.emit(isRateLimited ? "rateLimit" : "rateLimitCleared");
432
- }
433
- }
434
- }
1
+ import {
2
+ TimeoutError2,
3
+ PriorityQueue2,
4
+ PQueue2
5
+ } from "../../index-pwt0dz63.js";
435
6
  export {
436
- PriorityQueue,
437
- TimeoutError,
438
- PQueue as default
7
+ PQueue2 as PQueue,
8
+ PriorityQueue2 as PriorityQueue,
9
+ TimeoutError2 as TimeoutError,
10
+ PQueue2 as default
439
11
  };