hanzio 3.0.0 → 3.1.1

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 (112) hide show
  1. package/README.md +114 -3
  2. package/dist/api-wrapper/connection-auth.d.ts +61 -0
  3. package/dist/cli/fields.d.ts +30 -0
  4. package/dist/cli/index.d.ts +122 -0
  5. package/dist/format/index.d.ts +91 -0
  6. package/dist/format/phone.d.ts +19 -0
  7. package/dist/http/index.d.ts +14 -0
  8. package/dist/i18n/catalog.d.ts +47 -0
  9. package/dist/i18n/check.d.ts +45 -0
  10. package/dist/i18n/cli.d.ts +2 -0
  11. package/dist/i18n/content-rules.d.ts +55 -0
  12. package/dist/i18n/i18next.d.ts +39 -0
  13. package/dist/i18n/index.d.ts +16 -1
  14. package/dist/i18n/locales.d.ts +62 -0
  15. package/dist/i18n/vite.d.ts +16 -0
  16. package/dist/i18n/vue.d.ts +93 -0
  17. package/dist/{index-kj1phgrx.js → index-29mmh343.js} +24 -1
  18. package/dist/{index-zbj9s3s3.js → index-2kz392vw.js} +1 -1
  19. package/dist/index-5n2e326q.js +409 -0
  20. package/dist/{index-hy7kbb99.js → index-5tzqfmnj.js} +1 -1
  21. package/dist/{index-0zvtcbzy.js → index-6f2w90pp.js} +69 -1
  22. package/dist/index-mq2qgc20.js +116 -0
  23. package/dist/index-najbyzpr.js +99 -0
  24. package/dist/index-nfvq3zax.js +475 -0
  25. package/dist/index-ww09bm49.js +250 -0
  26. package/dist/iso/countries.d.ts +262 -0
  27. package/dist/iso/currencies.d.ts +165 -0
  28. package/dist/iso/index.d.ts +4 -0
  29. package/dist/iso/languages.d.ts +195 -0
  30. package/dist/iso/phone-language.d.ts +5 -0
  31. package/dist/promise/index.d.ts +31 -0
  32. package/dist/redis/client.d.ts +49 -0
  33. package/dist/redis/concurrency-limit.d.ts +63 -0
  34. package/dist/redis/index.d.ts +3 -0
  35. package/dist/redis/lua-script.d.ts +13 -0
  36. package/dist/secrets/infisical-identity-file.d.ts +12 -0
  37. package/dist/src/api-wrapper/connection-auth.js +82 -0
  38. package/dist/src/api-wrapper/index.js +1 -1
  39. package/dist/src/cli/index.js +10 -0
  40. package/dist/src/format/index.js +79 -2
  41. package/dist/src/format/phone.js +21 -0
  42. package/dist/src/http/index.js +69 -0
  43. package/dist/src/i18n/check.js +15 -0
  44. package/dist/src/i18n/cli.js +71 -0
  45. package/dist/src/i18n/i18next.js +48 -0
  46. package/dist/src/i18n/index.js +16 -34
  47. package/dist/src/i18n/vite.js +25 -0
  48. package/dist/src/i18n/vue.js +51 -0
  49. package/dist/src/index.js +14 -4
  50. package/dist/src/iso/index.js +655 -0
  51. package/dist/src/redis/index.js +577 -0
  52. package/dist/src/secrets/index.js +78 -35
  53. package/dist/src/sitemap/index.js +1 -1
  54. package/dist/src/storage/index.js +8 -117
  55. package/dist/src/testing/index.js +348 -0
  56. package/dist/src/zod/index.js +20 -253
  57. package/dist/string/index.d.ts +21 -0
  58. package/dist/testing/connection-auth-contract.d.ts +43 -0
  59. package/dist/testing/helpers.d.ts +26 -0
  60. package/dist/testing/index.d.ts +5 -0
  61. package/dist/testing/module-mocker.d.ts +30 -0
  62. package/dist/testing/prisma.d.ts +30 -0
  63. package/dist/testing/window.d.ts +18 -0
  64. package/dist/zod/index.d.ts +10 -0
  65. package/dist/zod/introspect.d.ts +2 -1
  66. package/package.json +96 -2
  67. package/src/api-wrapper/README.md +52 -0
  68. package/src/api-wrapper/connection-auth.ts +142 -0
  69. package/src/cli/README.md +220 -0
  70. package/src/cli/fields.ts +213 -0
  71. package/src/cli/index.ts +533 -0
  72. package/src/format/README.md +82 -2
  73. package/src/format/index.ts +148 -0
  74. package/src/format/phone.ts +43 -0
  75. package/src/http/README.md +25 -0
  76. package/src/http/index.ts +94 -0
  77. package/src/i18n/README.md +206 -3
  78. package/src/i18n/catalog.ts +139 -0
  79. package/src/i18n/check.ts +376 -0
  80. package/src/i18n/cli.ts +90 -0
  81. package/src/i18n/content-rules.ts +179 -0
  82. package/src/i18n/i18next.ts +89 -0
  83. package/src/i18n/index.ts +34 -0
  84. package/src/i18n/locales.ts +135 -0
  85. package/src/i18n/vite.ts +40 -0
  86. package/src/i18n/vue.ts +82 -0
  87. package/src/index.ts +1 -1
  88. package/src/iso/README.md +44 -0
  89. package/src/iso/countries.ts +272 -0
  90. package/src/iso/currencies.ts +172 -0
  91. package/src/iso/index.ts +8 -0
  92. package/src/iso/languages.ts +208 -0
  93. package/src/iso/phone-language.ts +46 -0
  94. package/src/promise/index.ts +100 -0
  95. package/src/redis/README.md +112 -0
  96. package/src/redis/client.ts +239 -0
  97. package/src/redis/concurrency-limit.ts +591 -0
  98. package/src/redis/index.ts +15 -0
  99. package/src/redis/lua-script.ts +43 -0
  100. package/src/secrets/README.md +5 -1
  101. package/src/secrets/infisical-identity-file.ts +69 -0
  102. package/src/secrets/infisical.ts +18 -3
  103. package/src/string/index.ts +59 -0
  104. package/src/testing/README.md +119 -0
  105. package/src/testing/connection-auth-contract.ts +303 -0
  106. package/src/testing/helpers.ts +41 -0
  107. package/src/testing/index.ts +12 -0
  108. package/src/testing/module-mocker.ts +50 -0
  109. package/src/testing/prisma.ts +78 -0
  110. package/src/testing/window.ts +119 -0
  111. package/src/zod/index.ts +20 -0
  112. package/src/zod/introspect.ts +1 -1
