hanzio 1.1.0 → 2.0.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 (172) hide show
  1. package/README.md +832 -219
  2. package/dist/api-wrapper/builders.d.ts +15 -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 +40 -2
  7. package/dist/api-wrapper/headers.d.ts +2 -1
  8. package/dist/api-wrapper/index.d.ts +5 -0
  9. package/dist/api-wrapper/otel.d.ts +44 -0
  10. package/dist/api-wrapper/paginate.d.ts +12 -0
  11. package/dist/api-wrapper/redaction.d.ts +2 -0
  12. package/dist/api-wrapper/shared.d.ts +16 -2
  13. package/dist/api-wrapper/testing.d.ts +23 -0
  14. package/dist/api-wrapper/transport.d.ts +12 -10
  15. package/dist/api-wrapper/types.d.ts +104 -18
  16. package/dist/array/index.d.ts +50 -4
  17. package/dist/cache/createCache.d.ts +31 -0
  18. package/dist/cache/index.d.ts +45 -2
  19. package/dist/color/contrast.d.ts +40 -0
  20. package/dist/color/index.d.ts +2 -0
  21. package/dist/{math → color}/metricsSeriesColors.d.ts +14 -7
  22. package/dist/cool-console-log/index.d.ts +34 -5
  23. package/dist/crypto/encoding.d.ts +18 -0
  24. package/dist/crypto/hash.d.ts +33 -0
  25. package/dist/crypto/index.d.ts +4 -0
  26. package/dist/crypto/sealer.d.ts +25 -0
  27. package/dist/crypto/webhook.d.ts +20 -0
  28. package/dist/date/index.d.ts +46 -2
  29. package/dist/emitter/index.d.ts +21 -0
  30. package/dist/error/index.d.ts +12 -0
  31. package/dist/format/index.d.ts +102 -0
  32. package/dist/function/index.d.ts +60 -0
  33. package/dist/guard/index.d.ts +20 -0
  34. package/dist/i18n/index.d.ts +37 -0
  35. package/dist/index-0zvtcbzy.js +224 -0
  36. package/dist/index-181e6vfw.js +29 -0
  37. package/dist/index-8r2vdzjg.js +87 -0
  38. package/dist/index-hy7kbb99.js +157 -0
  39. package/dist/{src/secrets/loaders.js → index-j1ybktbr.js} +608 -405
  40. package/dist/index-k9yx6bne.js +89 -0
  41. package/dist/index-kj1phgrx.js +169 -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-srt06xd2.js +15 -0
  46. package/dist/index-wjyb9bsd.js +263 -0
  47. package/dist/index.d.ts +7 -7
  48. package/dist/jwt/index.d.ts +50 -2
  49. package/dist/math/index.d.ts +2 -2
  50. package/dist/math/linearRegressionTrend.d.ts +14 -1
  51. package/dist/math/scale.d.ts +8 -0
  52. package/dist/object/index.d.ts +19 -0
  53. package/dist/p-queue/index.d.ts +1 -1
  54. package/dist/promise/index.d.ts +97 -2
  55. package/dist/secrets/core.d.ts +47 -0
  56. package/dist/secrets/deadline.d.ts +6 -0
  57. package/dist/secrets/environment.d.ts +9 -0
  58. package/dist/secrets/errors.d.ts +11 -0
  59. package/dist/secrets/index.d.ts +13 -25
  60. package/dist/secrets/infisical-cli.d.ts +6 -0
  61. package/dist/secrets/infisical-config.d.ts +17 -0
  62. package/dist/secrets/infisical-session.d.ts +4 -0
  63. package/dist/secrets/infisical.d.ts +8 -13
  64. package/dist/secrets/loaders.d.ts +5 -12
  65. package/dist/secrets/vite.d.ts +7 -3
  66. package/dist/secrets/worker-loader.d.ts +9 -0
  67. package/dist/secrets/worker.d.ts +3 -0
  68. package/dist/sitemap/index.d.ts +48 -6
  69. package/dist/src/api-wrapper/index.js +60 -1100
  70. package/dist/src/api-wrapper/testing.js +20 -0
  71. package/dist/{cool-console-log → src/cool-console-log}/index.js +80 -33
  72. package/dist/src/crypto/index.js +195 -0
  73. package/dist/src/format/index.js +211 -0
  74. package/dist/src/i18n/index.js +36 -0
  75. package/dist/src/index.js +863 -2809
  76. package/dist/src/jwt/index.js +138 -92
  77. package/dist/src/p-queue/index.js +9 -437
  78. package/dist/src/secrets/index.js +261 -1377
  79. package/dist/src/secrets/vite.js +6 -17
  80. package/dist/src/secrets/worker.js +12 -0
  81. package/dist/src/sitemap/index.js +183 -511
  82. package/dist/src/storage/index.js +119 -0
  83. package/dist/src/zod/index.js +347 -174
  84. package/dist/state/index.d.ts +21 -0
  85. package/dist/storage/index.d.ts +58 -0
  86. package/dist/string/index.d.ts +75 -2
  87. package/dist/typedswitch/index.d.ts +37 -26
  88. package/dist/types/index.d.ts +11 -0
  89. package/dist/url/index.d.ts +50 -1
  90. package/dist/zod/index.d.ts +32 -3
  91. package/dist/zod/introspect.d.ts +19 -0
  92. package/dist/zod/jsonToZodSchemaMapper.d.ts +3 -1
  93. package/dist/zod/zodMinMaxFilter.d.ts +22 -3
  94. package/dist/zod/zodToTypeString.d.ts +8 -3
  95. package/package.json +87 -7
  96. package/src/api-wrapper/actions-impl.ts +11 -72
  97. package/src/api-wrapper/builders.ts +84 -52
  98. package/src/api-wrapper/create-client.ts +246 -96
  99. package/src/api-wrapper/describe.ts +157 -0
  100. package/src/api-wrapper/endpoint.ts +26 -0
  101. package/src/api-wrapper/error-reporting.ts +7 -1
  102. package/src/api-wrapper/errors.ts +117 -2
  103. package/src/api-wrapper/headers.ts +19 -1
  104. package/src/api-wrapper/index.ts +5 -0
  105. package/src/api-wrapper/otel.ts +139 -0
  106. package/src/api-wrapper/paginate.ts +28 -0
  107. package/src/api-wrapper/redaction.ts +43 -0
  108. package/src/api-wrapper/shared.ts +21 -2
  109. package/src/api-wrapper/testing.ts +48 -0
  110. package/src/api-wrapper/transport.ts +68 -74
  111. package/src/api-wrapper/types.ts +186 -18
  112. package/src/array/index.ts +195 -42
  113. package/src/cache/createCache.ts +157 -0
  114. package/src/cache/index.ts +235 -83
  115. package/src/color/contrast.ts +163 -0
  116. package/src/color/index.ts +22 -0
  117. package/src/{math → color}/metricsSeriesColors.ts +47 -49
  118. package/src/cool-console-log/index.ts +128 -41
  119. package/src/crypto/encoding.ts +83 -0
  120. package/src/crypto/hash.ts +170 -0
  121. package/src/crypto/index.ts +26 -0
  122. package/src/crypto/sealer.ts +168 -0
  123. package/src/crypto/webhook.ts +86 -0
  124. package/src/date/index.ts +109 -34
  125. package/src/emitter/index.ts +82 -0
  126. package/src/error/index.ts +63 -0
  127. package/src/format/index.ts +389 -0
  128. package/src/function/index.ts +201 -0
  129. package/src/guard/index.ts +80 -0
  130. package/src/i18n/index.ts +125 -0
  131. package/src/index.ts +11 -7
  132. package/src/jwt/index.ts +199 -125
  133. package/src/math/index.ts +5 -10
  134. package/src/math/linearRegressionTrend.ts +33 -8
  135. package/src/math/scale.ts +17 -0
  136. package/src/object/index.ts +99 -0
  137. package/src/p-queue/index.ts +2 -0
  138. package/src/promise/index.ts +304 -9
  139. package/src/secrets/core.ts +348 -0
  140. package/src/secrets/deadline.ts +69 -0
  141. package/src/secrets/environment.ts +69 -0
  142. package/src/secrets/errors.ts +29 -0
  143. package/src/secrets/index.ts +79 -210
  144. package/src/secrets/infisical-cli.ts +99 -0
  145. package/src/secrets/infisical-config.ts +70 -0
  146. package/src/secrets/infisical-session.ts +42 -0
  147. package/src/secrets/infisical.ts +214 -66
  148. package/src/secrets/loaders.ts +24 -48
  149. package/src/secrets/vite.ts +44 -15
  150. package/src/secrets/worker-loader.ts +56 -0
  151. package/src/secrets/worker.ts +4 -0
  152. package/src/sitemap/index.ts +293 -130
  153. package/src/state/index.ts +133 -81
  154. package/src/storage/index.ts +187 -0
  155. package/src/string/index.ts +261 -23
  156. package/src/typedswitch/index.ts +134 -103
  157. package/src/types/index.ts +14 -0
  158. package/src/url/index.ts +146 -1
  159. package/src/zod/index.ts +105 -9
  160. package/src/zod/introspect.ts +103 -0
  161. package/src/zod/jsonToZodSchemaMapper.ts +44 -21
  162. package/src/zod/zodMinMaxFilter.ts +37 -13
  163. package/src/zod/zodToTypeString.ts +184 -181
  164. package/dist/api-wrapper/index.js +0 -250
  165. package/dist/gzip/index.d.ts +0 -2
  166. package/dist/gzip/index.js +0 -16
  167. package/dist/index.js +0 -1823
  168. package/dist/jwt/index.js +0 -19
  169. package/dist/sitemap/index.js +0 -552
  170. package/dist/src/gzip/index.js +0 -16
  171. package/dist/src/secrets/infisical.js +0 -1194
  172. package/dist/zod/index.js +0 -210