@@ -0,0 +1,195 @@
1
+ /** ISO 639-1 two-letter language codes (lowercase) with English names. */
2
+ export declare const languageNames: {
3
+ readonly aa: "Afar";
4
+ readonly ab: "Abkhazian";
5
+ readonly ae: "Avestan";
6
+ readonly af: "Afrikaans";
7
+ readonly ak: "Akan";
8
+ readonly am: "Amharic";
9
+ readonly an: "Aragonese";
10
+ readonly ar: "Arabic";
11
+ readonly as: "Assamese";
12
+ readonly av: "Avaric";
13
+ readonly ay: "Aymara";
14
+ readonly az: "Azerbaijani";
15
+ readonly ba: "Bashkir";
16
+ readonly be: "Belarusian";
17
+ readonly bg: "Bulgarian";
18
+ readonly bi: "Bislama";
19
+ readonly bm: "Bambara";
20
+ readonly bn: "Bangla";
21
+ readonly bo: "Tibetan";
22
+ readonly br: "Breton";
23
+ readonly bs: "Bosnian";
24
+ readonly ca: "Catalan";
25
+ readonly ce: "Chechen";
26
+ readonly ch: "Chamorro";
27
+ readonly co: "Corsican";
28
+ readonly cr: "Cree";
29
+ readonly cs: "Czech";
30
+ readonly cu: "Church Slavic";
31
+ readonly cv: "Chuvash";
32
+ readonly cy: "Welsh";
33
+ readonly da: "Danish";
34
+ readonly de: "German";
35
+ readonly dv: "Dhivehi";
36
+ readonly dz: "Dzongkha";
37
+ readonly ee: "Ewe";
38
+ readonly el: "Greek";
39
+ readonly en: "English";
40
+ readonly eo: "Esperanto";
41
+ readonly es: "Spanish";
42
+ readonly et: "Estonian";
43
+ readonly eu: "Basque";
44
+ readonly fa: "Persian";
45
+ readonly ff: "Fula";
46
+ readonly fi: "Finnish";
47
+ readonly fj: "Fijian";
48
+ readonly fo: "Faroese";
49
+ readonly fr: "French";
50
+ readonly fy: "Western Frisian";
51
+ readonly ga: "Irish";
52
+ readonly gd: "Scottish Gaelic";
53
+ readonly gl: "Galician";
54
+ readonly gn: "Guarani";
55
+ readonly gu: "Gujarati";
56
+ readonly gv: "Manx";
57
+ readonly ha: "Hausa";
58
+ readonly he: "Hebrew";
59
+ readonly hi: "Hindi";
60
+ readonly ho: "Hiri Motu";
61
+ readonly hr: "Croatian";
62
+ readonly ht: "Haitian Creole";
63
+ readonly hu: "Hungarian";
64
+ readonly hy: "Armenian";
65
+ readonly hz: "Herero";
66
+ readonly ia: "Interlingua";
67
+ readonly id: "Indonesian";
68
+ readonly ie: "Interlingue";
69
+ readonly ig: "Igbo";
70
+ readonly ii: "Liangshan Yi";
71
+ readonly ik: "Inupiaq";
72
+ readonly io: "Ido";
73
+ readonly is: "Icelandic";
74
+ readonly it: "Italian";
75
+ readonly iu: "Inuktitut";
76
+ readonly ja: "Japanese";
77
+ readonly jv: "Javanese";
78
+ readonly ka: "Georgian";
79
+ readonly kg: "Kongo";
80
+ readonly ki: "Kikuyu";
81
+ readonly kj: "Kuanyama";
82
+ readonly kk: "Kazakh";
83
+ readonly kl: "Kalaallisut";
84
+ readonly km: "Khmer";
85
+ readonly kn: "Kannada";
86
+ readonly ko: "Korean";
87
+ readonly kr: "Kanuri";
88
+ readonly ks: "Kashmiri";
89
+ readonly ku: "Kurdish";
90
+ readonly kv: "Komi";
91
+ readonly kw: "Cornish";
92
+ readonly ky: "Kyrgyz";
93
+ readonly la: "Latin";
94
+ readonly lb: "Luxembourgish";
95
+ readonly lg: "Ganda";
96
+ readonly li: "Limburgish";
97
+ readonly ln: "Lingala";
98
+ readonly lo: "Lao";
99
+ readonly lt: "Lithuanian";
100
+ readonly lu: "Luba-Katanga";
101
+ readonly lv: "Latvian";
102
+ readonly mg: "Malagasy";
103
+ readonly mh: "Marshallese";
104
+ readonly mi: "Māori";
105
+ readonly mk: "Macedonian";
106
+ readonly ml: "Malayalam";
107
+ readonly mn: "Mongolian";
108
+ readonly mr: "Marathi";
109
+ readonly ms: "Malay";
110
+ readonly mt: "Maltese";
111
+ readonly my: "Burmese";
112
+ readonly na: "Nauru";
113
+ readonly nb: "Norwegian Bokmål";
114
+ readonly nd: "North Ndebele";
115
+ readonly ne: "Nepali";
116
+ readonly ng: "Ndonga";
117
+ readonly nl: "Dutch";
118
+ readonly nn: "Norwegian Nynorsk";
119
+ readonly no: "Norwegian";
120
+ readonly nr: "South Ndebele";
121
+ readonly nv: "Navajo";
122
+ readonly ny: "Nyanja";
123
+ readonly oc: "Occitan";
124
+ readonly oj: "Ojibwa";
125
+ readonly om: "Oromo";
126
+ readonly or: "Odia";
127
+ readonly os: "Ossetic";
128
+ readonly pa: "Punjabi";
129
+ readonly pi: "Pali";
130
+ readonly pl: "Polish";
131
+ readonly ps: "Pashto";
132
+ readonly pt: "Portuguese";
133
+ readonly qu: "Quechua";
134
+ readonly rm: "Romansh";
135
+ readonly rn: "Rundi";
136
+ readonly ro: "Romanian";
137
+ readonly ru: "Russian";
138
+ readonly rw: "Kinyarwanda";
139
+ readonly sa: "Sanskrit";
140
+ readonly sc: "Sardinian";
141
+ readonly sd: "Sindhi";
142
+ readonly se: "North Sámi";
143
+ readonly sg: "Sango";
144
+ readonly si: "Sinhala";
145
+ readonly sk: "Slovak";
146
+ readonly sl: "Slovenian";
147
+ readonly sm: "Samoan";
148
+ readonly sn: "Shona";
149
+ readonly so: "Somali";
150
+ readonly sq: "Albanian";
151
+ readonly sr: "Serbian";
152
+ readonly ss: "Swati";
153
+ readonly st: "Southern Sotho";
154
+ readonly su: "Sundanese";
155
+ readonly sv: "Swedish";
156
+ readonly sw: "Swahili";
157
+ readonly ta: "Tamil";
158
+ readonly te: "Telugu";
159
+ readonly tg: "Tajik";
160
+ readonly th: "Thai";
161
+ readonly ti: "Tigrinya";
162
+ readonly tk: "Turkmen";
163
+ readonly tl: "Tagalog";
164
+ readonly tn: "Tswana";
165
+ readonly to: "Tongan";
166
+ readonly tr: "Turkish";
167
+ readonly ts: "Tsonga";
168
+ readonly tt: "Tatar";
169
+ readonly tw: "Twi";
170
+ readonly ty: "Tahitian";
171
+ readonly ug: "Uyghur";
172
+ readonly uk: "Ukrainian";
173
+ readonly ur: "Urdu";
174
+ readonly uz: "Uzbek";
175
+ readonly ve: "Venda";
176
+ readonly vi: "Vietnamese";
177
+ readonly vo: "Volapük";
178
+ readonly wa: "Walloon";
179
+ readonly wo: "Wolof";
180
+ readonly xh: "Xhosa";
181
+ readonly yi: "Yiddish";
182
+ readonly yo: "Yoruba";
183
+ readonly za: "Zhuang";
184
+ readonly zh: "Chinese";
185
+ readonly zu: "Zulu";
186
+ };
187
+ export type LanguageCode = keyof typeof languageNames;
188
+ export declare const languageCodes: readonly ("aa" | "ab" | "ae" | "af" | "ak" | "am" | "an" | "ar" | "as" | "av" | "ay" | "az" | "ba" | "be" | "bg" | "bi" | "bm" | "bn" | "bo" | "br" | "bs" | "ca" | "ce" | "ch" | "co" | "cr" | "cs" | "cu" | "cv" | "cy" | "da" | "de" | "dv" | "dz" | "ee" | "el" | "en" | "eo" | "es" | "et" | "eu" | "fa" | "ff" | "fi" | "fj" | "fo" | "fr" | "fy" | "ga" | "gd" | "gl" | "gn" | "gu" | "gv" | "ha" | "he" | "hi" | "ho" | "hr" | "ht" | "hu" | "hy" | "hz" | "ia" | "id" | "ie" | "ig" | "ii" | "ik" | "io" | "is" | "it" | "iu" | "ja" | "jv" | "ka" | "kg" | "ki" | "kj" | "kk" | "kl" | "km" | "kn" | "ko" | "kr" | "ks" | "ku" | "kv" | "kw" | "ky" | "la" | "lb" | "lg" | "li" | "ln" | "lo" | "lt" | "lu" | "lv" | "mg" | "mh" | "mi" | "mk" | "ml" | "mn" | "mr" | "ms" | "mt" | "my" | "na" | "nb" | "nd" | "ne" | "ng" | "nl" | "nn" | "no" | "nr" | "nv" | "ny" | "oc" | "oj" | "om" | "or" | "os" | "pa" | "pi" | "pl" | "ps" | "pt" | "qu" | "rm" | "rn" | "ro" | "ru" | "rw" | "sa" | "sc" | "sd" | "se" | "sg" | "si" | "sk" | "sl" | "sm" | "sn" | "so" | "sq" | "sr" | "ss" | "st" | "su" | "sv" | "sw" | "ta" | "te" | "tg" | "th" | "ti" | "tk" | "tl" | "tn" | "to" | "tr" | "ts" | "tt" | "tw" | "ty" | "ug" | "uk" | "ur" | "uz" | "ve" | "vi" | "vo" | "wa" | "wo" | "xh" | "yi" | "yo" | "za" | "zh" | "zu")[];
189
+ export declare function isLanguageCode(value: unknown): value is LanguageCode;
190
+ /**
191
+ * The ISO 639-1 language of a BCP-47-ish tag (`'en-GB'`, `'da_DK'`), or
192
+ * `null` when it has none. Map tags your app treats as one language (`'no'`
193
+ * and `'nn'` to `'nb'`, say) before or after.
194
+ */
195
+ export declare function matchLanguageCode(tag: string | null | undefined): LanguageCode | null;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * A default language from an E.164 number's calling code (`+45…` → `'da'`),
3
+ * or `null` when the number is missing, too short, or its code is unmapped.
4
+ */
5
+ export declare function languageFromE164PhoneNumber(phoneNumber: string | null | undefined): "da" | "de" | "en" | "es" | "fr" | "it" | "nb" | "nl" | "pt" | "sv" | null;
@@ -79,6 +79,37 @@ export declare function pMap<T, R>(items: Iterable<T>, fn: (item: T, index: numb
79
79
  concurrency?: number;
80
80
  signal?: AbortSignal;
81
81
  }): Promise<R[]>;
82
+ export type TaskPool = {
83
+ /** Queues `task`; it starts once a slot is free. */
84
+ run<T>(task: () => Promise<T>): Promise<T>;
85
+ /** Resolves once every queued and active task has settled; rejects with the first failure. */
86
+ drain(): Promise<void>;
87
+ /** Throws the abort reason or the first failure, if any. */
88
+ throwIfFailed(): void;
89
+ };
90
+ /**
91
+ * A bounded pool for work that arrives over time, such as a crawl that queues
92
+ * pages as it discovers them (`pMap` needs the whole list up front).
93
+ *
94
+ * The first failure, or an abort, discards queued tasks and rejects later
95
+ * `run` calls; `drain` waits for active tasks to settle before rejecting with
96
+ * it. Pass the same `signal` to the tasks' IO so an abort interrupts them too.
97
+ * `stopOnError: false` keeps the pool running when a task fails, for callers
98
+ * that retry or fall back per task.
99
+ *
100
+ * A `run` promise that is never awaited does not cause an unhandled rejection;
101
+ * `drain` still reports its failure.
102
+ *
103
+ * @example
104
+ * const pool = createTaskPool({ concurrency: 4, signal })
105
+ * for await (const page of discoverPages(signal)) void pool.run(() => scrape(page, signal))
106
+ * await pool.drain()
107
+ */
108
+ export declare function createTaskPool(options: {
109
+ concurrency: number;
110
+ signal?: AbortSignal;
111
+ stopOnError?: boolean;
112
+ }): TaskPool;
82
113
  /** Starts a clock; call the returned function to read elapsed ms. */