package/dist/src/index.js CHANGED
@@ -1,2332 +1,91 @@
1
- // src/zod/index.ts
2
- import { z as z3 } from "zod";
3
-
4
- // src/zod/jsonToZodSchemaMapper.ts
5
- import { z } from "zod";
6
- function jsonToZodSchemaMapper(jsonObject, zodSchema, config) {
7
- const result = {};
8
- const shape = zodSchema instanceof z.ZodObject ? zodSchema.shape : {};
9
- for (const key of Object.keys(shape)) {
10
- const fieldConfig = config[key];
11
- let value = jsonObject[key];
12
- if (fieldConfig) {
13
- value = fieldConfig(jsonObject);
14
- }
15
- if (shape[key] instanceof z.ZodObject && value && typeof value === "object") {
16
- result[key] = jsonToZodSchemaMapper(value, shape[key], config[key] || {});
17
- } else {
18
- result[key] = value;
19
- }
20
- }
21
- return zodSchema.parse(result);
22
- }
23
- // src/zod/zodMinMaxFilter.ts
24
- import { z as z2 } from "zod";
25
- var zodMinMaxFilter = z2.object({
26
- min: z2.number().optional(),
27
- max: z2.number().optional()
28
- });
29
- function toGteLteFilter(filter) {
30
- if (!filter)
31
- return;
32
- const hasMin = filter.min !== undefined;
33
- const hasMax = filter.max !== undefined;
34
- if (!hasMin && !hasMax)
35
- return;
36
- return {
37
- ...hasMin && { gte: filter.min },
38
- ...hasMax && { lte: filter.max }
39
- };
40
- }
41
- // src/zod/zodToTypeString.ts
42
- function getDefProp(def, prop) {
43
- return def?.[prop];
44
- }
45
- function zodToTypeString(schema, indent = 0) {
46
- const pad = " ".repeat(indent);
47
- const innerPad = " ".repeat(indent + 1);
48
- const def = schema._zod?.def ?? schema._def;
49
- if (!def)
50
- return "unknown";
51
- const schemaType = getDefProp(def, "type") ?? getDefProp(def, "typeName");
52
- switch (schemaType) {
53
- case "object": {
54
- const shape = getDefProp(def, "shape");
55
- if (!shape || Object.keys(shape).length === 0)
56
- return "{}";
57
- const fields = Object.entries(shape).map(([key, value]) => {
58
- const valueType = getDefProp(value._zod?.def ?? value._def, "type");
59
- const isOptional = valueType === "optional";
60
- const innerSchema = isOptional ? getDefProp(value._zod?.def ?? value._def, "innerType") ?? value : value;
61
- const typeStr = zodToTypeString(innerSchema, indent + 1);
62
- return `${innerPad}${key}${isOptional ? "?" : ""}: ${typeStr}`;
63
- });
64
- return `{
65
- ${fields.join(`
66
- `)}
67
- ${pad}}`;
68
- }
69
- case "array": {
70
- const itemType = getDefProp(def, "element") ?? getDefProp(def, "type");
71
- return itemType ? `${zodToTypeString(itemType, indent)}[]` : "unknown[]";
72
- }
73
- case "string":
74
- return "string";
75
- case "number":
76
- return "number";
77
- case "boolean":
78
- return "boolean";
79
- case "date":
80
- return "Date";
81
- case "null":
82
- return "null";
83
- case "undefined":
84
- return "undefined";
85
- case "any":
86
- return "any";
87
- case "unknown":
88
- return "unknown";
89
- case "record": {
90
- const valueType = getDefProp(def, "valueType");
91
- return valueType ? `Record<string, ${zodToTypeString(valueType, indent)}>` : "Record<string, unknown>";
92
- }
93
- case "enum": {
94
- const values = getDefProp(def, "values");
95
- return values ? values.map((v) => `"${v}"`).join(" | ") : "string";
96
- }
97
- case "literal": {
98
- const value = getDefProp(def, "value");
99
- return typeof value === "string" ? `"${value}"` : String(value);
100
- }
101
- case "union": {
102
- const options = getDefProp(def, "options");
103
- return options ? options.map((o) => zodToTypeString(o, indent)).join(" | ") : "unknown";
104
- }
105
- case "optional": {
106
- const inner = getDefProp(def, "innerType");
107
- return inner ? `${zodToTypeString(inner, indent)} | undefined` : "unknown";
108
- }
109
- case "nullable": {
110
- const inner = getDefProp(def, "innerType");
111
- return inner ? `${zodToTypeString(inner, indent)} | null` : "unknown";
112
- }
113
- case "default": {
114
- const inner = getDefProp(def, "innerType");
115
- return inner ? zodToTypeString(inner, indent) : "unknown";
116
- }
117
- case "ZodObject":
118
- case "ZodArray":
119
- case "ZodString":
120
- case "ZodNumber":
121
- case "ZodBoolean":
122
- case "ZodDate":
123
- case "ZodNull":
124
- case "ZodUndefined":
125
- case "ZodAny":
126
- case "ZodUnknown":
127
- case "ZodRecord":
128
- case "ZodEnum":
129
- case "ZodLiteral":
130
- case "ZodUnion":
131
- case "ZodOptional":
132
- case "ZodNullable":
133
- case "ZodDefault":
134
- return zodToTypeString(schema, indent);
135
- default:
136
- return "unknown";
137
- }
138
- }
139
- function zodToExample(schema) {
140
- const def = schema._zod?.def ?? schema._def;
141
- if (!def)
142
- return null;
143
- const schemaType = getDefProp(def, "type") ?? getDefProp(def, "typeName");
144
- switch (schemaType) {
145
- case "object": {
146
- const shape = getDefProp(def, "shape");
147
- if (!shape)
148
- return {};
149
- const result = {};
150
- for (const [key, value] of Object.entries(shape)) {
151
- const valueType = getDefProp(value._zod?.def ?? value._def, "type");
152
- const isOptional = valueType === "optional";
153
- if (!isOptional) {
154
- result[key] = zodToExample(value);
155
- }
156
- }
157
- return result;
158
- }
159
- case "array": {
160
- const itemType = getDefProp(def, "element") ?? getDefProp(def, "type");
161
- return itemType ? [zodToExample(itemType)] : [];
162
- }
163
- case "string":
164
- return "";
165
- case "number":
166
- return 0;
167
- case "boolean":
168
- return false;
169
- case "enum": {
170
- const values = getDefProp(def, "values");
171
- return values?.[0] ?? "";
172
- }
173
- case "literal":
174
- return getDefProp(def, "value");
175
- case "optional":
176
- case "default": {
177
- const inner = getDefProp(def, "innerType");
178
- return inner ? zodToExample(inner) : null;
179
- }
180
- case "record":
181
- return {};
182
- default:
183
- return null;
184
- }
185
- }
186
-
187
- // src/zod/index.ts
188
- function createZId(typeName) {
189
- return z3.string().min(1, `${typeName} ID is required`).brand();
190
- }
191
- function zSingleOrArray(schema) {
192
- return z3.union([z3.array(schema), schema]);
193
- }
194
- function normalizeSingleOrArray(value) {
195
- if (value == null)
196
- return [];
197
- if (Array.isArray(value))
198
- return [...value];
199
- return [value];
200
- }
201
- // src/api-wrapper/headers.ts
202
- var CANONICAL_HEADER_NAMES = {
203
- "content-type": "Content-Type",
204
- authorization: "Authorization",
205
- accept: "Accept",
206
- "user-agent": "User-Agent",
207
- "x-request-id": "X-Request-Id",
208
- "x-correlation-id": "X-Correlation-Id"
209
- };
210
- function normalizeHeaders(headers) {
211
- const result = {};
212
- const lowerToCanonical = new Map;
213
- for (const [key, value] of Object.entries(headers)) {
214
- const lower = key.toLowerCase();
215
- const canonical = CANONICAL_HEADER_NAMES[lower] ?? key;
216
- const existing = lowerToCanonical.get(lower);
217
- if (existing && existing !== canonical)
218
- delete result[existing];
219
- lowerToCanonical.set(lower, canonical);
220
- result[canonical] = value;
221
- }
222
- return result;
223
- }
224
- function getHeader(headers, name) {
225
- const lower = name.toLowerCase();
226
- const canonical = CANONICAL_HEADER_NAMES[lower];
227
- if (canonical !== undefined) {
228
- if (headers[canonical] !== undefined)
229
- return headers[canonical];
230
- }
231
- for (const [k, v] of Object.entries(headers)) {
232
- if (k.toLowerCase() === lower)
233
- return v;
234
- }
235
- return;
236
- }
237
- function hasJsonContentType(headers) {
238
- const ct = getHeader(headers, "content-type") ?? "";
239
- return ct.includes("application/json");
240
- }
241
- function buildFetchBody(body, headers) {
242
- if (body === undefined || body === null)
243
- return;
244
- if (body instanceof FormData || body instanceof Blob)
245
- return body;
246
- if (hasJsonContentType(headers))
247
- return JSON.stringify(body);
248
- return body;
249
- }
250
- function getHeadersAsObject(headers) {
251
- const result = {};
252
- headers.forEach((value, key) => {
253
- result[key] = value;
254
- });
255
- return result;
256
- }
257
-
258
- // src/api-wrapper/zod-issues.ts
259
- import { ZodError } from "zod";
260
- function formatZodIssues(error, rawData) {
261
- return error.issues.map((issue) => {
262
- const pathArray = [...issue.path];
263
- const path = formatIssuePath(pathArray);
264
- const value = getValueAtPath(rawData, pathArray);
265
- const valuePreview = value === undefined ? undefined : previewValue(value);
266
- const raw = issue;
267
- const expected = typeof raw.expected === "string" ? raw.expected : undefined;
268
- const received = typeof raw.received === "string" ? raw.received : value !== undefined ? typeofVerbose(value) : undefined;
269
- const known = new Set([
270
- "code",
271
- "path",
272
- "message",
273
- "expected",
274
- "received",
275
- "fatal"
276
- ]);
277
- const extra = {};
278
- for (const [k, v] of Object.entries(raw)) {
279
- if (!known.has(k) && v !== undefined)
280
- extra[k] = v;
281
- }
282
- return {
283
- path,
284
- pathArray,
285
- code: issue.code,
286
- message: issue.message,
287
- expected,
288
- received,
289
- value,
290
- valuePreview,
291
- extra: Object.keys(extra).length > 0 ? extra : undefined
292
- };
293
- });
294
- }
295
- function renderIssueSummary(issues) {
296
- if (issues.length === 0)
297
- return "(no issues reported)";
298
- return issues.map((issue, idx) => {
299
- const parts = [];
300
- parts.push(` [${idx + 1}] ${issue.path}: ${issue.message}`);
301
- if (issue.expected || issue.received) {
302
- const exp = issue.expected ? `expected ${issue.expected}` : "";
303
- const rec = issue.received ? `received ${issue.received}` : "";
304
- parts.push(` (${[exp, rec].filter(Boolean).join(", ")})`);
305
- }
306
- if (issue.valuePreview !== undefined) {
307
- parts.push(` value: ${issue.valuePreview}`);
308
- }
309
- if (issue.extra) {
310
- for (const [k, v] of Object.entries(issue.extra)) {
311
- parts.push(` ${k}: ${previewValue(v, 120)}`);
312
- }
313
- }
314
- return parts.join(`
315
- `);
316
- }).join(`
317
- `);
318
- }
319
- function formatIssuePath(pathArray) {
320
- if (pathArray.length === 0)
321
- return "<root>";
322
- let out = "";
323
- for (const segment of pathArray) {
324
- if (typeof segment === "number") {
325
- out += `[${segment}]`;
326
- } else if (/^[A-Za-z_$][\w$]*$/.test(segment)) {
327
- out += out === "" ? segment : `.${segment}`;
328
- } else {
329
- out += `[${JSON.stringify(segment)}]`;
330
- }
331
- }
332
- return out;
333
- }
334
- function getValueAtPath(data, pathArray) {
335
- let current = data;
336
- for (const segment of pathArray) {
337
- if (current === null || current === undefined)
338
- return;
339
- if (typeof current !== "object")
340
- return;
341
- current = current[segment];
342
- }
343
- return current;
344
- }
345
- function typeofVerbose(value) {
346
- if (value === null)
347
- return "null";
348
- if (Array.isArray(value))
349
- return "array";
350
- return typeof value;
351
- }
352
- function previewValue(value, maxLen = 200) {
353
- let str;
354
- try {
355
- if (value === undefined)
356
- str = "undefined";
357
- else if (typeof value === "string")
358
- str = JSON.stringify(value);
359
- else
360
- str = JSON.stringify(value);
361
- } catch {
362
- str = String(value);
363
- }
364
- if (str === undefined)
365
- str = String(value);
366
- if (str.length > maxLen)
367
- str = `${str.slice(0, maxLen)}…`;
368
- return str;
369
- }
370
- function makeJsonParseZodError(error, text) {
371
- const message = error instanceof Error ? `Response body was not valid JSON: ${error.message}` : "Response body was not valid JSON";
372
- const preview = text.length > 200 ? `${text.slice(0, 200)}…` : text;
373
- return new ZodError([
374
- {
375
- code: "custom",
376
- path: [],
377
- message: `${message} (body preview: ${JSON.stringify(preview)})`,
378
- input: text
379
- }
380
- ]);
381
- }
382
- function tryParseJson(body) {
383
- if (!body)
384
- return;
385
- try {
386
- return JSON.parse(body);
387
- } catch {
388
- return;
389
- }
390
- }
391
-
392
- // src/api-wrapper/errors.ts
393
- var MAX_BODY_PREVIEW = 500;
394
-
395
- class ApiError extends Error {
396
- context;
397
- cause;
398
- constructor(message, context, options) {
399
- super(message);
400
- this.name = "ApiError";
401
- this.context = context;
402
- this.cause = options?.cause;
403
- }
404
- toJSON() {
405
- return {
406
- name: this.name,
407
- message: this.message,
408
- context: this.context
409
- };
410
- }
411
- }
412
-
413
- class HttpResponseError extends ApiError {
414
- status;
415
- body;
416
- bodyJson;
417
- responseHeaders;
418
- requestId;
419
- constructor(status, body, responseHeaders, context) {
420
- const preview = body.length > MAX_BODY_PREVIEW ? `${body.slice(0, MAX_BODY_PREVIEW)}…` : body;
421
- super(`HTTP ${status} ${context.method} ${context.url} - ${preview}`, context);
422
- this.name = "HttpResponseError";
423
- this.status = status;
424
- this.body = body;
425
- this.responseHeaders = responseHeaders;
426
- this.requestId = getHeader(responseHeaders, "x-request-id") ?? getHeader(responseHeaders, "x-correlation-id");
427
- this.bodyJson = tryParseJson(body);
428
- }
429
- toJSON() {
430
- return {
431
- ...super.toJSON(),
432
- status: this.status,
433
- body: this.body,
434
- bodyJson: this.bodyJson,
435
- requestId: this.requestId,
436
- responseHeaders: this.responseHeaders
437
- };
438
- }
439
- }
440
-
441
- class ResponseValidationError extends ApiError {
442
- zodError;
443
- rawResponse;
444
- issues;
445
- validationIssues;
446
- constructor(zodError, rawResponse, context) {
447
- const issues = formatZodIssues(zodError, rawResponse);
448
- const summary = renderIssueSummary(issues);
449
- super(`Response validation failed (${context.method} ${context.url}):
450
- ${summary}`, context, { cause: zodError });
451
- this.name = "ResponseValidationError";
452
- this.zodError = zodError;
453
- this.rawResponse = rawResponse;
454
- this.issues = issues;
455
- this.validationIssues = issues.map((i) => `${i.path}: ${i.message}`).join("; ");
456
- }
457
- toJSON() {
458
- return {
459
- ...super.toJSON(),
460
- issues: this.issues,
461
- validationIssues: this.validationIssues,
462
- rawResponsePreview: previewValue(this.rawResponse, 1000)
463
- };
464
- }
465
- }
466
-
467
- class RequestValidationError extends ApiError {
468
- zodError;
469
- target;
470
- rawInput;
471
- issues;
472
- validationIssues;
473
- constructor(zodError, target, rawInput, context) {
474
- const issues = formatZodIssues(zodError, rawInput);
475
- const summary = renderIssueSummary(issues);
476
- super(`Request ${target} validation failed (${context.method} ${context.url}):
477
- ${summary}`, context, { cause: zodError });
478
- this.name = "RequestValidationError";
479
- this.zodError = zodError;
480
- this.target = target;
481
- this.rawInput = rawInput;
482
- this.issues = issues;
483
- this.validationIssues = issues.map((i) => `${i.path}: ${i.message}`).join("; ");
484
- }
485
- toJSON() {
486
- return {
487
- ...super.toJSON(),
488
- target: this.target,
489
- issues: this.issues,
490
- validationIssues: this.validationIssues
491
- };
492
- }
493
- }
494
-
495
- class RequestTimeoutError extends ApiError {
496
- timeoutMs;
497
- constructor(timeoutMs, context) {
498
- super(`Request timed out after ${timeoutMs}ms: ${context.method} ${context.url}`, context);
499
- this.name = "RequestTimeoutError";
500
- this.timeoutMs = timeoutMs;
501
- }
502
- }
503
-
504
- class NetworkError extends ApiError {
505
- constructor(message, context, cause) {
506
- super(message, context, { cause });
507
- this.name = "NetworkError";
508
- }
509
- }
510
-
511
- class RequestAbortedError extends ApiError {
512
- constructor(context, cause) {
513
- super(`Request aborted: ${context.method} ${context.url}`, context, {
514
- cause
515
- });
516
- this.name = "RequestAbortedError";
517
- }
518
- }
519
-
520
- class ConfigError extends ApiError {
521
- constructor(message, context) {
522
- super(message, context);
523
- this.name = "ConfigError";
524
- }
525
- }
526
-
527
- class ActionError extends ApiError {
528
- constructor(message, context, cause) {
529
- super(message, context, { cause });
530
- this.name = "ActionError";
531
- }
532
- }
533
- var isApiError = (e) => e instanceof ApiError;
534
- var isHttpResponseError = (e) => e instanceof HttpResponseError;
535
- var isResponseValidationError = (e) => e instanceof ResponseValidationError;
536
- var isRequestValidationError = (e) => e instanceof RequestValidationError;
537
- var isRequestTimeoutError = (e) => e instanceof RequestTimeoutError;
538
- var isNetworkError = (e) => e instanceof NetworkError;
539
- var isRequestAbortedError = (e) => e instanceof RequestAbortedError;
540
- var isConfigError = (e) => e instanceof ConfigError;
541
- var isActionError = (e) => e instanceof ActionError;
542
- // src/api-wrapper/builders.ts
543
- import { ZodError as ZodError2 } from "zod";
544
- function buildUrl(endpoint, params, reqQuery, baseApiUrls, defaultBaseApiUrl, url, configError) {
545
- if (url) {
546
- const finalUrl2 = replacePathParams(url, params, configError);
547
- const queryString2 = new URLSearchParams(buildQueryParamsRaw(endpoint, reqQuery)).toString();
548
- return {
549
- finalUrl: finalUrl2,
550
- fullUrl: queryString2 ? `${finalUrl2}?${queryString2}` : finalUrl2
551
- };
552
- }
553
- const defaultBaseUrl = defaultBaseApiUrl ?? Object.keys(baseApiUrls)[0];
554
- if (!defaultBaseUrl) {
555
- throw configError("At least one base API URL is required");
556
- }
557
- const baseUrlKey = endpoint.baseApiUrl ?? defaultBaseUrl;
558
- const configBaseUrl = baseApiUrls[baseUrlKey];
559
- if (!configBaseUrl) {
560
- throw configError(`Unknown base API URL: ${baseUrlKey}`);
561
- }
562
- const baseUrl = typeof configBaseUrl === "function" ? configBaseUrl() : configBaseUrl;
563
- const path = typeof endpoint.path === "function" ? endpoint.path(baseUrl) : endpoint.path;
564
- const finalUrl = replacePathParams(`${baseUrl}${path}`, params, configError);
565
- const queryString = new URLSearchParams(buildQueryParamsRaw(endpoint, reqQuery)).toString();
566
- return {
567
- finalUrl,
568
- fullUrl: queryString ? `${finalUrl}?${queryString}` : finalUrl
569
- };
570
- }
571
- function buildQueryParamsRaw(endpoint, query) {
572
- const defaultParams = endpoint.reqDefaultQueryParams ?? {};
573
- const merged = { ...defaultParams, ...query ?? {} };
574
- return Object.fromEntries(Object.entries(merged).filter(([, value]) => value !== undefined).map(([key, value]) => [key, String(value)]));
575
- }
576
- function buildQueryParams(endpoint, query, ctx) {
577
- const defaultParams = endpoint.reqDefaultQueryParams ?? {};
578
- let parsedQuery;
579
- if (endpoint.reqQuerySchema) {
580
- try {
581
- parsedQuery = endpoint.reqQuerySchema.parse(query);
582
- } catch (error) {
583
- if (error instanceof ZodError2) {
584
- throw new RequestValidationError(error, "query", query, ctx());
585
- }
586
- throw error;
587
- }
588
- } else {
589
- parsedQuery = query ?? {};
590
- }
591
- const merged = { ...defaultParams, ...parsedQuery };
592
- return Object.fromEntries(Object.entries(merged).filter(([, value]) => value !== undefined).map(([key, value]) => [key, String(value)]));
593
- }
594
- function buildRequestBody(endpoint, body, ctx) {
595
- if (!endpoint.reqBodySchema)
596
- return body;
597
- let parsedBody;
598
- try {
599
- parsedBody = endpoint.reqBodySchema.parse(body);
600
- } catch (error) {
601
- if (error instanceof ZodError2) {
602
- throw new RequestValidationError(error, "body", body, ctx());
603
- }
604
- throw error;
605
- }
606
- if (endpoint.reqBodyFormat !== "form-data") {
607
- return parsedBody;
608
- }
609
- const formData = new FormData;
610
- for (const [key, value] of Object.entries(parsedBody)) {
611
- if (value == null)
612
- continue;
613
- formData.set(key, value instanceof Blob ? value : String(value));
614
- }
615
- return formData;
616
- }
617
- function buildHeaders(endpoint, headers, defaultHeaders, ctx) {
618
- const contentType = endpoint.reqBodyFormat === "json" ? "application/json" : undefined;
619
- let parsedHeaders;
620
- if (endpoint.reqHeadersSchema) {
621
- try {
622
- parsedHeaders = endpoint.reqHeadersSchema.parse(headers);
623
- } catch (error) {
624
- if (error instanceof ZodError2) {
625
- throw new RequestValidationError(error, "headers", headers, ctx());
626
- }
627
- throw error;
628
- }
629
- } else {
630
- parsedHeaders = headers ?? {};
631
- }
632
- return normalizeHeaders({
633
- ...defaultHeaders,
634
- ...contentType && { "Content-Type": contentType },
635
- ...endpoint.defaultHeaders,
636
- ...parsedHeaders
637
- });
638
- }
639
- function replacePathParams(path, params, configError) {
640
- return path.replace(/:(\w+)/g, (_, key) => {
641
- const value = params?.[key];
642
- if (value === undefined) {
643
- throw configError(`Missing required path parameter: ${key}`);
644
- }
645
- return encodeURIComponent(String(value));
646
- });
647
- }
648
-
649
- // src/api-wrapper/actions-impl.ts
650
- function createActionCache() {
651
- const store = new Map;
652
- const isExpired = (entry) => entry.expiresAt !== undefined && entry.expiresAt <= Date.now();
653
- const cache = async (key, fn, options) => {
654
- const existing = store.get(key);
655
- if (existing && !isExpired(existing)) {
656
- if (existing.inflight)
657
- return existing.inflight;
658
- if (existing.hasValue)
659
- return existing.value;
660
- }
661
- const promise = (async () => fn())();
662
- const entry = {
663
- hasValue: false,
664
- inflight: promise,
665
- expiresAt: options?.ttlMs !== undefined ? Date.now() + options.ttlMs : undefined
666
- };
667
- store.set(key, entry);
668
- try {
669
- const value = await promise;
670
- entry.value = value;
671
- entry.hasValue = true;
672
- entry.inflight = undefined;
673
- return value;
674
- } catch (error) {
675
- store.delete(key);
676
- throw error;
677
- }
678
- };
679
- cache.get = (key) => {
680
- const entry = store.get(key);
681
- if (!entry || !entry.hasValue)
682
- return;
683
- if (isExpired(entry)) {
684
- store.delete(key);
685
- return;
686
- }
687
- return entry.value;
688
- };
689
- cache.set = (key, value, options) => {
690
- store.set(key, {
691
- value,
692
- hasValue: true,
693
- expiresAt: options?.ttlMs !== undefined ? Date.now() + options.ttlMs : undefined
694
- });
695
- };
696
- cache.invalidate = (key) => {
697
- store.delete(key);
698
- };
699
- cache.clear = () => {
700
- store.clear();
701
- };
702
- return cache;
703
- }
704
- function makeDefineAction() {
705
- function defineAction(...args) {
706
- if (args.length === 0) {
707
- return (def2) => ({
708
- ...def2,
709
- noRuntimeInput: false
710
- });
711
- }
712
- const def = args[0];
713
- return {
714
- ...def,
715
- noRuntimeInput: true
716
- };
717
- }
718
- return defineAction;
719
- }
720
- var defineAction = makeDefineAction();
721
-
722
- // src/api-wrapper/redaction.ts
723
- var SENSITIVE_HEADER_KEYS = new Set([
724
- "authorization",
725
- "cookie",
726
- "set-cookie",
727
- "x-api-key",
728
- "x-auth-token"
729
- ]);
730
- var SENSITIVE_BODY_KEYS = new Set([
731
- "password",
732
- "token",
733
- "accesstoken",
734
- "access_token",
735
- "refreshtoken",
736
- "refresh_token",
737
- "secret",
738
- "client_secret",
739
- "apikey",
740
- "api_key"
741
- ]);
742
- function redactHeaders(headers) {
743
- if (!headers)
744
- return;
745
- const out = {};
746
- for (const [k, v] of Object.entries(headers)) {
747
- if (SENSITIVE_HEADER_KEYS.has(k.toLowerCase())) {
748
- out[k] = "[REDACTED]";
749
- } else {
750
- out[k] = v;
751
- }
752
- }
753
- return out;
754
- }
755
- function redactBody(body) {
756
- if (body === null || body === undefined)
757
- return body;
758
- if (typeof body !== "object" || Array.isArray(body)) {
759
- return body;
760
- }
761
- const rec = body;
762
- const out = { ...rec };
763
- for (const key of Object.keys(out)) {
764
- if (SENSITIVE_BODY_KEYS.has(key.toLowerCase())) {
765
- out[key] = "[REDACTED]";
766
- }
767
- }
768
- return out;
769
- }
770
- function defaultRedactContext(ctx) {
771
- return {
772
- ...ctx,
773
- requestHeaders: redactHeaders(ctx.requestHeaders),
774
- requestBody: redactBody(ctx.requestBody),
775
- meta: ctx.meta
776
- };
777
- }
778
-
779
- // src/api-wrapper/error-reporting.ts
780
- function applyErrorContextRedaction(ctx, config) {
781
- const base = defaultRedactContext(ctx);
782
- return config.redact ? config.redact(base) : base;
783
- }
784
- async function reportApiError(err, config) {
785
- err.context = applyErrorContextRedaction(err.context, config);
786
- try {
787
- await config.onError?.(err);
788
- } catch {}
789
- config.logger?.error?.(err);
790
- return err;
791
- }
792
-
793
- // src/api-wrapper/size.ts
794
- function calculateSizeInMb(data) {
795
- let bytes;
796
- if (data === undefined || data === null) {
797
- bytes = 0;
798
- } else if (data instanceof Blob) {
799
- bytes = data.size;
800
- } else if (typeof FormData !== "undefined" && data instanceof FormData) {
801
- bytes = 0;
802
- data.forEach((value) => {
803
- if (value instanceof Blob)
804
- bytes += value.size;
805
- else
806
- bytes += new TextEncoder().encode(String(value)).length;
807
- });
808
- } else if (typeof data === "string") {
809
- bytes = new TextEncoder().encode(data).length;
810
- } else {
811
- bytes = new TextEncoder().encode(JSON.stringify(data) ?? "").length;
812
- }
813
- return bytes / (1024 * 1024);
814
- }
815
-
816
- // src/api-wrapper/transport.ts
817
- import { ZodError as ZodError3 } from "zod";
818
- async function validateResponse(schema, data, ctx) {
819
- try {
820
- return await schema.parseAsync(data);
821
- } catch (error) {
822
- if (error instanceof ZodError3) {
823
- throw new ResponseValidationError(error, data, ctx());
824
- }
825
- throw error;
826
- }
827
- }
828
- async function httpRequest(config, ctx) {
829
- const queryString = config.doNotEncodeQueryParams ? Object.entries(config.queryParams).map(([key, value]) => `${key}=${value}`).join("&") : new URLSearchParams(config.queryParams).toString();
830
- const fullUrl = queryString ? `${config.url}?${queryString}` : config.url;
831
- const timeoutController = new AbortController;
832
- const timeout = config.timeoutMs === undefined ? undefined : setTimeout(() => timeoutController.abort(), config.timeoutMs);
833
- const signal = mergeSignals(timeoutController.signal, config.userSignal);
834
- try {
835
- return await config.fetchFn(fullUrl, {
836
- method: config.method,
837
- headers: config.headers,
838
- body: buildFetchBody(config.body, config.headers),
839
- signal
840
- });
841
- } catch (error) {
842
- if (isDomAbortError(error)) {
843
- if (config.userSignal?.aborted) {
844
- throw new RequestAbortedError(ctx(), error);
845
- }
846
- if (timeoutController.signal.aborted && config.timeoutMs !== undefined) {
847
- throw new RequestTimeoutError(config.timeoutMs, ctx());
848
- }
849
- throw new RequestAbortedError(ctx(), error);
850
- }
851
- throw new NetworkError(error instanceof Error ? error.message : String(error), ctx(), error);
852
- } finally {
853
- if (timeout)
854
- clearTimeout(timeout);
855
- }
856
- }
857
- function isDomAbortError(error) {
858
- return typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
859
- }
860
- function mergeSignals(a, b) {
861
- if (!b)
862
- return a;
863
- const anyFn = AbortSignal.any;
864
- if (typeof anyFn === "function")
865
- return anyFn([a, b]);
866
- const controller = new AbortController;
867
- const onAbort = () => controller.abort();
868
- if (a.aborted)
869
- controller.abort();
870
- else
871
- a.addEventListener("abort", onAbort, { once: true });
872
- if (b.aborted)
873
- controller.abort();
874
- else
875
- b.addEventListener("abort", onAbort, { once: true });
876
- return controller.signal;
877
- }
878
- async function readErrorResponse(response) {
879
- const body = await response.text();
880
- return {
881
- body,
882
- headers: getHeadersAsObject(response.headers),
883
- status: response.status
884
- };
885
- }
886
- function getRetryDelay(params) {
887
- const { retryDelay, attempt, response } = params;
888
- if (response && (response.status === 429 || response.status === 503)) {
889
- const retryAfter = response.headers.get("retry-after");
890
- if (retryAfter) {
891
- const seconds = Number(retryAfter);
892
- if (Number.isFinite(seconds))
893
- return seconds * 1000;
894
- const dateMs = Date.parse(retryAfter);
895
- if (!Number.isNaN(dateMs)) {
896
- return Math.max(0, dateMs - Date.now());
897
- }
898
- }
899
- }
900
- if (typeof retryDelay === "function")
901
- return retryDelay(attempt);
902
- return retryDelay;
903
- }
904
- function shouldAttemptRetryOnError(error) {
905
- if (error instanceof HttpResponseError)
906
- return false;
907
- if (error instanceof ResponseValidationError)
908
- return false;
909
- if (error instanceof RequestValidationError)
910
- return false;
911
- if (error instanceof ConfigError)
912
- return false;
913
- if (error instanceof RequestAbortedError)
914
- return false;
915
- return true;
916
- }
917
- function shouldAttemptRetryOnHttp(retryCtx) {
918
- const { error, response } = retryCtx;
919
- if (error)
920
- return shouldAttemptRetryOnError(error);
921
- return response ? response.status >= 500 || response.status === 429 : false;
922
- }
923
- async function makeRequestWithRetry(args) {
924
- const {
925
- config,
926
- maxRetries,
927
- retryDelay,
928
- validateFn,
929
- shouldRetry,
930
- logger,
931
- ctx,
932
- endpointName,
933
- method,
934
- fullUrl,
935
- meta,
936
- onResponse,
937
- onRetry
938
- } = args;
939
- let retryCount = 0;
940
- while (true) {
941
- let response;
942
- try {
943
- logger?.debug?.("API request", config);
944
- response = await httpRequest(config, (over) => ctx({ attempt: retryCount, ...over }));
945
- await onResponse?.({
946
- endpoint: endpointName,
947
- method,
948
- url: fullUrl,
949
- response: response.clone(),
950
- attempt: retryCount,
951
- meta
952
- });
953
- if (response.status >= 400) {
954
- const retryCtx = {
955
- response,
956
- retryCount,
957
- maxRetries,
958
- endpoint: endpointName,
959
- method,
960
- url: fullUrl
961
- };
962
- if (retryCount < maxRetries && shouldRetry(retryCtx)) {
963
- const delayMs = getRetryDelay({
964
- retryDelay,
965
- attempt: retryCount,
966
- response
967
- });
968
- await onRetry?.({
969
- ...retryCtx,
970
- delayMs,
971
- nextAttempt: retryCount + 1
972
- });
973
- retryCount++;
974
- await delay(delayMs);
975
- continue;
976
- }
977
- const { body, headers: responseHeaders } = await readErrorResponse(response);
978
- throw new HttpResponseError(response.status, body, responseHeaders, ctx({ attempt: retryCount }));
979
- }
980
- return {
981
- validatedData: await validateFn(response),
982
- retryCount,
983
- httpStatus: response.status
984
- };
985
- } catch (error) {
986
- if (error instanceof HttpResponseError || error instanceof ResponseValidationError || error instanceof RequestValidationError || error instanceof ConfigError || error instanceof RequestAbortedError) {
987
- throw error;
988
- }
989
- const retryCtx = {
990
- error,
991
- retryCount,
992
- maxRetries,
993
- endpoint: endpointName,
994
- method,
995
- url: fullUrl
996
- };
997
- if (retryCount >= maxRetries || !shouldRetry(retryCtx)) {
998
- throw error;
999
- }
1000
- const delayMs = getRetryDelay({
1001
- retryDelay,
1002
- attempt: retryCount,
1003
- response: undefined
1004
- });
1005
- await onRetry?.({
1006
- ...retryCtx,
1007
- delayMs,
1008
- nextAttempt: retryCount + 1
1009
- });
1010
- retryCount++;
1011
- await delay(delayMs);
1012
- }
1013
- }
1014
- }
1015
- async function validateAndTransformResponse(endpoint, response, ctx) {
1016
- const responseHeaders = getHeadersAsObject(response.headers);
1017
- let responseData;
1018
- if (hasJsonContentType(responseHeaders)) {
1019
- const text = await response.text();
1020
- try {
1021
- responseData = text === "" ? undefined : JSON.parse(text);
1022
- } catch (error) {
1023
- throw new ResponseValidationError(makeJsonParseZodError(error, text), text, ctx());
1024
- }
1025
- } else {
1026
- responseData = await response.text();
1027
- }
1028
- const transformedData = endpoint.resFormatter ? endpoint.resFormatter(responseData, responseHeaders) : responseData;
1029
- return validateResponse(endpoint.resSchema, transformedData, ctx);
1030
- }
1031
- function defaultShouldRetry(ctx) {
1032
- if (ctx.error)
1033
- return shouldAttemptRetryOnError(ctx.error);
1034
- return shouldAttemptRetryOnHttp(ctx);
1035
- }
1036
- function delay(ms) {
1037
- return new Promise((resolve) => setTimeout(resolve, ms));
1038
- }
1039
-
1040
- // src/api-wrapper/create-client.ts
1041
- function isActionInvokeOptionsOnly(value) {
1042
- if (value === null || value === undefined)
1043
- return false;
1044
- if (typeof value !== "object" || Array.isArray(value))
1045
- return false;
1046
- return Object.keys(value).every((k) => k === "signal" || k === "meta");
1047
- }
1048
- function createApiClientImpl(apiConfig) {
1049
- let actions = {};
1050
- const cache = createActionCache();
1051
- const invokeEndpoint = async (endpointKey, input = {}) => {
1052
- const endpoint = apiConfig.endpoints[endpointKey];
1053
- const rawInput = input;
1054
- const endpointName = apiConfig.name ? `${apiConfig.name}.${String(endpointKey)}` : String(endpointKey);
1055
- const startedAt = Date.now();
1056
- const maxRetries = input.retries ?? apiConfig.retries ?? 3;
1057
- const baseContext = {
1058
- endpoint: endpointName,
1059
- method: endpoint?.method ?? "GET",
1060
- url: "",
1061
- attempt: 0,
1062
- maxRetries,
1063
- elapsedMs: 0,
1064
- meta: input.meta
1065
- };
1066
- const elapsed = () => Date.now() - startedAt;
1067
- const ctx = (over = {}) => ({
1068
- ...baseContext,
1069
- elapsedMs: elapsed(),
1070
- ...over
1071
- });
1072
- if (!endpoint) {
1073
- throw await reportApiError(new ConfigError(`Unknown API endpoint: ${String(endpointKey)}`, ctx()), apiConfig);
1074
- }
1075
- baseContext.method = endpoint.method;
1076
- let finalUrl;
1077
- let fullUrl;
1078
- try {
1079
- const built = buildUrl(endpoint, rawInput.reqParams, rawInput.reqQuery, apiConfig.baseApiUrls, apiConfig.defaultBaseApiUrl, input.url, (msg) => new ConfigError(msg, ctx()));
1080
- finalUrl = built.finalUrl;
1081
- fullUrl = built.fullUrl;
1082
- } catch (e) {
1083
- if (e instanceof ApiError)
1084
- throw await reportApiError(e, apiConfig);
1085
- throw e;
1086
- }
1087
- baseContext.url = fullUrl;
1088
- let queryParams;
1089
- let body;
1090
- let headers;
1091
- try {
1092
- queryParams = buildQueryParams(endpoint, rawInput.reqQuery, ctx);
1093
- body = buildRequestBody(endpoint, rawInput.reqBody, ctx);
1094
- headers = buildHeaders(endpoint, rawInput.reqHeaders, apiConfig.defaultHeaders ?? {}, ctx);
1095
- } catch (e) {
1096
- if (e instanceof ApiError)
1097
- throw await reportApiError(e, apiConfig);
1098
- throw e;
1099
- }
1100
- baseContext.requestHeaders = headers;
1101
- baseContext.requestBody = body;
1102
- if (apiConfig.onRequest) {
1103
- try {
1104
- const result = await apiConfig.onRequest({
1105
- endpoint: endpointName,
1106
- method: endpoint.method,
1107
- url: fullUrl,
1108
- headers,
1109
- body,
1110
- meta: input.meta
1111
- });
1112
- if (result?.headers)
1113
- headers = result.headers;
1114
- if (result && "body" in result)
1115
- body = result.body;
1116
- } catch (e) {
1117
- if (e instanceof ApiError)
1118
- throw await reportApiError(e, apiConfig);
1119
- throw e;
1120
- }
1121
- }
1122
- const config = {
1123
- method: endpoint.method,
1124
- url: finalUrl,
1125
- queryParams,
1126
- body,
1127
- headers,
1128
- doNotEncodeQueryParams: endpoint.doNotEncodeQueryParams,
1129
- timeoutMs: input.timeoutMs ?? apiConfig.timeoutMs,
1130
- fetchFn: input.fetch ?? apiConfig.fetch ?? fetch,
1131
- userSignal: input.signal
1132
- };
1133
- try {
1134
- const result = await makeRequestWithRetry({
1135
- config,
1136
- maxRetries,
1137
- retryDelay: apiConfig.retryDelayMs ?? 300,
1138
- validateFn: (response) => validateAndTransformResponse(endpoint, response, ctx),
1139
- shouldRetry: apiConfig.shouldRetry ?? defaultShouldRetry,
1140
- logger: apiConfig.logger,
1141
- ctx,
1142
- endpointName,
1143
- method: endpoint.method,
1144
- fullUrl,
1145
- meta: input.meta,
1146
- onResponse: apiConfig.onResponse,
1147
- onRetry: apiConfig.onRetry
1148
- });
1149
- const responseTimeMs = elapsed();
1150
- const responseSizeMb = calculateSizeInMb(result.validatedData);
1151
- const requestBodySizeMb = calculateSizeInMb(config.body);
1152
- return {
1153
- data: result.validatedData,
1154
- requestBodySizeMb,
1155
- responseSizeMb,
1156
- responseTimeMs,
1157
- httpStatus: result.httpStatus,
1158
- retryCount: result.retryCount
1159
- };
1160
- } catch (error) {
1161
- if (error instanceof ApiError)
1162
- throw await reportApiError(error, apiConfig);
1163
- throw error;
1164
- }
1165
- };
1166
- async function invokeAction(name, rawInput, options = {}) {
1167
- const action = actions[name];
1168
- const inputForHandler = action.noRuntimeInput ? undefined : rawInput;
1169
- const actionName = apiConfig.name ? `${apiConfig.name}.${name}` : name;
1170
- const startedAt = Date.now();
1171
- const baseContext = {
1172
- endpoint: actionName,
1173
- method: "GET",
1174
- url: "",
1175
- attempt: 0,
1176
- maxRetries: 0,
1177
- elapsedMs: 0,
1178
- meta: options.meta,
1179
- requestBody: action.noRuntimeInput ? undefined : rawInput
1180
- };
1181
- const ctx = (over = {}) => ({
1182
- ...baseContext,
1183
- elapsedMs: Date.now() - startedAt,
1184
- ...over
1185
- });
1186
- apiConfig.logger?.debug?.("Action start", { action: actionName });
1187
- try {
1188
- const result = await action.handler({
1189
- input: inputForHandler,
1190
- api: proxy,
1191
- signal: options.signal,
1192
- meta: options.meta,
1193
- logger: apiConfig.logger,
1194
- cache
1195
- });
1196
- apiConfig.logger?.debug?.("Action end", {
1197
- action: actionName,
1198
- elapsedMs: Date.now() - startedAt
1199
- });
1200
- return result;
1201
- } catch (error) {
1202
- if (error instanceof ApiError) {
1203
- throw await reportApiError(error, apiConfig);
1204
- }
1205
- const wrapped = new ActionError(`Action ${actionName} failed: ${error instanceof Error ? error.message : String(error)}`, ctx(), error);
1206
- throw await reportApiError(wrapped, apiConfig);
1207
- }
1208
- }
1209
- const request = async (key, input, options) => {
1210
- if (key in actions) {
1211
- const action = actions[key];
1212
- if (action.noRuntimeInput) {
1213
- if (input === undefined || input === null) {
1214
- return invokeAction(key, undefined, options ?? {});
1215
- }
1216
- if (options !== undefined) {
1217
- return invokeAction(key, undefined, options);
1218
- }
1219
- if (isActionInvokeOptionsOnly(input)) {
1220
- return invokeAction(key, undefined, input);
1221
- }
1222
- return invokeAction(key, undefined, {});
1223
- }
1224
- return invokeAction(key, input, options);
1225
- }
1226
- return invokeEndpoint(key, input ?? {});
1227
- };
1228
- const client = { request, cache };
1229
- const proxy = new Proxy(client, {
1230
- get(target, prop, receiver) {
1231
- if (prop in target || typeof prop !== "string") {
1232
- return Reflect.get(target, prop, receiver);
1233
- }
1234
- if (prop in apiConfig.endpoints) {
1235
- return (input) => invokeEndpoint(prop, input ?? {});
1236
- }
1237
- if (prop in actions) {
1238
- const action = actions[prop];
1239
- if (action.noRuntimeInput) {
1240
- return (first, second) => {
1241
- if (first === undefined || first === null) {
1242
- return invokeAction(prop, undefined, second ?? {});
1243
- }
1244
- if (second !== undefined) {
1245
- return invokeAction(prop, undefined, second);
1246
- }
1247
- if (isActionInvokeOptionsOnly(first)) {
1248
- return invokeAction(prop, undefined, first);
1249
- }
1250
- return invokeAction(prop, undefined, {});
1251
- };
1252
- }
1253
- return (input, opt) => invokeAction(prop, input, opt);
1254
- }
1255
- return;
1256
- }
1257
- });
1258
- const rawActions = apiConfig.actions;
1259
- if (typeof rawActions === "function") {
1260
- actions = rawActions({
1261
- api: proxy,
1262
- defineAction: makeDefineAction()
1263
- });
1264
- } else if (rawActions) {
1265
- actions = rawActions;
1266
- }
1267
- const collisions = Object.keys(actions).filter((key) => (key in apiConfig.endpoints));
1268
- if (collisions.length > 0) {
1269
- throw new ConfigError(`Action name(s) collide with endpoint name(s): ${collisions.join(", ")}`, {
1270
- endpoint: collisions[0],
1271
- method: "GET",
1272
- url: "",
1273
- attempt: 0,
1274
- maxRetries: 0,
1275
- elapsedMs: 0
1276
- });
1277
- }
1278
- return proxy;
1279
- }
1280
- var createApiClient = (apiConfig) => createApiClientImpl(apiConfig);
1281
- // src/p-queue/index.ts
1282
- class TimeoutError extends Error {
1283
- constructor(message) {
1284
- super(message);
1285
- this.name = "TimeoutError";
1286
- }
1287
- }
1288
-
1289
- class PriorityQueue {
1290
- #queue = [];
1291
- enqueue(run, options = {}) {
1292
- const element = {
1293
- priority: options.priority ?? 0,
1294
- id: options.id,
1295
- run
1296
- };
1297
- const index = this.#queue.findIndex((item) => item.priority < element.priority);
1298
- if (index === -1) {
1299
- this.#queue.push(element);
1300
- return;
1301
- }
1302
- this.#queue.splice(index, 0, element);
1303
- }
1304
- dequeue() {
1305
- return this.#queue.shift()?.run;
1306
- }
1307
- filter(options) {
1308
- return this.#queue.filter((item) => Object.entries(options).every(([key, value]) => item[key] === value)).map((item) => item.run);
1309
- }
1310
- setPriority(id, priority) {
1311
- const index = this.#queue.findIndex((item2) => item2.id === id);
1312
- if (index === -1) {
1313
- throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
1314
- }
1315
- const [item] = this.#queue.splice(index, 1);
1316
- this.enqueue(item.run, { ...item, priority });
1317
- }
1318
- remove(id) {
1319
- const index = this.#queue.findIndex((item) => item.id === id);
1320
- if (index !== -1) {
1321
- this.#queue.splice(index, 1);
1322
- }
1323
- }
1324
- get size() {
1325
- return this.#queue.length;
1326
- }
1327
- }
1328
-
1329
- class PQueue {
1330
- #listeners = new Map;
1331
- #queue;
1332
- #queueClass;
1333
- #pending = 0;
1334
- #concurrency;
1335
- #isPaused;
1336
- #intervalCap;
1337
- #interval;
1338
- #carryoverIntervalCount;
1339
- #strict;
1340
- #intervalCount = 0;
1341
- #intervalEnd = 0;
1342
- #intervalTimer;
1343
- #strictTimestamps = [];
1344
- #rateLimited = false;
1345
- #idCounter = 1n;
1346
- #runningTasks = new Map;
1347
- timeout;
1348
- constructor(options = {}) {
1349
- const {
1350
- concurrency = Number.POSITIVE_INFINITY,
1351
- autoStart = true,
1352
- queueClass = PriorityQueue,
1353
- intervalCap = Number.POSITIVE_INFINITY,
1354
- interval = 0,
1355
- carryoverIntervalCount,
1356
- carryoverConcurrencyCount,
1357
- strict = false,
1358
- timeout
1359
- } = options;
1360
- if (!(typeof concurrency === "number" && concurrency >= 1)) {
1361
- throw new TypeError("Expected `concurrency` to be a number from 1 and up");
1362
- }
1363
- if (!(typeof intervalCap === "number" && intervalCap >= 1)) {
1364
- throw new TypeError("Expected `intervalCap` to be a number from 1 and up");
1365
- }
1366
- if (!(typeof interval === "number" && Number.isFinite(interval) && interval >= 0)) {
1367
- throw new TypeError("Expected `interval` to be a finite number >= 0");
1368
- }
1369
- if (strict && interval === 0) {
1370
- throw new TypeError("The `strict` option requires a non-zero `interval`");
1371
- }
1372
- if (strict && intervalCap === Number.POSITIVE_INFINITY) {
1373
- throw new TypeError("The `strict` option requires a finite `intervalCap`");
1374
- }
1375
- if (timeout !== undefined && !(Number.isFinite(timeout) && timeout > 0)) {
1376
- throw new TypeError("Expected `timeout` to be a positive finite number");
1377
- }
1378
- this.#queueClass = queueClass;
1379
- this.#queue = new queueClass;
1380
- this.#concurrency = concurrency;
1381
- this.#isPaused = !autoStart;
1382
- this.#intervalCap = intervalCap;
1383
- this.#interval = interval;
1384
- this.#carryoverIntervalCount = carryoverIntervalCount ?? carryoverConcurrencyCount ?? false;
1385
- this.#strict = strict;
1386
- this.timeout = timeout;
1387
- }
1388
- on(event, listener) {
1389
- const listeners = this.#listeners.get(event) ?? new Set;
1390
- listeners.add(listener);
1391
- this.#listeners.set(event, listeners);
1392
- return this;
1393
- }
1394
- off(event, listener) {
1395
- this.#listeners.get(event)?.delete(listener);
1396
- return this;
1397
- }
1398
- emit(event, ...arguments_) {
1399
- const listeners = this.#listeners.get(event);
1400
- if (!listeners || listeners.size === 0) {
1401
- return false;
1402
- }
1403
- for (const listener of [...listeners]) {
1404
- listener(...arguments_);
1405
- }
1406
- return true;
1407
- }
1408
- get concurrency() {
1409
- return this.#concurrency;
1410
- }
1411
- set concurrency(newConcurrency) {
1412
- if (!(typeof newConcurrency === "number" && newConcurrency >= 1)) {
1413
- throw new TypeError("Expected `concurrency` to be a number from 1 and up");
1414
- }
1415
- this.#concurrency = newConcurrency;
1416
- this.#processQueue();
1417
- }
1418
- get size() {
1419
- return this.#queue.size;
1420
- }
1421
- sizeBy(options) {
1422
- return this.#queue.filter(options).length;
1423
- }
1424
- get pending() {
1425
- return this.#pending;
1426
- }
1427
- get isPaused() {
1428
- return this.#isPaused;
1429
- }
1430
- get isRateLimited() {
1431
- this.#updateRateLimitState();
1432
- return this.#rateLimited;
1433
- }
1434
- get isSaturated() {
1435
- return this.#pending >= this.#concurrency && this.#queue.size > 0 || this.isRateLimited && this.#queue.size > 0;
1436
- }
1437
- get runningTasks() {
1438
- return [...this.#runningTasks.values()].map((task) => ({ ...task }));
1439
- }
1440
- setPriority(id, priority) {
1441
- if (typeof priority !== "number" || !Number.isFinite(priority)) {
1442
- throw new TypeError("Expected `priority` to be a finite number");
1443
- }
1444
- this.#queue.setPriority(id, priority);
1445
- }
1446
- async add(function_, options = {}) {
1447
- const taskOptions = {
1448
- timeout: this.timeout,
1449
- ...options,
1450
- id: options.id ?? (this.#idCounter++).toString()
1451
- };
1452
- return new Promise((resolve, reject) => {
1453
- const taskSymbol = Symbol(taskOptions.id);
1454
- let didRun = false;
1455
- let queuedAbortHandler;
1456
- let runningAbortHandler;
1457
- const cleanupQueuedAbort = () => {
1458
- if (queuedAbortHandler) {
1459
- taskOptions.signal?.removeEventListener("abort", queuedAbortHandler);
1460
- queuedAbortHandler = undefined;
1461
- }
1462
- };
1463
- const run = async () => {
1464
- didRun = true;
1465
- cleanupQueuedAbort();
1466
- this.#pending++;
1467
- this.#runningTasks.set(taskSymbol, {
1468
- id: taskOptions.id,
1469
- priority: taskOptions.priority ?? 0,
1470
- startTime: Date.now(),
1471
- timeout: taskOptions.timeout
1472
- });
1473
- try {
1474
- taskOptions.signal?.throwIfAborted();
1475
- const operation = Promise.resolve(function_({ signal: taskOptions.signal }));
1476
- const result = await this.#withTimeoutAndAbort(operation, taskOptions, (listener) => {
1477
- runningAbortHandler = listener;
1478
- });
1479
- resolve(result);
1480
- this.emit("completed", result);
1481
- } catch (error) {
1482
- reject(error);
1483
- this.emit("error", error);
1484
- } finally {
1485
- if (runningAbortHandler) {
1486
- taskOptions.signal?.removeEventListener("abort", runningAbortHandler);
1487
- }
1488
- this.#runningTasks.delete(taskSymbol);
1489
- queueMicrotask(() => {
1490
- this.#next();
1491
- });
1492
- }
1493
- };
1494
- if (taskOptions.signal?.aborted) {
1495
- reject(taskOptions.signal.reason);
1496
- return;
1497
- }
1498
- if (taskOptions.signal) {
1499
- queuedAbortHandler = () => {
1500
- if (didRun) {
1501
- return;
1502
- }
1503
- this.#queue.remove?.(taskOptions.id);
1504
- reject(taskOptions.signal?.reason);
1505
- this.emit("next");
1506
- this.#tryToStartAnother();
1507
- };
1508
- taskOptions.signal.addEventListener("abort", queuedAbortHandler, {
1509
- once: true
1510
- });
1511
- }
1512
- this.#queue.enqueue(run, taskOptions);
1513
- this.emit("add");
1514
- this.#processQueue();
1515
- });
1516
- }
1517
- async addAll(functions, options) {
1518
- return Promise.all(functions.map(async (function_) => this.add(function_, options)));
1519
- }
1520
- start() {
1521
- if (!this.#isPaused) {
1522
- return this;
1523
- }
1524
- this.#isPaused = false;
1525
- this.#processQueue();
1526
- return this;
1527
- }
1528
- pause() {
1529
- this.#isPaused = true;
1530
- }
1531
- clear() {
1532
- this.#queue = new this.#queueClass;
1533
- this.#clearIntervalTimer();
1534
- this.#updateRateLimitState();
1535
- this.emit("empty");
1536
- if (this.#pending === 0) {
1537
- this.emit("idle");
1538
- }
1539
- this.emit("next");
1540
- }
1541
- async onEmpty() {
1542
- if (this.#queue.size === 0) {
1543
- return;
1544
- }
1545
- await this.#onEvent("empty");
1546
- }
1547
- async onIdle() {
1548
- if (this.#queue.size === 0 && this.#pending === 0) {
1549
- return;
1550
- }
1551
- await this.#onEvent("idle");
1552
- }
1553
- async onPendingZero() {
1554
- if (this.#pending === 0) {
1555
- return;
1556
- }
1557
- await this.#onEvent("pendingZero");
1558
- }
1559
- async onRateLimit() {
1560
- if (this.isRateLimited) {
1561
- return;
1562
- }
1563
- await this.#onEvent("rateLimit");
1564
- }
1565
- async onRateLimitCleared() {
1566
- if (!this.isRateLimited) {
1567
- return;
1568
- }
1569
- await this.#onEvent("rateLimitCleared");
1570
- }
1571
- onError() {
1572
- return new Promise((_resolve, reject) => {
1573
- const listener = (error) => {
1574
- this.off("error", listener);
1575
- reject(error);
1576
- };
1577
- this.on("error", listener);
1578
- });
1579
- }
1580
- async onSizeLessThan(limit) {
1581
- if (this.#queue.size < limit) {
1582
- return;
1583
- }
1584
- await this.#onEvent("next", () => this.#queue.size < limit);
1585
- }
1586
- async#onEvent(event, filter) {
1587
- return new Promise((resolve) => {
1588
- const listener = () => {
1589
- if (filter && !filter()) {
1590
- return;
1591
- }
1592
- this.off(event, listener);
1593
- resolve();
1594
- };
1595
- this.on(event, listener);
1596
- });
1597
- }
1598
- async#withTimeoutAndAbort(operation, options, setAbortListener) {
1599
- const races = [operation];
1600
- let timeoutId;
1601
- if (options.timeout) {
1602
- races.push(new Promise((_resolve, reject) => {
1603
- timeoutId = setTimeout(() => {
1604
- reject(new TimeoutError(`Task timed out after ${options.timeout}ms`));
1605
- }, options.timeout);
1606
- }));
1607
- }
1608
- if (options.signal) {
1609
- races.push(new Promise((_resolve, reject) => {
1610
- const listener = () => {
1611
- reject(options.signal?.reason);
1612
- };
1613
- setAbortListener(listener);
1614
- options.signal?.addEventListener("abort", listener, { once: true });
1615
- }));
1616
- }
1617
- try {
1618
- return await Promise.race(races);
1619
- } finally {
1620
- if (timeoutId) {
1621
- clearTimeout(timeoutId);
1622
- }
1623
- }
1624
- }
1625
- #next() {
1626
- this.#pending--;
1627
- if (this.#pending === 0) {
1628
- this.emit("pendingZero");
1629
- }
1630
- this.#processQueue();
1631
- this.emit("next");
1632
- }
1633
- #processQueue() {
1634
- while (this.#tryToStartAnother()) {}
1635
- this.#updateRateLimitState();
1636
- }
1637
- #tryToStartAnother() {
1638
- if (this.#queue.size === 0) {
1639
- this.#clearIntervalTimer();
1640
- this.emit("empty");
1641
- if (this.#pending === 0) {
1642
- this.emit("idle");
1643
- }
1644
- return false;
1645
- }
1646
- if (this.#isPaused || this.#pending >= this.#concurrency || !this.#doesIntervalAllowAnother()) {
1647
- return false;
1648
- }
1649
- const job = this.#queue.dequeue();
1650
- if (!job) {
1651
- return false;
1652
- }
1653
- this.#consumeIntervalSlot();
1654
- this.emit("active");
1655
- job();
1656
- return true;
1657
- }
1658
- #doesIntervalAllowAnother() {
1659
- if (this.#intervalCap === Number.POSITIVE_INFINITY || this.#interval === 0) {
1660
- return true;
1661
- }
1662
- const now = Date.now();
1663
- if (this.#strict) {
1664
- this.#strictTimestamps = this.#strictTimestamps.filter((timestamp) => now - timestamp < this.#interval);
1665
- if (this.#strictTimestamps.length < this.#intervalCap) {
1666
- return true;
1667
- }
1668
- this.#scheduleIntervalResume(this.#interval - (now - this.#strictTimestamps[0]));
1669
- return false;
1670
- }
1671
- if (this.#intervalEnd === 0 || now >= this.#intervalEnd) {
1672
- this.#intervalCount = this.#carryoverIntervalCount ? this.#pending : 0;
1673
- this.#intervalEnd = now + this.#interval;
1674
- }
1675
- if (this.#intervalCount < this.#intervalCap) {
1676
- return true;
1677
- }
1678
- this.#scheduleIntervalResume(this.#intervalEnd - now);
1679
- return false;
1680
- }
1681
- #consumeIntervalSlot() {
1682
- if (this.#intervalCap === Number.POSITIVE_INFINITY || this.#interval === 0) {
1683
- return;
1684
- }
1685
- if (this.#strict) {
1686
- this.#strictTimestamps.push(Date.now());
1687
- return;
1688
- }
1689
- this.#intervalCount++;
1690
- }
1691
- #scheduleIntervalResume(delay2) {
1692
- if (this.#intervalTimer) {
1693
- return;
1694
- }
1695
- this.#intervalTimer = setTimeout(() => {
1696
- this.#intervalTimer = undefined;
1697
- this.#processQueue();
1698
- }, Math.max(0, delay2));
1699
- }
1700
- #clearIntervalTimer() {
1701
- if (this.#intervalTimer) {
1702
- clearTimeout(this.#intervalTimer);
1703
- this.#intervalTimer = undefined;
1704
- }
1705
- }
1706
- #updateRateLimitState() {
1707
- const previous = this.#rateLimited;
1708
- const isRateLimited = this.#queue.size > 0 && this.#intervalCap !== Number.POSITIVE_INFINITY && this.#interval > 0 && !this.#doesIntervalAllowAnother();
1709
- this.#rateLimited = isRateLimited;
1710
- if (previous !== isRateLimited) {
1711
- this.emit(isRateLimited ? "rateLimit" : "rateLimitCleared");
1712
- }
1713
- }
1714
- }
1715
-
1716
- // src/jwt/index.ts
1717
- var BYTE_CHUNK_SIZE = 32768;
1718
- var textEncoder = new TextEncoder;
1719
- var textDecoder = new TextDecoder;
1720
- async function jwtSign(payload, secret) {
1721
- const header = encodeJson({ alg: "HS256" });
1722
- const body = encodeJson({
1723
- ...payload,
1724
- iat: Math.floor(Date.now() / 1000)
1725
- });
1726
- const data = `${header}.${body}`;
1727
- const signature = await sign(data, secret);
1728
- return `${data}.${encodeBase64Url(signature)}`;
1729
- }
1730
- async function jwtVerify(token, secret) {
1731
- try {
1732
- const parts = token.split(".");
1733
- if (parts.length !== 3)
1734
- return null;
1735
- const [encodedHeader, encodedPayload, encodedSignature] = parts;
1736
- const header = decodeJson(encodedHeader);
1737
- if (!isJwtHeader(header))
1738
- return null;
1739
- const data = `${encodedHeader}.${encodedPayload}`;
1740
- const signature = decodeBase64Url(encodedSignature);
1741
- const isValid = await verify(data, signature, secret);
1742
- if (!isValid)
1743
- return null;
1744
- const payload = decodeJson(encodedPayload);
1745
- if (!isJwtPayload(payload) || !isTimeValid(payload))
1746
- return null;
1747
- return payload;
1748
- } catch (_error) {
1749
- return null;
1750
- }
1751
- }
1752
- async function sign(data, secret) {
1753
- const key = await getKey(secret, ["sign"]);
1754
- return await getSubtleCrypto().sign("HMAC", key, encodeText(data));
1755
- }
1756
- async function verify(data, signature, secret) {
1757
- const key = await getKey(secret, ["verify"]);
1758
- return await getSubtleCrypto().verify("HMAC", key, signature, encodeText(data));
1759
- }
1760
- async function getKey(secret, usages) {
1761
- return await getSubtleCrypto().importKey("raw", encodeText(secret), {
1762
- name: "HMAC",
1763
- hash: "SHA-256"
1764
- }, false, usages);
1765
- }
1766
- function encodeJson(value) {
1767
- return encodeBase64Url(encodeText(JSON.stringify(value)));
1768
- }
1769
- function decodeJson(value) {
1770
- return JSON.parse(textDecoder.decode(decodeBase64Url(value)));
1771
- }
1772
- function encodeBase64Url(value) {
1773
- const bytes = value instanceof ArrayBuffer ? new Uint8Array(value) : value;
1774
- return btoa(bytesToBinaryString(bytes)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
1775
- }
1776
- function decodeBase64Url(value) {
1777
- const base64 = value.replaceAll("-", "+").replaceAll("_", "/");
1778
- const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
1779
- return binaryStringToBytes(atob(padded)).buffer;
1780
- }
1781
- function encodeText(value) {
1782
- return toArrayBuffer(textEncoder.encode(value));
1783
- }
1784
- function toArrayBuffer(bytes) {
1785
- return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
1786
- }
1787
- function bytesToBinaryString(bytes) {
1788
- let binary = "";
1789
- for (let offset = 0;offset < bytes.length; offset += BYTE_CHUNK_SIZE) {
1790
- binary += String.fromCharCode(...bytes.subarray(offset, offset + BYTE_CHUNK_SIZE));
1791
- }
1792
- return binary;
1793
- }
1794
- function binaryStringToBytes(binary) {
1795
- const bytes = new Uint8Array(binary.length);
1796
- for (let index = 0;index < binary.length; index += 1) {
1797
- bytes[index] = binary.charCodeAt(index);
1798
- }
1799
- return bytes;
1800
- }
1801
- function getSubtleCrypto() {
1802
- const subtle = globalThis.crypto?.subtle;
1803
- if (!subtle) {
1804
- throw new Error("Web Crypto is not available in this runtime");
1805
- }
1806
- return subtle;
1807
- }
1808
- function isJwtHeader(value) {
1809
- return typeof value === "object" && value !== null && "alg" in value && value.alg === "HS256";
1810
- }
1811
- function isJwtPayload(value) {
1812
- return typeof value === "object" && value !== null && !Array.isArray(value);
1813
- }
1814
- function isTimeValid(payload) {
1815
- const now = Math.floor(Date.now() / 1000);
1816
- if (typeof payload.exp === "number" && now >= payload.exp)
1817
- return false;
1818
- if (typeof payload.nbf === "number" && now < payload.nbf)
1819
- return false;
1820
- return true;
1821
- }
1822
-
1823
- // src/sitemap/index.ts
1824
- var createTimeoutController = (timeout) => {
1825
- const controller = new AbortController;
1826
- setTimeout(() => controller.abort(), timeout);
1827
- return controller;
1828
- };
1829
- var discoverSitemaps = async (domain) => {
1830
- const normalizedDomain = domain.replace(/\/$/, "");
1831
- const commonLocations = [
1832
- "/sitemap.xml",
1833
- "/sitemap_index.xml",
1834
- "/sitemap/",
1835
- "/sitemaps.xml",
1836
- "/sitemap/sitemap.xml"
1837
- ];
1838
- const sitemaps = new Set;
1839
- const requestOptions = {
1840
- headers: {
1841
- "User-Agent": "SitemapCrawler/1.0"
1842
- },
1843
- signal: createTimeoutController(5000).signal
1844
- };
1845
- try {
1846
- const robotsTxt = await fetch(`${normalizedDomain}/robots.txt`, {
1847
- ...requestOptions
1848
- });
1849
- if (robotsTxt.ok) {
1850
- const text = await robotsTxt.text();
1851
- const sitemapMatches = text.match(/Sitemap: (.*)/gi);
1852
- if (sitemapMatches) {
1853
- sitemapMatches.forEach((match) => {
1854
- const url = match.replace("Sitemap:", "").trim();
1855
- sitemaps.add(url);
1856
- });
1857
- }
1858
- if (sitemaps.size > 0) {
1859
- return [...sitemaps];
1860
- }
1861
- }
1862
- } catch (error) {
1863
- console.warn("Could not fetch robots.txt:", error instanceof Error ? error.message : "Unknown error");
1864
- }
1865
- for (const location of commonLocations) {
1866
- try {
1867
- const response = await fetch(`${normalizedDomain}${location}`, {
1868
- ...requestOptions,
1869
- method: "HEAD"
1870
- });
1871
- if (response.ok) {
1872
- return [`${normalizedDomain}${location}`];
1873
- }
1874
- } catch (_error) {}
1875
- }
1876
- return [];
1877
- };
1878
- var getDomainSitemap = async (domain, options = {}) => {
1879
- const {
1880
- filterIndexes,
1881
- concurrency = 10,
1882
- maxDepth = 5,
1883
- timeout = 1e4
1884
- } = options;
1885
- let normalizedDomain = domain.replace(/\/$/, "");
1886
- if (!normalizedDomain.startsWith("http")) {
1887
- normalizedDomain = `https://${normalizedDomain}`;
1888
- }
1889
- const sitemapUrls = await discoverSitemaps(normalizedDomain);
1890
- if (sitemapUrls.length === 0) {
1891
- throw new Error("No sitemaps found for the domain");
1892
- }
1893
- const queue = new PQueue({ concurrency });
1894
- const result = {
1895
- links: new Set,
1896
- visited: new Set
1897
- };
1898
- const locRegex = /<loc>([^<]+)<\/loc>/g;
1899
- const isXmlSitemap = (url) => url.endsWith(".xml") || url.toLowerCase().includes("sitemap");
1900
- const processSitemap = async (sitemapUrl, depth = 0) => {
1901
- if (depth > maxDepth || result.visited.has(sitemapUrl)) {
1902
- return;
1903
- }
1904
- result.visited.add(sitemapUrl);
1905
- try {
1906
- const controller = createTimeoutController(timeout);
1907
- const response = await fetch(sitemapUrl, {
1908
- headers: {
1909
- "User-Agent": "SitemapCrawler/1.0"
1910
- },
1911
- signal: controller.signal
1912
- });
1913
- if (!response.ok)
1914
- throw new Error(`HTTP error! status: ${response.status}`);
1915
- const data = await response.text();
1916
- const matches = [...data.matchAll(locRegex)].map((match) => match[1].trim()).filter((link) => {
1917
- if (filterIndexes && isXmlSitemap(link)) {
1918
- return link.includes(filterIndexes);
1919
- }
1920
- return true;
1921
- });
1922
- for (const link of matches) {
1923
- if (isXmlSitemap(link)) {
1924
- queue.add(() => processSitemap(link, depth + 1));
1925
- } else {
1926
- result.links.add(link);
1927
- }
1928
- }
1929
- } catch (error) {
1930
- console.warn(`Failed to process sitemap ${sitemapUrl}:`, error instanceof Error ? error.message : "Unknown error");
1931
- }
1932
- };
1933
- await Promise.all(sitemapUrls.map((sitemapUrl) => queue.add(() => processSitemap(sitemapUrl))));
1934
- await queue.onIdle();
1935
- return [...result.links];
1936
- };
1937
-
1938
- // src/secrets/infisical.ts
1939
- import { z as z4 } from "zod";
1940
- var DEFAULT_INFISICAL_SITE_URL = "https://eu.infisical.com";
1941
- var defaultFetch = globalThis.fetch;
1942
- var infisicalAuthResponseSchema = z4.object({
1943
- accessToken: z4.string()
1944
- });
1945
- var infisicalSecretSchema = z4.object({
1946
- secretKey: z4.string(),
1947
- secretValue: z4.string()
1948
- });
1949
- var infisicalSecretsResponseSchema = z4.object({
1950
- secrets: z4.array(infisicalSecretSchema)
1951
- });
1952
- async function fetchInfisicalSecrets({
1953
- keys,
1954
- projectId,
1955
- environment,
1956
- siteUrl,
1957
- clientId,
1958
- clientSecret
1959
- }) {
1960
- const infisical = createInfisicalApiClient(siteUrl);
1961
- const { data: auth } = await infisical.request("login", {
1962
- reqBody: {
1963
- clientId,
1964
- clientSecret
1965
- }
1966
- });
1967
- const { data } = await infisical.request("listSecrets", {
1968
- reqHeaders: {
1969
- Authorization: `Bearer ${auth.accessToken}`
1970
- },
1971
- reqQuery: {
1972
- environment,
1973
- projectId,
1974
- secretPath: "/",
1975
- viewSecretValue: true,
1976
- expandSecretReferences: true,
1977
- includeImports: true
1978
- }
1979
- });
1980
- const wantedKeys = new Set(keys);
1981
- return Object.fromEntries(data.secrets.filter((secret) => wantedKeys.has(secret.secretKey)).map((secret) => [secret.secretKey, secret.secretValue]));
1982
- }
1983
- async function loadInfisicalSecrets({
1984
- keys,
1985
- projectId,
1986
- environment,
1987
- siteUrl,
1988
- clientIdEnvKey,
1989
- clientSecretEnvKey
1990
- }) {
1991
- const clientId = process.env[clientIdEnvKey];
1992
- const clientSecret = process.env[clientSecretEnvKey];
1993
- if (!clientId || !clientSecret) {
1994
- throw new Error("Missing Infisical credentials");
1995
- }
1996
- return fetchInfisicalSecrets({
1997
- keys,
1998
- projectId,
1999
- environment,
2000
- siteUrl,
2001
- clientId,
2002
- clientSecret
2003
- });
2004
- }
2005
- function createInfisicalApiClient(siteUrl) {
2006
- return createApiClient({
2007
- name: "infisical",
2008
- baseApiUrls: {
2009
- infisical: siteUrl
2010
- },
2011
- defaultBaseApiUrl: "infisical",
2012
- fetch: getFetch(),
2013
- retries: 1,
2014
- endpoints: {
2015
- login: {
2016
- method: "POST",
2017
- path: "/api/v1/auth/universal-auth/login",
2018
- reqBodySchema: z4.object({
2019
- clientId: z4.string(),
2020
- clientSecret: z4.string()
2021
- }),
2022
- resSchema: infisicalAuthResponseSchema,
2023
- reqBodyFormat: "json"
2024
- },
2025
- listSecrets: {
2026
- method: "GET",
2027
- path: "/api/v4/secrets",
2028
- reqHeadersSchema: z4.object({
2029
- Authorization: z4.string()
2030
- }),
2031
- reqQuerySchema: z4.object({
2032
- projectId: z4.string(),
2033
- environment: z4.string(),
2034
- secretPath: z4.string(),
2035
- viewSecretValue: z4.boolean(),
2036
- expandSecretReferences: z4.boolean(),
2037
- includeImports: z4.boolean()
2038
- }),
2039
- resSchema: infisicalSecretsResponseSchema
2040
- }
2041
- }
2042
- });
2043
- }
2044
- function getFetch() {
2045
- return globalThis.fetch ?? defaultFetch;
2046
- }
2047
-
2048
- // src/secrets/loaders.ts
2049
- function cloudflareWorkerEnvLoader(workerEnv) {
2050
- return async (ctx) => {
2051
- const out = {};
2052
- for (const key of ctx.keys) {
2053
- const str = workerBindingToString(workerEnv[key]);
2054
- if (str !== undefined) {
2055
- out[key] = str;
2056
- }
2057
- }
2058
- return out;
2059
- };
2060
- }
2061
- function workerBindingToString(value) {
2062
- if (value === undefined || value === null) {
2063
- return;
2064
- }
2065
- if (typeof value === "string") {
2066
- return value === "" ? undefined : value;
2067
- }
2068
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
2069
- return String(value);
2070
- }
2071
- if (typeof value === "object") {
2072
- return JSON.stringify(value);
2073
- }
2074
- return String(value);
2075
- }
2076
- function infisicalLoader(config) {
2077
- return async (ctx) => fetchInfisicalSecrets({
2078
- keys: ctx.keys,
2079
- projectId: config.projectId,
2080
- environment: ctx.environment,
2081
- siteUrl: config.siteUrl ?? DEFAULT_INFISICAL_SITE_URL,
2082
- clientId: config.clientId,
2083
- clientSecret: config.clientSecret
2084
- });
2085
- }
2086
- async function processEnvLoader(_ctx) {
2087
- return {};
2088
- }
2089
-
2090
- // src/secrets/vite.ts
2091
- function getViteDefine(secretSet) {
2092
- return Object.fromEntries(Object.entries(secretSet.secrets()).map(([key, value]) => [
2093
- `import.meta.env.${key}`,
2094
- JSON.stringify(value)
2095
- ]));
2096
- }
2097
- function viteSecretSetPlugin(secretSet) {
2098
- return {
2099
- name: "hanzio-secret-set",
2100
- config: () => ({
2101
- define: getViteDefine(secretSet)
2102
- })
2103
- };
2104
- }
2105
-
2106
- // src/cool-console-log/index.ts
2107
- var terminalColors = {
2108
- reset: "\x1B[0m",
2109
- bold: "\x1B[1m",
2110
- dim: "\x1B[2m",
2111
- italic: "\x1B[3m",
2112
- underline: "\x1B[4m",
2113
- black: "\x1B[30m",
2114
- red: "\x1B[31m",
2115
- green: "\x1B[32m",
2116
- yellow: "\x1B[33m",
2117
- blue: "\x1B[34m",
2118
- magenta: "\x1B[35m",
2119
- cyan: "\x1B[36m",
2120
- white: "\x1B[37m",
2121
- gray: "\x1B[90m",
2122
- brightRed: "\x1B[91m",
2123
- brightGreen: "\x1B[92m",
2124
- brightYellow: "\x1B[93m",
2125
- brightBlue: "\x1B[94m",
2126
- brightMagenta: "\x1B[95m",
2127
- brightCyan: "\x1B[96m",
2128
- brightWhite: "\x1B[97m",
2129
- bgBlack: "\x1B[40m",
2130
- bgRed: "\x1B[41m",
2131
- bgGreen: "\x1B[42m",
2132
- bgYellow: "\x1B[43m",
2133
- bgBlue: "\x1B[44m",
2134
- bgMagenta: "\x1B[45m",
2135
- bgCyan: "\x1B[46m",
2136
- bgWhite: "\x1B[47m"
2137
- };
2138
- var levelColors = {
2139
- debug: { badge: terminalColors.gray, text: terminalColors.dim },
2140
- info: { badge: terminalColors.cyan, text: terminalColors.reset },
2141
- warn: { badge: terminalColors.yellow, text: terminalColors.yellow },
2142
- error: { badge: terminalColors.red, text: terminalColors.brightRed }
2143
- };
2144
- function formatAttributes(attrs) {
2145
- if (!attrs || Object.keys(attrs).length === 0)
2146
- return "";
2147
- const formatted = Object.entries(attrs).map(([k, v]) => `${terminalColors.dim}${k}=${terminalColors.reset}${v}`).join(" ");
2148
- return ` ${formatted}`;
2149
- }
2150
- function createCoolLogger(options = {}) {
2151
- const { colorsInDevOnly = true, onLog } = options;
2152
- const isDev = true;
2153
- const useColors = colorsInDevOnly ? isDev : true;
2154
- const createLogMethod = (level) => (message, attributes) => {
2155
- onLog?.(level, message, attributes);
2156
- if (level === "debug" && !isDev)
2157
- return;
2158
- if (useColors) {
2159
- const { badge, text } = levelColors[level];
2160
- const label = level.toUpperCase().padEnd(5);
2161
- const attrStr = formatAttributes(attributes);
2162
- console.log(`${badge}[${label}]${terminalColors.reset} ${text}${message}${terminalColors.reset}${attrStr}`);
2163
- } else {
2164
- console[level](`[${level.toUpperCase()}]`, message, attributes ?? "");
2165
- }
2166
- };
2167
- return {
2168
- debug: createLogMethod("debug"),
2169
- info: createLogMethod("info"),
2170
- warn: createLogMethod("warn"),
2171
- error: createLogMethod("error")
2172
- };
2173
- }
2174
- function logOperationSummary(operationName, durationMs, success, options = {}) {
2175
- const { devOnly = true, error } = options;
2176
- const isDev = true;
2177
- if (devOnly && !isDev)
2178
- return;
2179
- const c = terminalColors;
2180
- const statusIcon = success ? `${c.brightGreen}✓${c.reset}` : `${c.brightRed}✗${c.reset}`;
2181
- const statusColor = success ? c.green : c.red;
2182
- const durationStr = `${c.dim}${durationMs.toFixed(1)}ms${c.reset}`;
2183
- const errorMessage = error ? ` ${c.dim}·${c.reset} ${c.red}${error instanceof Error ? error.message : String(error)}${c.reset}` : "";
2184
- console.log(`${statusColor}${c.bold}${operationName}${c.reset} ${statusIcon} ${c.dim}·${c.reset} ${durationStr}${errorMessage}`);
2185
- }
2186
- function colorize(text, color, ...modifiers) {
2187
- const isDev = true;
2188
- if (!isDev)
2189
- return text;
2190
- const colorCodes = [
2191
- terminalColors[color],
2192
- ...modifiers.map((m) => terminalColors[m])
2193
- ].join("");
2194
- return `${colorCodes}${text}${terminalColors.reset}`;
2195
- }
2196
- function logBanner(text, color = "cyan", options = {}) {
2197
- const { devOnly = true } = options;
2198
- const isDev = true;
2199
- if (devOnly && !isDev) {
2200
- console.log(`=== ${text} ===`);
2201
- return;
2202
- }
2203
- const c = terminalColors;
2204
- const padding = 2;
2205
- const line = "═".repeat(text.length + padding * 2);
2206
- console.log(`${c[color]}╔${line}╗${c.reset}`);
2207
- console.log(`${c[color]}║${" ".repeat(padding)}${c.bold}${text}${c.reset}${c[color]}${" ".repeat(padding)}║${c.reset}`);
2208
- console.log(`${c[color]}╚${line}╝${c.reset}`);
2209
- }
2210
-
2211
- // src/secrets/index.ts
2212
- var logger = createCoolLogger();
2213
- function getSecretEnvironment() {
2214
- const env = process.env.SECRETS_ENV || "development";
2215
- if (env === "production" || env === "prod")
2216
- return "prod";
2217
- if (env === "staging")
2218
- return "staging";
2219
- return "dev";
2220
- }
2221
- async function defineSecretSet(keys, options) {
2222
- const keySet = [...new Set(keys)];
2223
- const resolvedOptions = resolveSecretSetOptions(options);
2224
- let cachedSecrets = null;
2225
- const loadSecrets = async (force = false) => {
2226
- const nextSecrets = await loadAndMergeSecrets({
2227
- keySet,
2228
- cachedSecrets,
2229
- force,
2230
- ...resolvedOptions
2231
- });
2232
- cachedSecrets = nextSecrets;
2233
- return nextSecrets;
2234
- };
2235
- const secretSet = createSecretSet({
2236
- getCachedSecrets: () => cachedSecrets,
2237
- reload: loadSecrets
2238
- });
2239
- await loadSecrets();
2240
- return secretSet;
2241
- }
2242
- function resolveSecretSetOptions(options) {
2243
- const environment = resolveEnvironment(options.environment);
2244
- const loader = options.loader ? options.loader : (context) => loadInfisicalSecrets({
2245
- ...context,
2246
- projectId: options.projectId,
2247
- siteUrl: options.siteUrl ?? DEFAULT_INFISICAL_SITE_URL,
2248
- clientIdEnvKey: options.clientIdEnvKey ?? "INFISICAL_CLIENT_ID",
2249
- clientSecretEnvKey: options.clientSecretEnvKey ?? "INFISICAL_CLIENT_SECRET"
2250
- });
2251
- return {
2252
- loader,
2253
- environment
2254
- };
2255
- }
2256
- async function loadAndMergeSecrets({
2257
- keySet,
2258
- cachedSecrets,
2259
- loader,
2260
- environment,
2261
- force
2262
- }) {
2263
- const processEnvSecrets = readProcessEnvSecrets(keySet, force ? cachedSecrets : null);
2264
- const keysMissingFromEnv = keySet.filter((key) => !processEnvSecrets[key]);
2265
- logSecretEnvironment(environment, keySet.length);
2266
- const loaderKeys = force ? keySet : keysMissingFromEnv;
2267
- const loadedSecrets = loaderKeys.length === 0 ? {} : await loader({
2268
- keys: loaderKeys,
2269
- environment
2270
- });
2271
- const missingKeys = keySet.filter((key) => !(processEnvSecrets[key] ?? loadedSecrets[key]));
2272
- if (missingKeys.length > 0) {
2273
- throw new Error(`Missing secrets: ${missingKeys.join(", ")}`);
2274
- }
2275
- const nextSecrets = Object.fromEntries(keySet.map((key) => [
2276
- key,
2277
- processEnvSecrets[key] ?? loadedSecrets[key]
2278
- ]));
2279
- for (const [key, value] of Object.entries(nextSecrets)) {
2280
- process.env[key] = value;
2281
- }
2282
- return nextSecrets;
2283
- }
2284
- function createSecretSet({
2285
- getCachedSecrets,
2286
- reload
2287
- }) {
2288
- const secretSet = {
2289
- secret(key) {
2290
- const value = getCachedSecrets()?.[key] ?? process.env[key];
2291
- if (!value) {
2292
- throw new Error(`Secret ${key} not found`);
2293
- }
2294
- return value;
2295
- },
2296
- secrets() {
2297
- const cachedSecrets = getCachedSecrets();
2298
- if (!cachedSecrets) {
2299
- throw new Error("Secrets not initialized.");
2300
- }
2301
- return { ...cachedSecrets };
2302
- },
2303
- async reload() {
2304
- await reload(true);
2305
- return secretSet;
2306
- }
2307
- };
2308
- return secretSet;
2309
- }
2310
- function resolveEnvironment(environment) {
2311
- if (typeof environment === "function")
2312
- return environment();
2313
- return environment ?? getSecretEnvironment();
2314
- }
2315
- function logSecretEnvironment(environment, secretCount) {
2316
- logger.info(colorize("Loading secrets", "cyan", "bold"), {
2317
- environment: colorize(environment, "brightCyan", "bold"),
2318
- count: secretCount
2319
- });
2320
- }
2321
- function readProcessEnvSecrets(keys, previousSecrets = null) {
2322
- return Object.fromEntries(keys.filter((key) => {
2323
- const value = process.env[key];
2324
- return value && value !== previousSecrets?.[key];
2325
- }).map((key) => [key, process.env[key]]));
2326
- }
1
+ import {
2
+ chunkArray2,
3
+ findArrayDifferenceByKey2,
4
+ getUniqueValues2,
5
+ compact2,
6
+ getUniqueValuesByKey2,
7
+ groupBy2,
8
+ countBy2,
9
+ keyBy2,
10
+ partition2,
11
+ pickItemsInArray2,
12
+ toArray2,
13
+ sumBy2,
14
+ sortBy2,
15
+ range2
16
+ } from "../index-hy7kbb99.js";
17
+ import {
18
+ createCache2
19
+ } from "../index-k9yx6bne.js";
20
+ import {
21
+ ok2,
22
+ err2,
23
+ isSuccess2,
24
+ isFailure2,
25
+ unwrapResult2,
26
+ backgroundPromise2,
27
+ backgroundPromiseSync2,
28
+ promiseTimeout2,
29
+ tryCatch2,
30
+ PromiseTimeoutError2,
31
+ withTimeout2,
32
+ exponentialBackoff2,
33
+ retry2,
34
+ pMap2,
35
+ startTimer2,
36
+ timed2,
37
+ anySignal2,
38
+ timeoutSignal2,
39
+ raceAbort2,
40
+ createLatestGuard2
41
+ } from "../index-0zvtcbzy.js";
42
+ import {
43
+ InvariantError2,
44
+ getErrorMessage2,
45
+ toError2,
46
+ must2,
47
+ invariant2,
48
+ isRecord2,
49
+ isPlainObject2,
50
+ isDefined2,
51
+ isTruthy2,
52
+ isString2,
53
+ isNumber2,
54
+ isBoolean2,
55
+ isFunction2,
56
+ isOneOf2,
57
+ hasKey2,
58
+ isNonEmpty2,
59
+ nonEmpty2
60
+ } from "../index-8r2vdzjg.js";
61
+ import {
62
+ extractNumber2,
63
+ generateId2,
64
+ sha256Id2,
65
+ slugify2,
66
+ stableStringify2,
67
+ truncate2,
68
+ normalizeWhitespace2,
69
+ escapeRegExp2,
70
+ foldForSearch2,
71
+ matchesSearch2,
72
+ initials2,
73
+ safeJsonParse2
74
+ } from "../index-kj1phgrx.js";
75
+ import {
76
+ buildQueryString2,
77
+ replacePathParams2,
78
+ buildUrl2,
79
+ normalizeDomain2,
80
+ getDomainFaviconUrl2,
81
+ trimTrailingSlash2,
82
+ ensureLeadingSlash2,
83
+ buildMailto2,
84
+ parseRetryAfter2
85
+ } from "../index-mnkcfyx8.js";
2327
86
 