83
114
  export declare function startTimer(): () => number;
84
115
  /** Runs `fn` and reports how long it took (throws pass through). */
@@ -0,0 +1,49 @@
1
+ import type { RedisClient, RedisOptions } from 'bun';
2
+ export type RedisRole = 'client' | 'subscriber';
3
+ export type RedisErrorContext = {
4
+ role: RedisRole;
5
+ stage: 'close' | 'subscribe' | 'resubscribe' | 'unsubscribe' | 'handler';
6
+ channel?: string;
7
+ };
8
+ export type ManagedRedisOptions = {
9
+ /** Read when a connection is created, so a secret store can resolve it lazily. */
10
+ url: string | (() => string);
11
+ /** Every failure, for logging, metrics and error tracking. Defaults to `console.error`. */
12
+ onError?: (error: unknown, context: RedisErrorContext) => void;
13
+ /** Builds each connection. Defaults to `new Bun.RedisClient(url, options)`. */
14
+ createClient?: (url: string, options: RedisOptions) => RedisClient;
15
+ };
16
+ export type RedisMessageHandler = (message: string, channel: string) => void;
17
+ export type ManagedRedis = {
18
+ /** The shared command connection, created on first use. */
19
+ getClient(): RedisClient;
20
+ /**
21
+ * Subscribes `handler` to `channel` on the shared subscriber connection.
22
+ * Channels are ref-counted: Redis sees one `SUBSCRIBE` however many handlers
23
+ * share it, and the returned function unsubscribes when the last one leaves.
24
+ */
25
+ subscribe(channel: string, handler: RedisMessageHandler): Promise<() => Promise<void>>;
26
+ isConnected(): boolean;
27
+ getStats(): {
28
+ channelCount: number;
29
+ channels: string[];
30
+ isConnected: boolean;
31
+ isSubscriberConnected: boolean;
32
+ };
33
+ /** Closes both connections. Errors from the shutdown itself are not reported. */
34
+ close(): void;
35
+ };
36
+ /**
37
+ * A command connection plus one shared subscriber connection for a Bun
38
+ * server. Both reconnect on their own, and subscriptions come back after a
39
+ * reconnect.
40
+ *
41
+ * @example
42
+ * export const redis = createManagedRedis({
43
+ * url: () => getSecret('REDIS_URL'),
44
+ * onError: (error, context) => captureException(error, 'redis', context)
45
+ * })
46
+ * await redis.getClient().set('key', 'value')
47
+ * const unsubscribe = await redis.subscribe('events', (message) => handle(message))
48
+ */
49
+ export declare function createManagedRedis(options: ManagedRedisOptions): ManagedRedis;
@@ -0,0 +1,63 @@
1
+ import { type RedisSend } from './lua-script';
2
+ export type ConcurrencyLimitStage = 'slot' | 'start';
3
+ export type RedisConcurrencyLimitOptions = {
4
+ key: string;
5
+ max: number;
6
+ slotTtlMs: number;
7
+ send: RedisSend;
8
+ maxStartsPerSecond?: number;
9
+ failOpenAfterMs?: number;
10
+ commandTimeoutMs?: number;
11
+ /** Receives throttled warnings. Defaults to `console`. */
12
+ logger?: Pick<Console, 'warn'>;
13
+ /** Called when a caller starts queueing; the returned function runs once it stops. */
14
+ onWait?: (stage: ConcurrencyLimitStage) => (() => void) | void;
15
+ };
16
+ export type RedisConcurrencyLimit = {
17
+ <T>(run: () => Promise<T>, signal?: AbortSignal): Promise<T>;
18
+ tripCooldown: (retryAfterMs: number) => Promise<void>;
19
+ /** Callers in this process waiting for a slot or a start, e.g. for a gauge. */
20
+ queueDepth: () => number;
21
+ /** Drop this limiter's timers. See `createRedisConcurrencyLimit`. */
22
+ dispose: () => void;
23
+ };
24
+ /**
25
+ * Redis semaphore shared by every process. Returns `withLimit(run)` - at most
26
+ * `max` callbacks in flight for `key`.
27
+ *
28
+ * A held slot is heartbeated for as long as `run` lasts, so `slotTtlMs` is a
29
+ * crash-detection window rather than a run budget: slots leaked by a killed pod
30
+ * free themselves within one TTL, while slow-but-alive work keeps its slot.
31
+ *
32
+ * `maxStartsPerSecond` is a separate sliding 1s window of *starts*. Use it when
33
+ * the provider quota is requests-per-second (Cloudflare Quick Actions) so
34
+ * in-flight concurrency can sit higher than the start rate.
35
+ *
36
+ * `tripCooldown` writes a shared pause from an upstream `Retry-After` so every
37
+ * process backs off together instead of stampeding into 429s.
38
+ *
39
+ * Waiters inside one process queue locally and are handed to Redis in a single
40
+ * batched call, so a pod with hundreds of callers costs the same Redis traffic
41
+ * as one with a handful.
42
+ *
43
+ * When Redis itself is unreachable for `failOpenAfterMs` the limiter gives up
44
+ * and runs uncapped. Callers guard a third-party quota; degrading to the
45
+ * provider's own rate limit beats hanging every caller until Redis returns.
46
+ * That verdict is shared per limiter: once tripped, later calls degrade
47
+ * immediately while a background probe watches for Redis to come back.
48
+ *
49
+ * `onWait` and `queueDepth` feed metrics. A limiter minted per tenant or per
50
+ * customer host should report under a shared pool label rather than its key,
51
+ * or every key ever touched leaves a permanent series. Call `dispose()` when
52
+ * such a limiter is discarded, and unregister any gauge reading `queueDepth`.
53
+ *
54
+ * @example
55
+ * const withLimit = createRedisConcurrencyLimit({
56
+ * key: 'openai',
57
+ * max: 20,
58
+ * slotTtlMs: 30_000,
59
+ * send: (command, args) => redis.getClient().send(command, args)
60
+ * })
61
+ * const reply = await withLimit(() => openai.chat(request), signal)
62
+ */
63
+ export declare function createRedisConcurrencyLimit(input: RedisConcurrencyLimitOptions): RedisConcurrencyLimit;
@@ -0,0 +1,3 @@
1
+ export { createManagedRedis, type ManagedRedis, type ManagedRedisOptions, type RedisErrorContext, type RedisMessageHandler, type RedisRole } from './client';
2
+ export { type ConcurrencyLimitStage, createRedisConcurrencyLimit, type RedisConcurrencyLimit, type RedisConcurrencyLimitOptions } from './concurrency-limit';
3
+ export { createLuaScript, type RedisSend } from './lua-script';
@@ -0,0 +1,13 @@
1
+ /** One raw Redis command, e.g. `(command, args) => redis.getClient().send(command, args)`. */
2
+ export type RedisSend = (command: string, args: string[]) => Promise<unknown>;
3
+ /**
4
+ * Ship a Lua script by SHA instead of resending its source on every call.
5
+ *
6
+ * Redis forgets its script cache on restart and on `SCRIPT FLUSH`, so a
7
+ * `NOSCRIPT` reply falls back to an inline `EVAL` (which repopulates the cache)
8
+ * and drops the stale digest.
9
+ *
10
+ * The digest is cached per instance rather than per module so each limiter -
11
+ * and each test fake - owns its own cache.
12
+ */
13
+ export declare function createLuaScript(send: RedisSend, source: string): (keys: string[], args: string[]) => Promise<unknown>;
@@ -0,0 +1,12 @@
1
+ import type { EnvironmentVariables } from './environment';
2
+ /**
3
+ * Machine identity (Universal Auth) credentials kept in a private file for every
4
+ * process on this machine, for example by agentgate, which syncs one identity to
5
+ * all of a user's machines. `INFISICAL_UNIVERSAL_AUTH_FILE` overrides the default
6
+ * `~/.infisical/universal-auth.json`. Only credentials for `siteUrl`'s instance are
7
+ * returned, so a secret is never sent to another Infisical instance.
8
+ */
9
+ export declare function readInfisicalIdentityFile(env: EnvironmentVariables | undefined, siteUrl: string): Promise<{
10
+ clientId: string;
11
+ clientSecret: string;
12
+ } | undefined>;
@@ -0,0 +1,82 @@
1
+ import {
2
+ raceAbort2
3
+ } from "../../index-6f2w90pp.js";
4
+
5
+ // src/api-wrapper/connection-auth.ts
6
+ import { createHmac, randomBytes } from "node:crypto";
7
+ class ConnectionAuthCache {
8
+ maxEntries;
9
+ key = randomBytes(32);
10
+ entries = new Map;
11
+ constructor(maxEntries = 1000) {
12
+ this.maxEntries = maxEntries;
13
+ }
14
+ get size() {
15
+ return this.entries.size;
16
+ }
17
+ clear() {
18
+ for (const entry of this.entries.values())
19
+ entry.token = undefined;
20
+ this.entries.clear();
21
+ }
22
+ prune(protectedEntry) {
23
+ for (const [connectionId, entry] of this.entries) {
24
+ if (this.entries.size <= this.maxEntries)
25
+ break;
26
+ if (entry.pending || entry === protectedEntry)
27
+ continue;
28
+ entry.token = undefined;
29
+ this.entries.delete(connectionId);
30
+ }
31
+ }
32
+ bind(input) {
33
+ const identity = createHmac("sha256", this.key).update(JSON.stringify(input.authInputs)).digest("hex");
34
+ let entry = this.entries.get(input.connectionId);
35
+ if (!entry || entry.identity !== identity) {
36
+ if (entry)
37
+ entry.token = undefined;
38
+ entry = { identity };
39
+ }
40
+ this.entries.delete(input.connectionId);
41
+ this.entries.set(input.connectionId, entry);
42
+ this.prune(entry);
43
+ const state = entry;
44
+ const get = (options) => {
45
+ if (options?.signal?.aborted) {
46
+ return Promise.reject(options.signal.reason);
47
+ }
48
+ if (this.entries.get(input.connectionId) === state) {
49
+ this.entries.delete(input.connectionId);
50
+ this.entries.set(input.connectionId, state);
51
+ }
52
+ if (state.pending)
53
+ return raceAbort2(state.pending, options?.signal);
54
+ if (!options?.fresh && state.token && state.token.expiresAt - Date.now() > input.refreshMarginMs) {
55
+ return Promise.resolve(state.token);
56
+ }
57
+ state.token = undefined;
58
+ const pending = input.exchange().then((token) => {
59
+ if (this.entries.get(input.connectionId) === state) {
60
+ state.token = token;
61
+ }
62
+ return token;
63
+ }).finally(() => {
64
+ if (state.pending === pending)
65
+ state.pending = undefined;
66
+ this.prune();
67
+ });
68
+ state.pending = pending;
69
+ return raceAbort2(pending, options?.signal);
70
+ };
71
+ return {
72
+ get,
73
+ reject(token) {
74
+ if (state.token === token)
75
+ state.token = undefined;
76
+ }
77
+ };
78
+ }
79
+ }
80
+ export {
81
+ ConnectionAuthCache
82
+ };
@@ -28,7 +28,7 @@ import {
28
28
  paginate2,
29
29
  otelMiddleware2,
30
30
  defineEndpoint2
31
- } from "../../index-zbj9s3s3.js";
31
+ } from "../../index-2kz392vw.js";
32
32
  export {
33
33
  ActionError2 as ActionError,
34
34
  ApiError2 as ApiError,
@@ -0,0 +1,10 @@
1
+ import {
2
+ CliError2,
3
+ defineCommand2,
4
+ defineCli2
5
+ } from "../../index-nfvq3zax.js";
6
+ export {
7
+ CliError2 as CliError,
8
+ defineCli2 as defineCli,
9
+ defineCommand2 as defineCommand
10
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  stableStringify2
3
- } from "../../index-kj1phgrx.js";
3
+ } from "../../index-29mmh343.js";
4
4
 
5
5
  // src/format/index.ts
6
6
  var MAX_CACHED_FORMATTERS = 100;
@@ -44,6 +44,9 @@ function formatCurrency(amount, currency, locale, options) {
44
44
  currency
45
45
  });
46
46
  }
47
+ function formatPrice(amount, currency, locale) {
48
+ return formatCurrency(amount, currency, locale, Number.isInteger(amount) ? { minimumFractionDigits: 0, maximumFractionDigits: 0 } : undefined);
49
+ }
47
50
  function formatCompactNumber(value, locale) {
48
51
  return formatNumber(value, locale, { notation: "compact" });
49
52
  }
@@ -173,12 +176,68 @@ function formatDateRange(start, end, locale, options = {}) {
173
176
  const to = new Date(toTime(end));
174
177
  return typeof format.formatRange === "function" ? format.formatRange(from, to) : `${format.format(from)} – ${format.format(to)}`;
175
178
  }
179
+ var DATE_PRESETS = {
180
+ "DD/MM/YYYY": { day: "2-digit", month: "2-digit", year: "numeric" },
181
+ "DD/MM/YYYY HH:mm": {
182
+ day: "2-digit",
183
+ month: "2-digit",
184
+ year: "numeric",
185
+ hour: "2-digit",
186
+ minute: "2-digit",
187
+ hourCycle: "h23"
188
+ },
189
+ "HH:mm": { hour: "2-digit", minute: "2-digit", hourCycle: "h23" },
190
+ ddd: { weekday: "short" },
191
+ "D MMM": { day: "numeric", month: "short" },
192
+ "D MMM YYYY": { day: "numeric", month: "short", year: "numeric" },
193
+ "dddd, MMMM D": { weekday: "long", day: "numeric", month: "long" },
194
+ "MMMM YYYY": { month: "long", year: "numeric" }
195
+ };
196
+ function formatDate(date, preset, locale) {
197
+ return getDateTimeFormat(locale, DATE_PRESETS[preset]).format(toTime(date));
198
+ }
199
+ function formatDateTime(date, locale) {
200
+ return getDateTimeFormat(locale, {
201
+ dateStyle: "medium",
202
+ timeStyle: "short"
203
+ }).format(toTime(date));
204
+ }
205
+ function dayOffset(date, now) {
206
+ const start = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
207
+ return Math.round((start(date) - start(now)) / DAY_MS);
208
+ }
209
+ var relativeDay = (offset, locale) => getRelativeTimeFormat(locale, { numeric: "auto" }).format(offset, "day");
210
+ function formatCompactTime(date, locale, options = {}) {
211
+ const value = new Date(toTime(date));
212
+ if (Number.isNaN(value.getTime()))
213
+ return "";
214
+ const now = new Date(toTime(options.now ?? Date.now()));
215
+ const offset = dayOffset(value, now);
216
+ if (offset === 0)
217
+ return formatDate(value, "HH:mm", locale);
218
+ if (offset === -1)
219
+ return relativeDay(-1, locale);
220
+ const sameYear = value.getFullYear() === now.getFullYear();
221
+ return formatDate(value, sameYear ? "D MMM" : "D MMM YYYY", locale);
222
+ }
223
+ function formatDayDivider(date, locale, options = {}) {
224
+ const value = new Date(toTime(date));
225
+ if (Number.isNaN(value.getTime()))
226
+ return "";
227
+ const now = new Date(toTime(options.now ?? Date.now()));
228
+ const offset = dayOffset(value, now);
229
+ if (offset === 0 || offset === -1)
230
+ return relativeDay(offset, locale);
231
+ const sameYear = value.getFullYear() === now.getFullYear();
232
+ return formatDate(value, sameYear ? "dddd, MMMM D" : "D MMM YYYY", locale);
233
+ }
176
234
  function formatList(items, locale, options) {
177
235
  if (typeof Intl.ListFormat !== "function") {
178
236
  return items.join(options?.style === "narrow" ? " " : ", ");
179
237
  }
180
238
  return getListFormat(locale, options).format(items);
181
239
  }