2328
87
  // src/typedswitch/index.ts
2329
- function runSwitch(value, keyOrCases, casesOrDefault, defaultCase) {
88
+ function typedSwitch(value, keyOrCases, casesOrDefault, defaultCase) {
2330
89
  let key;
2331
90
  let cases;
2332
91
  let defaultHandler;
@@ -2334,213 +93,34 @@ function runSwitch(value, keyOrCases, casesOrDefault, defaultCase) {
2334
93
  if (typeof value === "string") {
2335
94
  key = value;
2336
95
  cases = keyOrCases;
2337
- defaultHandler = casesOrDefault;
2338
- } else {
2339
- if (typeof keyOrCases !== "string") {
2340
- throw new Error("Invalid typedSwitch call: object mode requires a string discriminant key");
2341
- }
2342
- discriminantKey = keyOrCases;
2343
- const discriminantValue = value[discriminantKey];
2344
- if (typeof discriminantValue !== "string") {
2345
- throw new Error(`Invalid discriminant value for key "${discriminantKey}": expected string, received ${typeof discriminantValue}`);
2346
- }
2347
- key = discriminantValue;
2348
- cases = casesOrDefault;
2349
- defaultHandler = defaultCase;
2350
- }
2351
- const handler = cases[key];
2352
- if (handler) {
2353
- return handler(value);
2354
- }
2355
- if (defaultHandler) {
2356
- return defaultHandler(value);
2357
- }
2358
- const availableCases = Object.keys(cases).join(", ");
2359
- const availableCasesSuffix = availableCases.length > 0 ? ` Available cases: ${availableCases}` : " Available cases: (none)";
2360
- const contextSuffix = discriminantKey ? ` (discriminant key: "${discriminantKey}")` : "";
2361
- throw new Error(`Unhandled case: ${key}${contextSuffix}.${availableCasesSuffix}`);
2362
- }
2363
- function typedSwitch(value, keyOrCases, casesOrDefault, defaultCase) {
2364
- return runSwitch(value, keyOrCases, casesOrDefault, defaultCase);
2365
- }
2366
- // src/array/index.ts
2367
- function chunkArray(array, chunkSize) {
2368
- if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
2369
- throw new Error("Chunk size must be a positive integer");
2370
- }
2371
- const chunks = [];
2372
- for (let index = 0;index < array.length; index += chunkSize) {
2373
- chunks.push(array.slice(index, index + chunkSize));
2374
- }
2375
- return chunks;
2376
- }
2377
- function findArrayDifferenceByKey(current, next, key) {
2378
- const currentByKey = new Map(current.map((item) => [String(item[key]), item]));
2379
- const itemsToDelete = [...current];
2380
- const newItems = [];
2381
- const upsertItems = [];
2382
- for (const item of next) {
2383
- const keyValue = String(item[key]);
2384
- if (!currentByKey.has(keyValue)) {
2385
- newItems.push(item);
2386
- continue;
2387
- }
2388
- upsertItems.push(item);
2389
- const deleteIndex = itemsToDelete.findIndex((currentItem) => String(currentItem[key]) === keyValue);
2390
- if (deleteIndex >= 0) {
2391
- itemsToDelete.splice(deleteIndex, 1);
2392
- }
2393
- }
2394
- return {
2395
- new: newItems,
2396
- upsert: upsertItems,
2397
- delete: itemsToDelete
2398
- };
2399
- }
2400
- function getUniqueValues(array) {
2401
- const seen = new Map;
2402
- for (const element of array) {
2403
- const key = JSON.stringify(element);
2404
- if (!seen.has(key)) {
2405
- seen.set(key, element);
2406
- }
2407
- }
2408
- return Array.from(seen.values());
2409
- }
2410
- function compact(array) {
2411
- return array.filter((item) => item != null);
2412
- }
2413
- function getUniqueValuesByKey(array, key) {
2414
- const seen = new Set;
2415
- const result = [];
2416
- for (const item of array) {
2417
- const value = item[key];
2418
- if (seen.has(value))
2419
- continue;
2420
- seen.add(value);
2421
- result.push(item);
2422
- }
2423
- return result;
2424
- }
2425
- function groupBy(array, keyOrFn) {
2426
- return array.reduce((result, item) => {
2427
- const groupKey = typeof keyOrFn === "function" ? keyOrFn(item) : item[keyOrFn];
2428
- result[groupKey] ??= [];
2429
- result[groupKey].push(item);
2430
- return result;
2431
- }, {});
2432
- }
2433
- function keyBy(array, keyOrFn) {
2434
- const result = {};
2435
- for (const item of array) {
2436
- const recordKey = typeof keyOrFn === "function" ? keyOrFn(item) : item[keyOrFn];
2437
- result[recordKey] = item;
2438
- }
2439
- return result;
2440
- }
2441
- function partition(array, predicate) {
2442
- const matched = [];
2443
- const unmatched = [];
2444
- array.forEach((item, index) => {
2445
- if (predicate(item, index)) {
2446
- matched.push(item);
2447
- } else {
2448
- unmatched.push(item);
2449
- }
2450
- });
2451
- return [matched, unmatched];
2452
- }
2453
- function pickItemsInArray(array, key, values) {
2454
- return array.filter((item) => values.includes(item[key]));
2455
- }
2456
- // src/string/index.ts
2457
- function extractNumber(value) {
2458
- if (!value?.trim())
2459
- return;
2460
- const cleanedValue = value.replace(/[^\d.,-]/g, "");
2461
- if (!cleanedValue)
2462
- return;
2463
- const parsedNumber = Number.parseFloat(cleanedValue);
2464
- return Number.isNaN(parsedNumber) ? undefined : parsedNumber;
2465
- }
2466
- function generateId(input) {
2467
- const data = normalizeIdInput(input);
2468
- let hash = 0;
2469
- for (let index = 0;index < data.length; index++) {
2470
- const char = data.charCodeAt(index);
2471
- hash = (hash << 5) - hash + char;
2472
- hash |= 0;
2473
- }
2474
- return Math.abs(hash).toString(16).padStart(8, "0");
2475
- }
2476
- function slugify(value) {
2477
- const source = "àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìłḿñńǹňôöòóœøōõṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;";
2478
- const replacement = "aaaaaaaaaacccddeeeeeeeegghiiiiiilmnnnnooooooooprrsssssttuuuuuuuuuwxyyzzz------";
2479
- const specialCharacterPattern = new RegExp(source.split("").join("|"), "g");
2480
- return value.toString().toLowerCase().replace(/\s+/g, "-").replace(specialCharacterPattern, (character) => replacement.charAt(source.indexOf(character))).replace(/&/g, "-and-").replace(/[^\w-]+/g, "").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
2481
- }
2482
- function normalizeIdInput(input) {
2483
- if (input === undefined)
2484
- return "undefined";
2485
- if (input === null)
2486
- return "null";
2487
- if (typeof input === "string") {
2488
- return decodeURIComponent(input).split("&").sort().join("&");
2489
- }
2490
- if (typeof input === "number" || typeof input === "boolean") {
2491
- return input.toString();
2492
- }
2493
- return JSON.stringify(sortJsonValue(input));
2494
- }
2495
- function sortJsonValue(value) {
2496
- if (value === undefined)
2497
- return null;
2498
- if (Array.isArray(value)) {
2499
- return value.map((item) => sortJsonValue(item));
96
+ defaultHandler = casesOrDefault;
97
+ } else {
98
+ if (typeof keyOrCases !== "string") {
99
+ throw new Error("Invalid typedSwitch call: object mode requires a string discriminant key");
100
+ }
101
+ discriminantKey = keyOrCases;
102
+ const discriminantValue = value[discriminantKey];
103
+ if (typeof discriminantValue !== "string" && typeof discriminantValue !== "number" && typeof discriminantValue !== "boolean") {
104
+ throw new Error(`Invalid discriminant value for key "${discriminantKey}": expected string, number or boolean, received ${typeof discriminantValue}`);
105
+ }
106
+ key = String(discriminantValue);
107
+ cases = casesOrDefault;
108
+ defaultHandler = defaultCase;
2500
109
  }
2501
- if (typeof value === "object" && value !== null) {
2502
- return Object.fromEntries(Object.entries(value).filter(([, itemValue]) => itemValue !== undefined).sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)).map(([key, itemValue]) => [key, sortJsonValue(itemValue)]));
110
+ const handler = Object.hasOwn(cases, key) ? cases[key] : undefined;
111
+ if (handler) {
112
+ return handler(value);
2503
113
  }
2504
- return value;
2505
- }
2506
- // src/promise/index.ts
2507
- function isSuccess(result) {
2508
- return result.error === null;
2509
- }
2510
- function isFailure(result) {
2511
- return result.error !== null;
2512
- }
2513
- function unwrapResult(result) {
2514
- if (isSuccess(result))
2515
- return result.data;
2516
- throw result.error;
2517
- }
2518
- function backgroundPromise(promiseFactory, options = {}) {
2519
- const run = () => {
2520
- promiseFactory().then(() => options.onSuccess?.()).catch((error) => options.onError?.(error));
2521
- };
2522
- if (options.scheduler) {
2523
- options.scheduler(run);
2524
- return;
114
+ if (defaultHandler) {
115
+ return defaultHandler(value);
2525
116
  }
2526
- run();
2527
- }
2528
- function backgroundPromiseSync(promiseFactory, options = {}) {
2529
- backgroundPromise(promiseFactory, {
2530
- ...options,
2531
- scheduler: options.scheduler ?? queueMicrotask
2532
- });
2533
- }
2534
- function promiseTimeout(ms) {
2535
- return new Promise((resolve) => setTimeout(resolve, ms));
117
+ const availableCases = Object.keys(cases).join(", ");
118
+ const availableCasesSuffix = availableCases.length > 0 ? ` Available cases: ${availableCases}` : " Available cases: (none)";
119
+ const contextSuffix = discriminantKey ? ` (discriminant key: "${discriminantKey}")` : "";
120
+ throw new Error(`Unhandled case: ${key}${contextSuffix}.${availableCasesSuffix}`);
2536
121
  }
2537
- async function tryCatch(promise) {
2538
- try {
2539
- const data = await promise;
2540
- return { data, error: null };
2541
- } catch (error) {
2542
- return { data: null, error };
2543
- }
122
+ function assertNever(value, message) {
123
+ throw new Error(message ?? `Unexpected value: ${String(value)}`);
2544
124
  }
2545
125
  // src/cache/index.ts
2546
126
  function cacheFunction(options) {
@@ -2551,84 +131,151 @@ function cacheFunction(options) {
2551
131
  refreshInBackground = false,
2552
132
  cacheKeyArgs,
2553
133
  cacheKeyFn,
2554
- onBackgroundRefreshError
134
+ onBackgroundRefreshError,
135
+ store,
136
+ onStoreError,
137
+ maxEntries
2555
138
  } = options;
139
+ const externalStore = store;
2556
140
  const cache = new Map;
2557
141
  const pendingPromises = new Map;
2558
- const cleanupInterval = setInterval(() => {
2559
- const now = Date.now();
2560
- for (const [key, entry] of cache.entries()) {
2561
- if (now - entry.timestamp >= cacheTimeMs) {
2562
- cache.delete(key);
2563
- }
142
+ const entryLifetimeMs = refreshInBackground ? cacheTimeMs * 2 : cacheTimeMs;
143
+ let cleanupInterval;
144
+ const stopCleanup = () => {
145
+ if (cleanupInterval !== undefined) {
146
+ clearInterval(cleanupInterval);
147
+ cleanupInterval = undefined;
2564
148
  }
2565
- }, Math.min(cacheTimeMs / 2, 5 * 60 * 1000));
2566
- const wrappedFn = (...args) => {
2567
- const keyArgs = cacheKeyFn ? cacheKeyFn(...args) : cacheKeyArgs ? cacheKeyArgs.map((i) => args[i]) : args;
2568
- const key = `${name}:${JSON.stringify(keyArgs)}`;
2569
- const now = Date.now();
2570
- const pending = pendingPromises.get(key);
2571
- if (pending) {
2572
- return pending;
149
+ };
150
+ const ensureCleanup = () => {
151
+ if (cleanupInterval !== undefined) {
152
+ return;
2573
153
  }
2574
- const cached = cache.get(key);
2575
- if (cached) {
2576
- const isCacheFresh = now - cached.timestamp < cacheTimeMs;
2577
- if (!isCacheFresh && !refreshInBackground) {
2578
- cache.delete(key);
2579
- } else {
2580
- if (isCacheFresh && !refreshInBackground) {
2581
- return cached.value;
2582
- }
2583
- if (refreshInBackground) {
2584
- const existingPending = pendingPromises.get(key);
2585
- if (existingPending) {
2586
- return existingPending;
2587
- }
2588
- const backgroundUpdate = fn(...args);
2589
- if (isPromiseLike(backgroundUpdate)) {
2590
- const backgroundPromise2 = backgroundUpdate.then((resolvedValue) => {
2591
- cache.set(key, { value: resolvedValue, timestamp: now });
2592
- pendingPromises.delete(key);
2593
- return resolvedValue;
2594
- }).catch((error) => {
2595
- pendingPromises.delete(key);
2596
- onBackgroundRefreshError?.(error, { name });
2597
- });
2598
- pendingPromises.set(key, backgroundPromise2);
2599
- } else {
2600
- cache.set(key, {
2601
- value: backgroundUpdate,
2602
- timestamp: now
2603
- });
2604
- }
2605
- return cached.value;
2606
- }
2607
- if (isCacheFresh) {
2608
- return cached.value;
154
+ cleanupInterval = setInterval(() => {
155
+ const now = Date.now();
156
+ for (const [key, entry] of cache.entries()) {
157
+ if (now - entry.timestamp >= entryLifetimeMs) {
158
+ cache.delete(key);
2609
159
  }
2610
160
  }
161
+ if (cache.size === 0) {
162
+ stopCleanup();
163
+ }
164
+ }, Math.min(cacheTimeMs / 2, 5 * 60 * 1000));
165
+ cleanupInterval.unref?.();
166
+ };
167
+ const buildKey = (args) => {
168
+ const keyArgs = cacheKeyFn ? cacheKeyFn(...args) : cacheKeyArgs ? cacheKeyArgs.map((i) => args[i]) : args;
169
+ return `${name}:${stableStringify2(keyArgs)}`;
170
+ };
171
+ const isFresh = (entry) => Date.now() - entry.timestamp < cacheTimeMs;
172
+ const servable = (entry) => entry && (refreshInBackground || isFresh(entry)) ? entry : undefined;
173
+ const touch = (key, entry) => {
174
+ cache.delete(key);
175
+ cache.set(key, entry);
176
+ if (maxEntries !== undefined && cache.size > maxEntries) {
177
+ cache.delete(cache.keys().next().value);
178
+ }
179
+ };
180
+ const guardStore = async (operation) => {
181
+ try {
182
+ return await operation();
183
+ } catch (error) {
184
+ onStoreError?.(error, { name });
185
+ return;
186
+ }
187
+ };
188
+ const save = (key, value) => {
189
+ const entry = { value, timestamp: Date.now() };
190
+ if (externalStore) {
191
+ return guardStore(() => externalStore.set(key, entry, entryLifetimeMs));
2611
192
  }
193
+ touch(key, entry);
194
+ ensureCleanup();
195
+ };
196
+ const run = (key, args, stale) => {
2612
197
  const result = fn(...args);
2613
- if (isPromiseLike(result)) {
2614
- const promise = result.then((resolvedValue) => {
2615
- cache.set(key, { value: resolvedValue, timestamp: now });
2616
- pendingPromises.delete(key);
2617
- return resolvedValue;
2618
- }).catch((error) => {
2619
- pendingPromises.delete(key);
198
+ if (!isPromiseLike(result)) {
199
+ save(key, result);
200
+ return result;
201
+ }
202
+ const promise = Promise.resolve(result).then(async (value) => {
203
+ if (pendingPromises.get(key) === promise) {
204
+ await save(key, value);
205
+ }
206
+ return value;
207
+ }, (error) => {
208
+ if (!stale)
2620
209
  throw error;
2621
- });
2622
- pendingPromises.set(key, promise);
2623
- return promise;
210
+ onBackgroundRefreshError?.(error, { name });
211
+ return stale.value;
212
+ }).finally(() => {
213
+ if (pendingPromises.get(key) === promise) {
214
+ pendingPromises.delete(key);
215
+ }
216
+ });
217
+ pendingPromises.set(key, promise);
218
+ return promise;
219
+ };
220
+ const serve = (key, args, entry) => {
221
+ if (!isFresh(entry) && !pendingPromises.has(key)) {
222
+ run(key, args, entry);
2624
223
  }
2625
- cache.set(key, { value: result, timestamp: now });
2626
- return result;
224
+ return entry.value;
225
+ };
226
+ const callWithStore = (cacheStore, key, args) => {
227
+ const pending = pendingPromises.get(key);
228
+ if (pending && !refreshInBackground) {
229
+ return pending;
230
+ }
231
+ return (async () => {
232
+ const entry = await guardStore(() => cacheStore.get(key));
233
+ const cached = servable(entry);
234
+ if (cached) {
235
+ return serve(key, args, cached);
236
+ }
237
+ if (entry) {
238
+ await guardStore(() => cacheStore.delete(key));
239
+ }
240
+ return pendingPromises.get(key) ?? run(key, args);
241
+ })();
242
+ };
243
+ const wrappedFn = (...args) => {
244
+ const key = buildKey(args);
245
+ if (externalStore) {
246
+ return callWithStore(externalStore, key, args);
247
+ }
248
+ const cached = servable(cache.get(key));
249
+ if (cached) {
250
+ touch(key, cached);
251
+ return serve(key, args, cached);
252
+ }
253
+ cache.delete(key);
254
+ return pendingPromises.get(key) ?? run(key, args);
2627
255
  };
2628
256
  wrappedFn.clearCache = () => {
2629
257
  cache.clear();
2630
258
  pendingPromises.clear();
2631
- clearInterval(cleanupInterval);
259
+ stopCleanup();
260
+ const clearStore = externalStore?.clear?.bind(externalStore);
261
+ if (clearStore) {
262
+ guardStore(clearStore);
263
+ }
264
+ };
265
+ wrappedFn.invalidate = (...args) => {
266
+ const key = buildKey(args);
267
+ cache.delete(key);
268
+ pendingPromises.delete(key);
269
+ if (externalStore) {
270
+ guardStore(() => externalStore.delete(key));
271
+ }
272
+ };
273
+ wrappedFn.peek = (...args) => {
274
+ const key = buildKey(args);
275
+ if (externalStore) {
276
+ return guardStore(() => externalStore.get(key)).then((entry) => servable(entry)?.value);
277
+ }
278
+ return servable(cache.get(key))?.value;
2632
279
  };
2633
280
  return wrappedFn;
2634
281
  }
@@ -2650,84 +297,54 @@ class SimpleStateMachine {
2650
297
  }
2651
298
  async getAvailableActions() {
2652
299
  const actionsMap = this.config.stateActionMap[this.getCurrentStatus()] || {};
2653
- const result = {};
2654
- for (const [action, targetState] of Object.entries(actionsMap)) {
2655
- if (!targetState)
2656
- continue;
2657
- const validationResult = await this.validateTransition(targetState, { action });
2658
- result[action] = validationResult;
2659
- }
2660
- return result;
300
+ const entries = Object.entries(actionsMap).filter((entry) => !!entry[1]);
301
+ const results = await Promise.all(entries.map(([action, targetState]) => this.validateTransition(targetState, { action })));
302
+ return Object.fromEntries(entries.map(([action], i) => [action, results[i]]));
2661
303
  }
2662
304
  async getPossibleTransitions() {
2663
305
  const possibleTransitions = this.config.stateTransitions[this.getCurrentStatus()] || [];
2664
306
  const actionsMap = this.config.stateActionMap[this.getCurrentStatus()] || {};
2665
- const result = {};
2666
- for (const targetState of possibleTransitions) {
307
+ const results = await Promise.all(possibleTransitions.map(async (targetState) => {
2667
308
  const actionsToTarget = Object.entries(actionsMap).filter(([, t]) => t === targetState);
2668
309
  if (actionsToTarget.length === 0) {
2669
- result[targetState] = await this.validateTransition(targetState);
2670
- continue;
310
+ return this.validateTransition(targetState);
2671
311
  }
2672
- let lastError = true;
2673
- let anyOk = false;
2674
- for (const [actionKey] of actionsToTarget) {
2675
- const r = await this.validateTransition(targetState, {
2676
- action: actionKey
2677
- });
2678
- if (r === true) {
2679
- anyOk = true;
2680
- break;
2681
- }
2682
- lastError = r;
2683
- }
2684
- result[targetState] = anyOk ? true : lastError;
2685
- }
2686
- return result;
312
+ const rs = await Promise.all(actionsToTarget.map(([action]) => this.validateTransition(targetState, { action })));
313
+ return rs.includes(true) ? true : rs[rs.length - 1];
314
+ }));
315
+ return Object.fromEntries(possibleTransitions.map((targetState, i) => [targetState, results[i]]));
2687
316
  }
2688
- async executeAction(action, data) {
317
+ async canExecute(action) {
2689
318
  const actionsMap = this.config.stateActionMap[this.getCurrentStatus()];
2690
319
  if (!actionsMap) {
2691
- return {
2692
- success: false,
2693
- error: `No actions defined for state '${this.getCurrentStatus()}'`
2694
- };
320
+ return `No actions defined for state '${this.getCurrentStatus()}'`;
2695
321
  }
2696
322
  const targetState = actionsMap[action];
2697
323
  if (!targetState) {
2698
- return {
2699
- success: false,
2700
- error: `Action '${action}' not allowed in state '${this.getCurrentStatus()}'`
2701
- };
324
+ return `Action '${action}' not allowed in state '${this.getCurrentStatus()}'`;
2702
325
  }
2703
- const validationResult = await this.validateTransition(targetState, {
2704
- action
2705
- });
2706
- if (validationResult === true) {
2707
- if (this.config.actions?.[action]) {
2708
- try {
2709
- const result = await this.config.actions[action](this.item, data);
2710
- return {
2711
- success: true,
2712
- newState: targetState,
2713
- result
2714
- };
2715
- } catch (error) {
2716
- return {
2717
- success: false,
2718
- error: error instanceof Error ? error.message : String(error)
2719
- };
2720
- }
326
+ return this.validateTransition(targetState, { action });
327
+ }
328
+ async executeAction(action, data) {
329
+ const fromState = this.getCurrentStatus();
330
+ const validationResult = await this.canExecute(action);
331
+ if (validationResult !== true) {
332
+ return { success: false, error: validationResult };
333
+ }
334
+ const targetState = this.config.stateActionMap[fromState][action];
335
+ try {
336
+ const result = await this.config.actions?.[action]?.(this.item, data);
337
+ await this.config.onTransition?.(this.item, fromState, targetState, action);
338
+ if (this.config.applyTransition) {
339
+ this.item[this.stateKey] = targetState;
2721
340
  }
341
+ return { success: true, newState: targetState, result };
342
+ } catch (error) {
2722
343
  return {
2723
- success: true,
2724
- newState: targetState
344
+ success: false,
345
+ error: error instanceof Error ? error.message : String(error)
2725
346
  };
2726
347
  }
2727
- return {
2728
- success: false,
2729
- error: validationResult
2730
- };
2731
348
  }
2732
349
  async validateTransition(toState, options) {
2733
350
  const action = options?.action;
@@ -2745,7 +362,14 @@ class SimpleStateMachine {
2745
362
  }
2746
363
  const stateValidator = this.config.validators?.[toState];
2747
364
  if (stateValidator) {
2748
- return await stateValidator(this.item, this.getCurrentStatus(), toState, action);
365
+ const stateResult = await stateValidator(this.item, this.getCurrentStatus(), toState, action);
366
+ if (stateResult !== true) {
367
+ return stateResult;
368
+ }
369
+ }
370
+ const actionValidator = action && this.config.actionValidators?.[action];
371
+ if (actionValidator) {
372
+ return await actionValidator(this.item, this.getCurrentStatus(), toState, action);
2749
373
  }
2750
374
  return true;
2751
375
  }
@@ -2753,17 +377,23 @@ class SimpleStateMachine {
2753
377
  return Object.keys(this.config.stateTransitions);
2754
378
  }
2755
379
  getInitialState() {
2756
- return this.getStates()[0];
380
+ return this.config.initialState ?? this.getStates()[0];
2757
381
  }
2758
382
  }
383
+ function createStateMachine(config) {
384
+ return {
385
+ config,
386
+ for: (item, stateKey) => new SimpleStateMachine(config, item, stateKey)
387
+ };
388
+ }
2759
389
  // src/math/linearRegressionTrend.ts
2760
- function linearRegressionTrend(values) {
390
+ function linearRegression(values) {
2761
391
  const n = values.length;
2762
392
  if (n < 2)
2763
- return [];
393
+ return null;
2764
394
  for (const v of values) {
2765
395
  if (!Number.isFinite(v))
2766
- return [];
396
+ return null;
2767
397
  }
2768
398
  let sumX = 0;
2769
399
  let sumY = 0;
@@ -2779,24 +409,155 @@ function linearRegressionTrend(values) {
2779
409
  }
2780
410
  const denom = n * sumX2 - sumX * sumX;
2781
411
  if (denom === 0)
2782
- return [];
412
+ return null;
2783
413
  const slope = (n * sumXY - sumX * sumY) / denom;
2784
414
  const intercept = (sumY - slope * sumX) / n;
2785
- const out = [];
415
+ const mean = sumY / n;
416
+ const fitted = [];
417
+ let ssRes = 0;
418
+ let ssTot = 0;
2786
419
  for (let i = 0;i < n; i++) {
2787
- out.push(intercept + slope * i);
420
+ const y = values[i];
421
+ const f = intercept + slope * i;
422
+ fitted.push(f);
423
+ ssRes += (y - f) ** 2;
424
+ ssTot += (y - mean) ** 2;
2788
425
  }
2789
- return out;
426
+ return { slope, intercept, r2: ssTot === 0 ? 1 : 1 - ssRes / ssTot, fitted };
427
+ }
428
+ function linearRegressionTrend(values) {
429
+ return linearRegression(values)?.fitted ?? [];
430
+ }
431
+ // src/math/scale.ts
432
+ function clamp(value, min, max) {
433
+ return Math.min(max, Math.max(min, value));
434
+ }
435
+ function lerp(start, end, t) {
436
+ return start + (end - start) * t;
437
+ }
438
+ function normalize(value, min, max) {
439
+ if (max <= min)
440
+ return 0;
441
+ return clamp((value - min) / (max - min), 0, 1);
442
+ }
443
+ // src/color/contrast.ts
444
+ function colorFunctionArgs(color) {
445
+ const match = /^(rgb|hsl)a?\(([^()]*)\)$/i.exec(color.trim());
446
+ const args = match?.[2]?.trim().split(/[\s,/]+/);
447
+ if (!match || !args || args.length !== 3 && args.length !== 4) {
448
+ return;
449
+ }
450
+ return { name: match[1].toLowerCase(), args };
451
+ }
452
+ function parseChannel(raw, percentOf) {
453
+ const isPercent = raw.endsWith("%");
454
+ const text = isPercent ? raw.slice(0, -1) : raw;
455
+ const n = text === "" ? Number.NaN : Number(text);
456
+ if (!Number.isFinite(n))
457
+ return;
458
+ return isPercent ? n / 100 * percentOf : n;
459
+ }
460
+ function hslToRgb(h, s, l) {
461
+ const a = s * Math.min(l, 1 - l);
462
+ const f = (n) => {
463
+ const k = (n + h / 30) % 12;
464
+ return (l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1))) * 255;
465
+ };
466
+ return [f(0), f(8), f(4)];
467
+ }
468
+ function parseColor(color) {
469
+ const trimmed = color.trim();
470
+ const hex = /^#([\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i.exec(trimmed)?.[1];
471
+ if (hex) {
472
+ const full = hex.length <= 4 ? hex.replace(/./g, "$&$&") : hex;
473
+ const [r = 0, g = 0, b = 0, a = 255] = [0, 2, 4, 6].map((i) => i < full.length ? Number.parseInt(full.slice(i, i + 2), 16) : undefined);
474
+ return { r, g, b, a: a / 255 };
475
+ }
476
+ const fn = colorFunctionArgs(trimmed);
477
+ if (!fn)
478
+ return;
479
+ const [x = "", y = "", z = "", alpha = "1"] = fn.args;
480
+ const isRgb = fn.name === "rgb";
481
+ const c1 = parseChannel(isRgb ? x : x.replace(/deg$/i, ""), isRgb ? 255 : 360);
482
+ const c2 = parseChannel(y, isRgb ? 255 : 100);
483
+ const c3 = parseChannel(z, isRgb ? 255 : 100);
484
+ const a = parseChannel(alpha, 1);
485
+ if (c1 === undefined || c2 === undefined || c3 === undefined)
486
+ return;
487
+ if (a === undefined)
488
+ return;
489
+ const [r, g, b] = isRgb ? [c1, c2, c3] : hslToRgb((c1 % 360 + 360) % 360, clamp(c2 / 100, 0, 1), clamp(c3 / 100, 0, 1));
490
+ const channel = (v) => Math.round(clamp(v, 0, 255));
491
+ return { r: channel(r), g: channel(g), b: channel(b), a: clamp(a, 0, 1) };
492
+ }
493
+ function toRgba(color) {
494
+ if (typeof color !== "string")
495
+ return color;
496
+ const parsed = parseColor(color);
497
+ if (!parsed)
498
+ throw new TypeError(`Unsupported color: ${color}`);
499
+ return parsed;
500
+ }
501
+ function toHex(color, options = {}) {
502
+ const { r, g, b, a } = toRgba(color);
503
+ const channels = options.alpha ? [r, g, b, a * 255] : [r, g, b];
504
+ return `#${channels.map((v) => Math.round(clamp(v, 0, 255)).toString(16).padStart(2, "0")).join("")}`;
505
+ }
506
+ function toRgbString(color) {
507
+ const { r, g, b, a } = toRgba(color);
508
+ const [rr, gg, bb] = [r, g, b].map((v) => Math.round(clamp(v, 0, 255)));
509
+ return a < 1 ? `rgba(${rr}, ${gg}, ${bb}, ${a})` : `rgb(${rr}, ${gg}, ${bb})`;
510
+ }
511
+ function relativeLuminance(color) {
512
+ const { r, g, b } = toRgba(color);
513
+ const [lr, lg, lb] = [r, g, b].map((v) => {
514
+ const c = clamp(v, 0, 255) / 255;
515
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
516
+ });
517
+ return 0.2126 * lr + 0.7152 * lg + 0.0722 * lb;
518
+ }
519
+ function contrastRatio(a, b) {
520
+ const la = relativeLuminance(a);
521
+ const lb = relativeLuminance(b);
522
+ return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
2790
523
  }
2791
- // src/math/metricsSeriesColors.ts
524
+ function contrastText(background, options = {}) {
525
+ const { light = "#ffffff", dark = "#000000" } = options;
526
+ return contrastRatio(background, light) >= contrastRatio(background, dark) ? light : dark;
527
+ }
528
+ function mix(a, b, weight) {
529
+ const t = clamp(weight, 0, 1);
530
+ const at = (x, y) => x + (y - x) * t;
531
+ return {
532
+ r: at(a.r, b.r),
533
+ g: at(a.g, b.g),
534
+ b: at(a.b, b.b),
535
+ a: at(a.a, b.a)
536
+ };
537
+ }
538
+ var hexOf = (color) => toHex(color, { alpha: color.a < 1 });
539
+ function mixColors(a, b, weight) {
540
+ return hexOf(mix(toRgba(a), toRgba(b), weight));
541
+ }
542
+ function shade(color, amount) {
543
+ const base = toRgba(color);
544
+ const v = amount < 0 ? 0 : 255;
545
+ return hexOf(mix(base, { r: v, g: v, b: v, a: base.a }, Math.abs(amount)));
546
+ }
547
+ // src/color/metricsSeriesColors.ts
2792
548
  var METRICS_SERIES_PALETTE_SIZE = 10;
2793
- function hashStringToColorIndex(str) {
549
+ function hashStringToColorIndex(str, paletteSize = METRICS_SERIES_PALETTE_SIZE) {
2794
550
  let hash = 2166136261;
2795
551
  for (let i = 0;i < str.length; i++) {
2796
552
  hash ^= str.charCodeAt(i);
2797
553
  hash = Math.imul(hash, 16777619);
2798
554
  }
2799
- return Math.abs(hash) % METRICS_SERIES_PALETTE_SIZE;
555
+ return Math.abs(hash) % paletteSize;
556
+ }
557
+ function pickFromPalette(seed, palette) {
558
+ if (palette.length === 0)
559
+ throw new RangeError("palette is empty");
560
+ return palette[hashStringToColorIndex(seed, palette.length)];
2800
561
  }
2801
562
  function circularHueDistance(a, b, paletteSize) {
2802
563
  const diff = Math.abs(a - b);
@@ -2823,21 +584,20 @@ function seriesColorKey(label, key) {
2823
584
  return fromLabel;
2824
585
  return key.trim() || key;
2825
586
  }
2826
- function resolveSeriesColorMap(keys) {
587
+ function resolveSeriesColorMap(keys, paletteSize = METRICS_SERIES_PALETTE_SIZE) {
2827
588
  const result = new Map;
2828
589
  const uniqueKeys = [...new Set(keys)];
2829
590
  if (uniqueKeys.length === 0)
2830
591
  return result;
2831
- const paletteSize = METRICS_SERIES_PALETTE_SIZE;
2832
592
  if (uniqueKeys.length === 1) {
2833
593
  const only = uniqueKeys[0];
2834
- result.set(only, hashStringToColorIndex(only));
594
+ result.set(only, hashStringToColorIndex(only, paletteSize));
2835
595
  return result;
2836
596
  }
2837
597
  const usedIndices = new Set;
2838
598
  const entries = uniqueKeys.map((key) => ({
2839
599
  key,
2840
- preferred: hashStringToColorIndex(key)
600
+ preferred: hashStringToColorIndex(key, paletteSize)
2841
601
  }));
2842
602
  for (const entry of entries) {
2843
603
  if (!usedIndices.has(entry.preferred)) {
@@ -2859,35 +619,25 @@ function resolveSeriesColorMap(keys) {
2859
619
  }
2860
620
  return result;
2861
621
  }
2862
- function createResolveColorsByKeys(keys, getSeriesColor, getSeriesHoverColor) {
2863
- const colorMap = resolveSeriesColorMap(keys);
622
+ function createResolveColorsByKeys(keys, getSeriesColor, getSeriesHoverColor, paletteSize = METRICS_SERIES_PALETTE_SIZE) {
623
+ const colorMap = resolveSeriesColorMap(keys, paletteSize);
624
+ const indexOf = (key) => colorMap.get(key) ?? hashStringToColorIndex(key, paletteSize);
2864
625
  return {
2865
- getColor: (key) => getSeriesColor(colorMap.get(key) ?? hashStringToColorIndex(key)),
2866
- getHoverColor: (key) => getSeriesHoverColor(colorMap.get(key) ?? hashStringToColorIndex(key))
626
+ getColor: (key) => getSeriesColor(indexOf(key)),
627
+ getHoverColor: (key) => getSeriesHoverColor(indexOf(key))
2867
628
  };
2868
629
  }
2869
- function clamp(value, min, max) {
2870
- return Math.min(max, Math.max(min, value));
2871
- }
2872
630
  function withAlpha(color, alpha) {
2873
631
  const trimmed = color.trim();
2874
- if (trimmed.startsWith("#")) {
2875
- const hex = trimmed.slice(1);
2876
- const normalized = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
2877
- if (normalized.length === 6) {
2878
- const r = Number.parseInt(normalized.slice(0, 2), 16);
2879
- const g = Number.parseInt(normalized.slice(2, 4), 16);
2880
- const b = Number.parseInt(normalized.slice(4, 6), 16);
2881
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
2882
- }
2883
- }
2884
- if (trimmed.startsWith("rgb(")) {
2885
- return trimmed.replace("rgb(", "rgba(").replace(")", `, ${alpha})`);
632
+ const rgba = parseColor(trimmed);
633
+ const fn = rgba && colorFunctionArgs(trimmed);
634
+ if (fn?.name === "hsl") {
635
+ const [h, s, l] = fn.args;
636
+ return `hsla(${h}, ${s}, ${l}, ${alpha})`;
2886
637
  }
2887
- if (trimmed.startsWith("rgba(")) {
2888
- return trimmed.replace(/,\s*[\d.]+\)$/, `, ${alpha})`);
2889
- }
2890
- return trimmed;
638
+ if (rgba)
639
+ return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${alpha})`;
640
+ return `color-mix(in srgb, ${trimmed} ${alpha * 100}%, transparent)`;
2891
641
  }
2892
642
  function getHeatmapCellStyle(params) {
2893
643
  const {
@@ -2910,136 +660,440 @@ function getHeatmapCellStyle(params) {
2910
660
  backgroundColor: withAlpha(neutralColor ?? baseColor, 0.32)
2911
661
  };
2912
662
  }
2913
- const normalized = clamp((value - min) / (max - min), 0, 1);
2914
- const alpha = minAlpha + (maxAlpha - minAlpha) * normalized;
2915
663
  return {
2916
- backgroundColor: withAlpha(baseColor, alpha)
664
+ backgroundColor: withAlpha(baseColor, lerp(minAlpha, maxAlpha, normalize(value, min, max)))
2917
665
  };
2918
666
  }
2919
667
  // src/date/index.ts
2920
- function getPreviousReportPeriod(periodType, referenceDate = new Date) {
2921
- const month = referenceDate.getMonth();
2922
- const year = referenceDate.getFullYear();
2923
- switch (periodType) {
2924
- case "MONTHLY": {
2925
- const prevMonth = month === 0 ? 11 : month - 1;
2926
- const prevYear = month === 0 ? year - 1 : year;
2927
- return {
2928
- start: new Date(prevYear, prevMonth, 1),
2929
- end: new Date(year, month, 0)
2930
- };
2931
- }
2932
- case "QUARTERLY": {
2933
- const qStart = Math.floor(month / 3) * 3;
2934
- const prevQStart = qStart === 0 ? 9 : qStart - 3;
2935
- const prevQYear = qStart === 0 ? year - 1 : year;
2936
- return {
2937
- start: new Date(prevQYear, prevQStart, 1),
2938
- end: new Date(prevQYear, prevQStart + 3, 0)
2939
- };
2940
- }
2941
- case "YEARLY": {
2942
- return {
2943
- start: new Date(year - 1, 0, 1),
2944
- end: new Date(year - 1, 11, 31)
2945
- };
2946
- }
668
+ var MONTHS_PER_PERIOD = { MONTHLY: 1, QUARTERLY: 3, YEARLY: 12 };
669
+ function ymd(date, utc = false) {
670
+ return utc ? [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()] : [date.getFullYear(), date.getMonth(), date.getDate()];
671
+ }
672
+ function startOfDay(y, m, d, utc = false) {
673
+ return utc ? new Date(Date.UTC(y, m, d)) : new Date(y, m, d);
674
+ }
675
+ function addPeriod(date, type, n, options = {}) {
676
+ const { utc = false } = options;
677
+ let [y, m, d] = ymd(date, utc);
678
+ if (type === "DAILY" || type === "WEEKLY") {
679
+ d += n * (type === "WEEKLY" ? 7 : 1);
680
+ } else {
681
+ m += n * MONTHS_PER_PERIOD[type];
682
+ d = Math.min(d, new Date(Date.UTC(y, m + 1, 0)).getUTCDate());
2947
683
  }
684
+ const out = new Date(date);
685
+ if (utc)
686
+ out.setUTCFullYear(y, m, d);
687
+ else
688
+ out.setFullYear(y, m, d);
689
+ return out;
690
+ }
691
+ function getPeriod(type, referenceDate = new Date, offset = 0, options = {}) {
692
+ const { utc = false, weekStartsOn = 1 } = options;
693
+ const [y, m, d] = ymd(referenceDate, utc);
694
+ const weekday = utc ? referenceDate.getUTCDay() : referenceDate.getDay();
695
+ const anchor = {
696
+ DAILY: () => startOfDay(y, m, d, utc),
697
+ WEEKLY: () => startOfDay(y, m, d - (weekday - weekStartsOn + 7) % 7, utc),
698
+ MONTHLY: () => startOfDay(y, m, 1, utc),
699
+ QUARTERLY: () => startOfDay(y, m - m % 3, 1, utc),
700
+ YEARLY: () => startOfDay(y, 0, 1, utc)
701
+ }[type]();
702
+ const [ey, em, ed] = ymd(addPeriod(anchor, type, offset + 1, { utc }), utc);
703
+ return {
704
+ start: addPeriod(anchor, type, offset, { utc }),
705
+ end: startOfDay(ey, em, ed - 1, utc)
706
+ };
707
+ }
708
+ function getPreviousReportPeriod(periodType, referenceDate = new Date) {
709
+ return getPeriod(periodType, referenceDate, -1);
2948
710
  }
2949
- function formatPeriodLabel(start, end, includeDay = false) {
711
+ function formatPeriodLabel(start, end, options = false) {
712
+ const {
713
+ includeDay = false,
714
+ locale = "en-GB",
715
+ separator = " — ",
716
+ collapse = false,
717
+ timeZone
718
+ } = typeof options === "boolean" ? { includeDay: options } : options;
2950
719
  const s = start instanceof Date ? start : new Date(start);
2951
720
  const e = end instanceof Date ? end : new Date(end);
2952
- const opts = {
721
+ const format = new Intl.DateTimeFormat(locale, {
2953
722
  year: "numeric",
2954
723
  month: "long",
2955
- ...includeDay && { day: "numeric" }
724
+ ...includeDay && { day: "numeric" },
725
+ timeZone
726
+ });
727
+ return collapse ? format.formatRange(s, e) : `${format.format(s)}${separator}${format.format(e)}`;
728
+ }
729
+ // src/object/index.ts
730
+ function typedKeys(object) {
731
+ return Object.keys(object);
732
+ }
733
+ function typedEntries(object) {
734
+ return Object.entries(object);
735
+ }
736
+ function typedFromEntries(entries) {
737
+ return Object.fromEntries(entries);
738
+ }
739
+ function recordFromKeys(keys, fn) {
740
+ return typedFromEntries(keys.map((key) => [key, fn(key)]));
741
+ }
742
+ function mapValues(object, fn) {
743
+ return typedFromEntries(typedEntries(object).map(([key, value]) => [key, fn(value, key)]));
744
+ }
745
+ function pick(object, keys) {
746
+ const result = {};
747
+ for (const key of keys) {
748
+ if (key in object)
749
+ result[key] = object[key];
750
+ }
751
+ return result;
752
+ }
753
+ function omit(object, keys) {
754
+ const result = { ...object };
755
+ for (const key of keys)
756
+ delete result[key];
757
+ return result;
758
+ }
759
+ var UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
760
+ function toPath(path) {
761
+ if (typeof path !== "string")
762
+ return path;
763
+ return path === "" ? [] : path.split(".");
764
+ }
765
+ function getAtPath(object, path) {
766
+ let current = object;
767
+ for (const key of toPath(path)) {
768
+ if (current === null || typeof current !== "object")
769
+ return;
770
+ current = current[key];
771
+ }
772
+ return current;
773
+ }
774
+ function setAtPath(object, path, value) {
775
+ const keys = toPath(path);
776
+ if (keys.length === 0)
777
+ throw new Error("Path must not be empty");
778
+ for (const key of keys) {
779
+ if (UNSAFE_KEYS.has(String(key))) {
780
+ throw new Error(`Unsafe path segment: ${key}`);
781
+ }
782
+ }
783
+ let current = object;
784
+ for (let index = 0;index < keys.length - 1; index++) {
785
+ const key = keys[index];
786
+ let next = current[key];
787
+ if (next === null || typeof next !== "object") {
788
+ next = /^\d+$/.test(String(keys[index + 1])) ? [] : {};
789
+ current[key] = next;
790
+ }
791
+ current = next;
792
+ }
793
+ current[keys.at(-1)] = value;
794
+ }
795
+ // src/function/index.ts
796
+ function debounce(fn, waitMs, options = {}) {
797
+ let timer;
798
+ let maxTimer;
799
+ let lastArgs;
800
+ const cancel = () => {
801
+ clearTimeout(timer);
802
+ clearTimeout(maxTimer);
803
+ timer = maxTimer = lastArgs = undefined;
804
+ };
805
+ const flush = () => {
806
+ const args = lastArgs;
807
+ cancel();
808
+ if (args)
809
+ fn(...args);
810
+ };
811
+ const debounced = (...args) => {
812
+ const idle = timer === undefined;
813
+ clearTimeout(timer);
814
+ timer = setTimeout(flush, waitMs);
815
+ if (options.maxWaitMs !== undefined && maxTimer === undefined) {
816
+ maxTimer = setTimeout(flush, options.maxWaitMs);
817
+ }
818
+ if (idle && options.leading)
819
+ fn(...args);
820
+ else
821
+ lastArgs = args;
822
+ };
823
+ return Object.assign(debounced, {
824
+ cancel,
825
+ flush,
826
+ pending: () => lastArgs !== undefined
827
+ });
828
+ }
829
+ function keyedDebounce(fn, waitMs) {
830
+ const byKey = new Map;
831
+ const each = (key, action) => {
832
+ const targets = key === undefined ? [...byKey.values()] : [byKey.get(key)];
833
+ for (const debounced of targets)
834
+ if (debounced)
835
+ action(debounced);
836
+ };
837
+ return {
838
+ call(key, ...args) {
839
+ let debounced = byKey.get(key);
840
+ if (!debounced) {
841
+ debounced = debounce((...latest) => {
842
+ byKey.delete(key);
843
+ fn(key, ...latest);
844
+ }, waitMs);
845
+ byKey.set(key, debounced);
846
+ }
847
+ debounced(...args);
848
+ },
849
+ cancel(key) {
850
+ each(key, (debounced) => debounced.cancel());
851
+ if (key === undefined)
852
+ byKey.clear();
853
+ else
854
+ byKey.delete(key);
855
+ },
856
+ flush(key) {
857
+ each(key, (debounced) => debounced.flush());
858
+ }
859
+ };
860
+ }
861
+ function throttle(fn, intervalMs, options = {}) {
862
+ const { trailing = true } = options;
863
+ let timer;
864
+ let trailingArgs;
865
+ const invoke = (args) => {
866
+ timer = setTimeout(() => {
867
+ timer = undefined;
868
+ const next = trailingArgs;
869
+ trailingArgs = undefined;
870
+ if (next)
871
+ invoke(next);
872
+ }, intervalMs);
873
+ fn(...args);
874
+ };
875
+ const throttled = (...args) => {
876
+ if (timer === undefined)
877
+ invoke(args);
878
+ else if (trailing)
879
+ trailingArgs = args;
880
+ };
881
+ return Object.assign(throttled, {
882
+ cancel: () => {
883
+ clearTimeout(timer);
884
+ timer = trailingArgs = undefined;
885
+ }
886
+ });
887
+ }
888
+ function once(fn) {
889
+ let called = false;
890
+ let result;
891
+ return (...args) => {
892
+ if (!called) {
893
+ called = true;
894
+ result = fn(...args);
895
+ }
896
+ return result;
2956
897
  };
2957
- return `${s.toLocaleDateString("en-GB", opts)} — ${e.toLocaleDateString("en-GB", opts)}`;
2958
898
  }
2959
- // src/url/index.ts
2960
- function getDomainFaviconUrl(domain, size = 128) {
2961
- return `https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=${size}`;
899
+ function createHeartbeat(options) {
900
+ const {
901
+ now = Date.now,
902
+ setTimeout: schedule = (callback, ms) => setTimeout(callback, ms),
903
+ clearTimeout: unschedule = (timer) => clearTimeout(timer)
904
+ } = options;
905
+ let active = false;
906
+ let lastSentAt = 0;
907
+ let idleTimer;
908
+ const stop = () => {
909
+ if (idleTimer !== undefined)
910
+ unschedule(idleTimer);
911
+ idleTimer = undefined;
912
+ if (!active)
913
+ return;
914
+ active = false;
915
+ options.onStop?.();
916
+ };
917
+ return {
918
+ activity() {
919
+ const time = now();
920
+ if (!active || time - lastSentAt >= options.intervalMs) {
921
+ active = true;
922
+ lastSentAt = time;
923
+ options.send();
924
+ }
925
+ if (idleTimer !== undefined)
926
+ unschedule(idleTimer);
927
+ idleTimer = schedule(stop, options.idleMs);
928
+ },
929
+ stop
930
+ };
931
+ }
932
+ // src/emitter/index.ts
933
+ function createEmitter() {
934
+ const listeners = new Map;
935
+ const add = (event, listener, once) => {
936
+ const map = listeners.get(event) ?? new Map;
937
+ listeners.set(event, map);
938
+ map.set(listener, once);
939
+ return () => {
940
+ map.delete(listener);
941
+ };
942
+ };
943
+ return {
944
+ on: (event, listener) => add(event, listener, false),
945
+ once: (event, listener) => add(event, listener, true),
946
+ off(event, listener) {
947
+ listeners.get(event)?.delete(listener);
948
+ },
949
+ emit(event, ...[payload]) {
950
+ const map = listeners.get(event);
951
+ if (!map)
952
+ return;
953
+ const errors = [];
954
+ for (const [listener, once] of [...map]) {
955
+ if (!map.has(listener))
956
+ continue;
957
+ if (once)
958
+ map.delete(listener);
959
+ try {
960
+ listener(payload);
961
+ } catch (error) {
962
+ errors.push(error);
963
+ }
964
+ }
965
+ if (errors.length === 1)
966
+ throw errors[0];
967
+ if (errors.length > 1) {
968
+ throw new AggregateError(errors, `${errors.length} listeners threw for "${String(event)}"`);
969
+ }
970
+ },
971
+ clear(event) {
972
+ if (event === undefined)
973
+ listeners.clear();
974
+ else
975
+ listeners.delete(event);
976
+ },
977
+ listenerCount: (event) => listeners.get(event)?.size ?? 0
978
+ };
2962
979
  }
2963
980
  export {
2964
- zodToTypeString,
2965
- zodToExample,
2966
- zodMinMaxFilter,
2967
- zSingleOrArray,
2968
- withAlpha,
2969
- viteSecretSetPlugin,
2970
- unwrapResult,
2971
- typedSwitch,
2972
- tryCatch,
2973
- toGteLteFilter,
2974
- terminalColors,
2975
- slugify,
2976
- seriesColorKey,
2977
- resolveSeriesColorMap,
2978
- promiseTimeout,
2979
- processEnvLoader,
2980
- pickItemsInArray,
2981
- partition,
2982
- normalizeSingleOrArray,
2983
- logOperationSummary,
2984
- logBanner,
2985
- loadInfisicalSecrets,
2986
- linearRegressionTrend,
2987
- keyBy,
2988
- jwtVerify,
2989
- jwtSign,
2990
- jsonToZodSchemaMapper,
2991
- isSuccess,
2992
- isResponseValidationError,
2993
- isRequestValidationError,
2994
- isRequestTimeoutError,
2995
- isRequestAbortedError,
2996
- isNetworkError,
2997
- isHttpResponseError,
2998
- isFailure,
2999
- isConfigError,
3000
- isApiError,
3001
- isActionError,
3002
- infisicalLoader,
3003
- hashStringToColorIndex,
3004
- groupBy,
3005
- getViteDefine,
3006
- getUniqueValuesByKey,
3007
- getUniqueValues,
3008
- getSecretEnvironment,
3009
- getPreviousReportPeriod,
3010
- getHeatmapCellStyle,
3011
- getDomainSitemap,
3012
- getDomainFaviconUrl,
3013
- generateId,
3014
- formatPeriodLabel,
3015
- findArrayDifferenceByKey,
3016
- fetchInfisicalSecrets,
3017
- extractNumber,
3018
- defineSecretSet,
3019
- defineAction,
3020
- createZId,
3021
- createResolveColorsByKeys,
3022
- createCoolLogger,
3023
- createApiClient,
3024
- compact,
3025
- colorize,
3026
- cloudflareWorkerEnvLoader,
3027
- chunkArray,
3028
- cacheFunction,
3029
- backgroundPromiseSync,
3030
- backgroundPromise,
3031
- TimeoutError,
3032
- SimpleStateMachine,
3033
- ResponseValidationError,
3034
- RequestValidationError,
3035
- RequestTimeoutError,
3036
- RequestAbortedError,
3037
- PriorityQueue,
3038
- NetworkError,
981
+ InvariantError2 as InvariantError,
3039
982
  METRICS_SERIES_PALETTE_SIZE,
3040
- HttpResponseError,
3041
- DEFAULT_INFISICAL_SITE_URL,
3042
- ConfigError,
3043
- ApiError,
3044
- ActionError
983
+ PromiseTimeoutError2 as PromiseTimeoutError,
984
+ SimpleStateMachine,
985
+ addPeriod,
986
+ anySignal2 as anySignal,
987
+ assertNever,
988
+ backgroundPromise2 as backgroundPromise,
989
+ backgroundPromiseSync2 as backgroundPromiseSync,
990
+ buildMailto2 as buildMailto,
991
+ buildQueryString2 as buildQueryString,
992
+ buildUrl2 as buildUrl,
993
+ cacheFunction,
994
+ chunkArray2 as chunkArray,
995
+ clamp,
996
+ compact2 as compact,
997
+ contrastRatio,
998
+ contrastText,
999
+ countBy2 as countBy,
1000
+ createCache2 as createCache,
1001
+ createEmitter,
1002
+ createHeartbeat,
1003
+ createLatestGuard2 as createLatestGuard,
1004
+ createResolveColorsByKeys,
1005
+ createStateMachine,
1006
+ debounce,
1007
+ ensureLeadingSlash2 as ensureLeadingSlash,
1008
+ err2 as err,
1009
+ escapeRegExp2 as escapeRegExp,
1010
+ exponentialBackoff2 as exponentialBackoff,
1011
+ extractNumber2 as extractNumber,
1012
+ findArrayDifferenceByKey2 as findArrayDifferenceByKey,
1013
+ foldForSearch2 as foldForSearch,
1014
+ formatPeriodLabel,
1015
+ generateId2 as generateId,
1016
+ getAtPath,
1017
+ getDomainFaviconUrl2 as getDomainFaviconUrl,
1018
+ getErrorMessage2 as getErrorMessage,
1019
+ getHeatmapCellStyle,
1020
+ getPeriod,
1021
+ getPreviousReportPeriod,
1022
+ getUniqueValues2 as getUniqueValues,
1023
+ getUniqueValuesByKey2 as getUniqueValuesByKey,
1024
+ groupBy2 as groupBy,
1025
+ hasKey2 as hasKey,
1026
+ hashStringToColorIndex,
1027
+ initials2 as initials,
1028
+ invariant2 as invariant,
1029
+ isBoolean2 as isBoolean,
1030
+ isDefined2 as isDefined,
1031
+ isFailure2 as isFailure,
1032
+ isFunction2 as isFunction,
1033
+ isNonEmpty2 as isNonEmpty,
1034
+ isNumber2 as isNumber,
1035
+ isOneOf2 as isOneOf,
1036
+ isPlainObject2 as isPlainObject,
1037
+ isRecord2 as isRecord,
1038
+ isString2 as isString,
1039
+ isSuccess2 as isSuccess,
1040
+ isTruthy2 as isTruthy,
1041
+ keyBy2 as keyBy,
1042
+ keyedDebounce,
1043
+ lerp,
1044
+ linearRegression,
1045
+ linearRegressionTrend,
1046
+ mapValues,
1047
+ matchesSearch2 as matchesSearch,
1048
+ mixColors,
1049
+ must2 as must,
1050
+ nonEmpty2 as nonEmpty,
1051
+ normalize,
1052
+ normalizeDomain2 as normalizeDomain,
1053
+ normalizeWhitespace2 as normalizeWhitespace,
1054
+ ok2 as ok,
1055
+ omit,
1056
+ once,
1057
+ pMap2 as pMap,
1058
+ parseColor,
1059
+ parseRetryAfter2 as parseRetryAfter,
1060
+ partition2 as partition,
1061
+ pick,
1062
+ pickFromPalette,
1063
+ pickItemsInArray2 as pickItemsInArray,
1064
+ promiseTimeout2 as promiseTimeout,
1065
+ raceAbort2 as raceAbort,
1066
+ range2 as range,
1067
+ recordFromKeys,
1068
+ relativeLuminance,
1069
+ replacePathParams2 as replacePathParams,
1070
+ resolveSeriesColorMap,
1071
+ retry2 as retry,
1072
+ safeJsonParse2 as safeJsonParse,
1073
+ seriesColorKey,
1074
+ setAtPath,
1075
+ sha256Id2 as sha256Id,
1076
+ shade,
1077
+ slugify2 as slugify,
1078
+ sortBy2 as sortBy,
1079
+ stableStringify2 as stableStringify,
1080
+ startTimer2 as startTimer,
1081
+ sumBy2 as sumBy,
1082
+ throttle,
1083
+ timed2 as timed,
1084
+ timeoutSignal2 as timeoutSignal,
1085
+ toArray2 as toArray,
1086
+ toError2 as toError,
1087
+ toHex,
1088
+ toRgbString,
1089
+ trimTrailingSlash2 as trimTrailingSlash,
1090
+ truncate2 as truncate,
1091
+ tryCatch2 as tryCatch,
1092
+ typedEntries,
1093
+ typedFromEntries,
1094
+ typedKeys,
1095
+ typedSwitch,
1096
+ unwrapResult2 as unwrapResult,
1097
+ withAlpha,
1098
+ withTimeout2 as withTimeout
3045
1099
  };