240
+ var EM_DASH = "—";
182
241
  function formatCappedCount(count, max = 99) {
183
242
  if (!(count > 0))
184
243
  return "0";
@@ -188,17 +247,34 @@ function pluralize(count, forms, locale) {
188
247
  const form = forms[getPluralRules(locale).select(count)] ?? forms.other;
189
248
  return form.replaceAll("{count}", formatNumber(count, locale));
190
249
  }
250
+ function withLocale(getLocale) {
251
+ return {
252
+ formatDate: (date, preset) => formatDate(date, preset, getLocale()),
253
+ formatDateTime: (date) => formatDateTime(date, getLocale()),
254
+ formatCompactTime: (date) => formatCompactTime(date, getLocale()),
255
+ formatDayDivider: (date) => formatDayDivider(date, getLocale()),
256
+ formatRelativeTime: (date, options) => formatRelativeTime(date, getLocale(), options),
257
+ formatNumber: (value, options) => formatNumber(value, getLocale(), options),
258
+ formatPrice: (amount, currency) => formatPrice(amount, currency, getLocale())
259
+ };
260
+ }
191
261
  export {
262
+ EM_DASH,
192
263
  formatBytes,
193
264
  formatCappedCount,
194
265
  formatClockDuration,
195
266
  formatCompactNumber,
267
+ formatCompactTime,
196
268
  formatCurrency,
269
+ formatDate,
197
270
  formatDateRange,
271
+ formatDateTime,
272
+ formatDayDivider,
198
273
  formatDuration,
199
274
  formatList,
200
275
  formatNumber,
201
276
  formatPercent,
277
+ formatPrice,
202
278
  formatRelativeTime,
203
279
  formatWait,
204
280
  getDateTimeFormat,
@@ -207,5 +283,6 @@ export {
207
283
  getPluralRules,
208
284
  getRelativeTimeFormat,
209
285
  pluralize,
210
- splitDuration
286
+ splitDuration,
287
+ withLocale
211
288
  };
@@ -0,0 +1,21 @@
1
+ // src/format/phone.ts
2
+ import {
3
+ isSupportedCountry,
4
+ parsePhoneNumberFromString
5
+ } from "libphonenumber-js";
6
+ function formatPhone(value, country) {
7
+ const raw = value?.trim() ?? "";
8
+ if (!raw)
9
+ return "";
10
+ const region = country && isSupportedCountry(country) ? country : undefined;
11
+ const parsed = parsePhoneNumberFromString(raw, region ? { defaultCountry: region } : undefined);
12
+ if (!parsed)
13
+ return raw;
14
+ if (region && parsed.country === region && parsed.isValid()) {
15
+ return parsed.formatNational();
16
+ }
17
+ return parsed.formatInternational();
18
+ }
19
+ export {
20
+ formatPhone
21
+ };