@voyantjs/utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/LICENSE +109 -0
  2. package/README.md +42 -0
  3. package/dist/accounting-countries.d.ts +12 -0
  4. package/dist/accounting-countries.d.ts.map +1 -0
  5. package/dist/accounting-countries.js +307 -0
  6. package/dist/accounting-countries.js.map +1 -0
  7. package/dist/accounting-regions.d.ts +103 -0
  8. package/dist/accounting-regions.d.ts.map +1 -0
  9. package/dist/accounting-regions.js +38 -0
  10. package/dist/accounting-regions.js.map +1 -0
  11. package/dist/airlines.d.ts +960 -0
  12. package/dist/airlines.d.ts.map +1 -0
  13. package/dist/airlines.js +989 -0
  14. package/dist/airlines.js.map +1 -0
  15. package/dist/analytics/api-key-events.d.ts +89 -0
  16. package/dist/analytics/api-key-events.d.ts.map +1 -0
  17. package/dist/analytics/api-key-events.js +99 -0
  18. package/dist/analytics/api-key-events.js.map +1 -0
  19. package/dist/api-keys-client.d.ts +40 -0
  20. package/dist/api-keys-client.d.ts.map +1 -0
  21. package/dist/api-keys-client.js +63 -0
  22. package/dist/api-keys-client.js.map +1 -0
  23. package/dist/api-keys.d.ts +48 -0
  24. package/dist/api-keys.d.ts.map +1 -0
  25. package/dist/api-keys.js +108 -0
  26. package/dist/api-keys.js.map +1 -0
  27. package/dist/cache.d.ts +123 -0
  28. package/dist/cache.d.ts.map +1 -0
  29. package/dist/cache.js +182 -0
  30. package/dist/cache.js.map +1 -0
  31. package/dist/checkout-signature.d.ts +15 -0
  32. package/dist/checkout-signature.d.ts.map +1 -0
  33. package/dist/checkout-signature.js +64 -0
  34. package/dist/checkout-signature.js.map +1 -0
  35. package/dist/conditions.d.ts +36 -0
  36. package/dist/conditions.d.ts.map +1 -0
  37. package/dist/conditions.js +396 -0
  38. package/dist/conditions.js.map +1 -0
  39. package/dist/countries.d.ts +5 -0
  40. package/dist/countries.d.ts.map +1 -0
  41. package/dist/countries.js +251 -0
  42. package/dist/countries.js.map +1 -0
  43. package/dist/currencies.d.ts +1011 -0
  44. package/dist/currencies.d.ts.map +1 -0
  45. package/dist/currencies.js +1011 -0
  46. package/dist/currencies.js.map +1 -0
  47. package/dist/email/send.d.ts +20 -0
  48. package/dist/email/send.d.ts.map +1 -0
  49. package/dist/email/send.js +53 -0
  50. package/dist/email/send.js.map +1 -0
  51. package/dist/form-runtime.d.ts +38 -0
  52. package/dist/form-runtime.d.ts.map +1 -0
  53. package/dist/form-runtime.js +174 -0
  54. package/dist/form-runtime.js.map +1 -0
  55. package/dist/gcs/storage.d.ts +23 -0
  56. package/dist/gcs/storage.d.ts.map +1 -0
  57. package/dist/gcs/storage.js +25 -0
  58. package/dist/gcs/storage.js.map +1 -0
  59. package/dist/geo.d.ts +85 -0
  60. package/dist/geo.d.ts.map +1 -0
  61. package/dist/geo.js +141 -0
  62. package/dist/geo.js.map +1 -0
  63. package/dist/geographic-regions.d.ts +66 -0
  64. package/dist/geographic-regions.d.ts.map +1 -0
  65. package/dist/geographic-regions.js +326 -0
  66. package/dist/geographic-regions.js.map +1 -0
  67. package/dist/index.d.ts +9 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +9 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/kms-aws.d.ts +26 -0
  72. package/dist/kms-aws.d.ts.map +1 -0
  73. package/dist/kms-aws.js +133 -0
  74. package/dist/kms-aws.js.map +1 -0
  75. package/dist/kms-crypto.d.ts +20 -0
  76. package/dist/kms-crypto.d.ts.map +1 -0
  77. package/dist/kms-crypto.js +108 -0
  78. package/dist/kms-crypto.js.map +1 -0
  79. package/dist/kms-env.d.ts +13 -0
  80. package/dist/kms-env.d.ts.map +1 -0
  81. package/dist/kms-env.js +13 -0
  82. package/dist/kms-env.js.map +1 -0
  83. package/dist/kms-gcp.d.ts +32 -0
  84. package/dist/kms-gcp.d.ts.map +1 -0
  85. package/dist/kms-gcp.js +116 -0
  86. package/dist/kms-gcp.js.map +1 -0
  87. package/dist/kms-local.d.ts +13 -0
  88. package/dist/kms-local.d.ts.map +1 -0
  89. package/dist/kms-local.js +13 -0
  90. package/dist/kms-local.js.map +1 -0
  91. package/dist/kms-symmetric.d.ts +14 -0
  92. package/dist/kms-symmetric.d.ts.map +1 -0
  93. package/dist/kms-symmetric.js +67 -0
  94. package/dist/kms-symmetric.js.map +1 -0
  95. package/dist/kms.d.ts +66 -0
  96. package/dist/kms.d.ts.map +1 -0
  97. package/dist/kms.js +169 -0
  98. package/dist/kms.js.map +1 -0
  99. package/dist/kv-codecs.d.ts +6 -0
  100. package/dist/kv-codecs.d.ts.map +1 -0
  101. package/dist/kv-codecs.js +4 -0
  102. package/dist/kv-codecs.js.map +1 -0
  103. package/dist/kv.d.ts +10 -0
  104. package/dist/kv.d.ts.map +1 -0
  105. package/dist/kv.js +18 -0
  106. package/dist/kv.js.map +1 -0
  107. package/dist/languages.d.ts +187 -0
  108. package/dist/languages.d.ts.map +1 -0
  109. package/dist/languages.js +187 -0
  110. package/dist/languages.js.map +1 -0
  111. package/dist/localized-countries-regions.d.ts +15 -0
  112. package/dist/localized-countries-regions.d.ts.map +1 -0
  113. package/dist/localized-countries-regions.js +674 -0
  114. package/dist/localized-countries-regions.js.map +1 -0
  115. package/dist/localized-regions.d.ts +33 -0
  116. package/dist/localized-regions.d.ts.map +1 -0
  117. package/dist/localized-regions.js +63 -0
  118. package/dist/localized-regions.js.map +1 -0
  119. package/dist/price/resolve.d.ts +91 -0
  120. package/dist/price/resolve.d.ts.map +1 -0
  121. package/dist/price/resolve.js +227 -0
  122. package/dist/price/resolve.js.map +1 -0
  123. package/dist/rate-limits.d.ts +39 -0
  124. package/dist/rate-limits.d.ts.map +1 -0
  125. package/dist/rate-limits.js +86 -0
  126. package/dist/rate-limits.js.map +1 -0
  127. package/dist/redis.d.ts +13 -0
  128. package/dist/redis.d.ts.map +1 -0
  129. package/dist/redis.js +16 -0
  130. package/dist/redis.js.map +1 -0
  131. package/dist/region-only.d.ts +11 -0
  132. package/dist/region-only.d.ts.map +1 -0
  133. package/dist/region-only.js +49 -0
  134. package/dist/region-only.js.map +1 -0
  135. package/dist/region.d.ts +11 -0
  136. package/dist/region.d.ts.map +1 -0
  137. package/dist/region.js +47 -0
  138. package/dist/region.js.map +1 -0
  139. package/dist/romania-bucharest-sectors.d.ts +6 -0
  140. package/dist/romania-bucharest-sectors.d.ts.map +1 -0
  141. package/dist/romania-bucharest-sectors.js +27 -0
  142. package/dist/romania-bucharest-sectors.js.map +1 -0
  143. package/dist/romania-counties.d.ts +6 -0
  144. package/dist/romania-counties.d.ts.map +1 -0
  145. package/dist/romania-counties.js +171 -0
  146. package/dist/romania-counties.js.map +1 -0
  147. package/dist/session-claims.d.ts +40 -0
  148. package/dist/session-claims.d.ts.map +1 -0
  149. package/dist/session-claims.js +184 -0
  150. package/dist/session-claims.js.map +1 -0
  151. package/dist/sms/provider.d.ts +28 -0
  152. package/dist/sms/provider.d.ts.map +1 -0
  153. package/dist/sms/provider.js +50 -0
  154. package/dist/sms/provider.js.map +1 -0
  155. package/dist/sms/segments.d.ts +3 -0
  156. package/dist/sms/segments.d.ts.map +1 -0
  157. package/dist/sms/segments.js +33 -0
  158. package/dist/sms/segments.js.map +1 -0
  159. package/dist/temporal.d.ts +2 -0
  160. package/dist/temporal.d.ts.map +1 -0
  161. package/dist/temporal.js +6 -0
  162. package/dist/temporal.js.map +1 -0
  163. package/dist/timezones.d.ts +9 -0
  164. package/dist/timezones.d.ts.map +1 -0
  165. package/dist/timezones.js +1217 -0
  166. package/dist/timezones.js.map +1 -0
  167. package/dist/twilio/client.d.ts +13 -0
  168. package/dist/twilio/client.d.ts.map +1 -0
  169. package/dist/twilio/client.js +26 -0
  170. package/dist/twilio/client.js.map +1 -0
  171. package/dist/usage/index.d.ts +34 -0
  172. package/dist/usage/index.d.ts.map +1 -0
  173. package/dist/usage/index.js +18 -0
  174. package/dist/usage/index.js.map +1 -0
  175. package/dist/usage/policy.d.ts +27 -0
  176. package/dist/usage/policy.d.ts.map +1 -0
  177. package/dist/usage/policy.js +17 -0
  178. package/dist/usage/policy.js.map +1 -0
  179. package/dist/validation/log.d.ts +10 -0
  180. package/dist/validation/log.d.ts.map +1 -0
  181. package/dist/validation/log.js +37 -0
  182. package/dist/validation/log.js.map +1 -0
  183. package/dist/with-timeout.d.ts +2 -0
  184. package/dist/with-timeout.d.ts.map +1 -0
  185. package/dist/with-timeout.js +15 -0
  186. package/dist/with-timeout.js.map +1 -0
  187. package/dist/zod-form-builder.d.ts +45 -0
  188. package/dist/zod-form-builder.d.ts.map +1 -0
  189. package/dist/zod-form-builder.js +216 -0
  190. package/dist/zod-form-builder.js.map +1 -0
  191. package/package.json +92 -0
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Session Claims Cookie Utilities
3
+ *
4
+ * Implements signed session claims to reduce API calls in middleware.
5
+ * Claims contain minimal session info (userId, sessionId hash) that can be
6
+ * verified locally without database lookup.
7
+ *
8
+ * Security:
9
+ * - HMAC-SHA256 signing prevents tampering
10
+ * - 5-minute expiration ensures quick revocation
11
+ * - HttpOnly, Secure, SameSite cookies
12
+ *
13
+ * Compatible with both Node.js (middleware) and Cloudflare Workers (API)
14
+ */
15
+ // Use Node crypto when available (Next.js middleware, Node.js environments)
16
+ // Falls back to Web Crypto API for Cloudflare Workers
17
+ let nodeCrypto = null;
18
+ try {
19
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
20
+ nodeCrypto = require("node:crypto");
21
+ }
22
+ catch {
23
+ // Not in Node.js environment
24
+ }
25
+ function getWebCrypto() {
26
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
27
+ return globalThis.crypto;
28
+ }
29
+ if (nodeCrypto?.webcrypto) {
30
+ return nodeCrypto.webcrypto;
31
+ }
32
+ throw new Error("No crypto implementation available");
33
+ }
34
+ const CLAIMS_EXPIRY_SECONDS = 5 * 60; // 5 minutes
35
+ /**
36
+ * Create a short identifier from session ID for inclusion in claims
37
+ * Uses first 16 chars of base64url-encoded SHA-256 hash
38
+ */
39
+ async function hashSessionId(sessionId) {
40
+ // Node.js crypto (preferred - synchronous)
41
+ if (nodeCrypto) {
42
+ const hash = nodeCrypto.createHash("sha256").update(sessionId).digest("base64url");
43
+ return hash.slice(0, 16);
44
+ }
45
+ // Web Crypto API (Cloudflare Workers)
46
+ const webCrypto = getWebCrypto();
47
+ const encoder = new TextEncoder();
48
+ const data = encoder.encode(sessionId);
49
+ const hashBuffer = await webCrypto.subtle.digest("SHA-256", data);
50
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
51
+ // Convert to base64url manually
52
+ const hashB64 = btoa(String.fromCharCode(...hashArray))
53
+ .replace(/\+/g, "-")
54
+ .replace(/\//g, "_")
55
+ .replace(/=/g, "");
56
+ return hashB64.slice(0, 16);
57
+ }
58
+ /**
59
+ * Sign session claims and return as JWT-like token
60
+ *
61
+ * Format: base64url(header).base64url(payload).base64url(signature)
62
+ *
63
+ * @param userId - User ID from verified session
64
+ * @param sessionId - Full session ID (will be hashed)
65
+ * @param secret - HMAC secret for signing
66
+ * @returns Signed token string
67
+ */
68
+ export async function signSessionClaims(userId, sessionId, secret) {
69
+ const now = Math.floor(Date.now() / 1000);
70
+ const exp = now + CLAIMS_EXPIRY_SECONDS;
71
+ const sessionIdHash = await hashSessionId(sessionId);
72
+ const claims = {
73
+ userId,
74
+ sessionId: sessionIdHash,
75
+ iat: now,
76
+ exp,
77
+ };
78
+ // Encode payload (works in both environments)
79
+ const header = { alg: "HS256", typ: "JWT" };
80
+ const headerB64 = btoa(JSON.stringify(header))
81
+ .replace(/\+/g, "-")
82
+ .replace(/\//g, "_")
83
+ .replace(/=/g, "");
84
+ const payloadB64 = btoa(JSON.stringify(claims))
85
+ .replace(/\+/g, "-")
86
+ .replace(/\//g, "_")
87
+ .replace(/=/g, "");
88
+ // Create signature
89
+ const message = `${headerB64}.${payloadB64}`;
90
+ let signature;
91
+ // Node.js crypto (preferred - synchronous)
92
+ if (nodeCrypto) {
93
+ signature = nodeCrypto.createHmac("sha256", secret).update(message).digest("base64url");
94
+ }
95
+ else {
96
+ // Web Crypto API (Cloudflare Workers)
97
+ const webCrypto = getWebCrypto();
98
+ const encoder = new TextEncoder();
99
+ const keyData = encoder.encode(secret);
100
+ const key = await webCrypto.subtle.importKey("raw", keyData, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
101
+ const sigBuffer = await webCrypto.subtle.sign("HMAC", key, encoder.encode(message));
102
+ const sigArray = Array.from(new Uint8Array(sigBuffer));
103
+ signature = btoa(String.fromCharCode(...sigArray))
104
+ .replace(/\+/g, "-")
105
+ .replace(/\//g, "_")
106
+ .replace(/=/g, "");
107
+ }
108
+ return `${headerB64}.${payloadB64}.${signature}`;
109
+ }
110
+ /**
111
+ * Verify and decode session claims token
112
+ *
113
+ * @param token - Signed token from cookie
114
+ * @param secret - HMAC secret for verification
115
+ * @returns Decoded claims if valid, null if invalid/expired
116
+ */
117
+ export async function verifySessionClaims(token, secret) {
118
+ try {
119
+ const parts = token.split(".");
120
+ if (parts.length !== 3) {
121
+ return null;
122
+ }
123
+ const [headerB64, payloadB64, signature] = parts;
124
+ // Ensure all parts are defined
125
+ if (!headerB64 || !payloadB64 || !signature) {
126
+ return null;
127
+ }
128
+ // Verify signature
129
+ const message = `${headerB64}.${payloadB64}`;
130
+ let expectedSig;
131
+ // Node.js crypto (preferred - synchronous)
132
+ if (nodeCrypto) {
133
+ expectedSig = nodeCrypto.createHmac("sha256", secret).update(message).digest("base64url");
134
+ }
135
+ else {
136
+ // Web Crypto API (Cloudflare Workers)
137
+ const webCrypto = getWebCrypto();
138
+ const encoder = new TextEncoder();
139
+ const keyData = encoder.encode(secret);
140
+ const key = await webCrypto.subtle.importKey("raw", keyData, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
141
+ const sigBuffer = await webCrypto.subtle.sign("HMAC", key, encoder.encode(message));
142
+ const sigArray = Array.from(new Uint8Array(sigBuffer));
143
+ expectedSig = btoa(String.fromCharCode(...sigArray))
144
+ .replace(/\+/g, "-")
145
+ .replace(/\//g, "_")
146
+ .replace(/=/g, "");
147
+ }
148
+ // Constant-time comparison
149
+ if (!constantTimeEqual(signature, expectedSig)) {
150
+ return null;
151
+ }
152
+ // Decode payload (works in both environments)
153
+ // base64url decode: replace - with +, _ with /, then decode
154
+ const payloadJson = atob(payloadB64.replace(/-/g, "+").replace(/_/g, "/"));
155
+ const payload = JSON.parse(payloadJson);
156
+ // Check expiration
157
+ const now = Math.floor(Date.now() / 1000);
158
+ if (payload.exp < now) {
159
+ return null;
160
+ }
161
+ // Validate structure
162
+ if (!payload.userId || !payload.sessionId || !payload.iat || !payload.exp) {
163
+ return null;
164
+ }
165
+ return payload;
166
+ }
167
+ catch (_error) {
168
+ // Invalid token format or JSON parse error
169
+ return null;
170
+ }
171
+ }
172
+ /**
173
+ * Constant-time string comparison to prevent timing attacks
174
+ */
175
+ function constantTimeEqual(a, b) {
176
+ if (a.length !== b.length)
177
+ return false;
178
+ let result = 0;
179
+ for (let i = 0; i < a.length; i++) {
180
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
181
+ }
182
+ return result === 0;
183
+ }
184
+ //# sourceMappingURL=session-claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-claims.js","sourceRoot":"","sources":["../src/session-claims.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export type SendTransactionalSmsInput = {
2
+ toE164: string;
3
+ body: string;
4
+ senderId?: string;
5
+ };
6
+ /**
7
+ * BYOK (Bring Your Own Key) Twilio configuration for organization-specific credentials.
8
+ */
9
+ export type TwilioByokConfig = {
10
+ accountSid: string;
11
+ authToken: string;
12
+ phoneNumber?: string | null;
13
+ messagingServiceSid?: string | null;
14
+ };
15
+ export type SendTransactionalSmsResult = {
16
+ provider: "twilio" | "sns";
17
+ id?: string;
18
+ raw?: unknown;
19
+ };
20
+ /**
21
+ * Send a transactional SMS via Twilio.
22
+ *
23
+ * @param input - SMS content and recipient
24
+ * @param twilioConfig - Optional organization-specific Twilio credentials (BYOK).
25
+ * If not provided, falls back to global environment variables.
26
+ */
27
+ export declare function sendTransactionalSms(input: SendTransactionalSmsInput, twilioConfig?: TwilioByokConfig): Promise<SendTransactionalSmsResult>;
28
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/sms/provider.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,QAAQ,GAAG,KAAK,CAAA;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,OAAO,CAAA;CACd,CAAA;AAOD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,EAChC,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,0BAA0B,CAAC,CAiDrC"}
@@ -0,0 +1,50 @@
1
+ import { createTwilioClientWithCredentials, getTwilioClient } from "../twilio/client.js";
2
+ function getSmsProvider() {
3
+ const p = (process.env.SMS_PROVIDER || "twilio").toLowerCase();
4
+ return p === "sns" ? "sns" : "twilio";
5
+ }
6
+ /**
7
+ * Send a transactional SMS via Twilio.
8
+ *
9
+ * @param input - SMS content and recipient
10
+ * @param twilioConfig - Optional organization-specific Twilio credentials (BYOK).
11
+ * If not provided, falls back to global environment variables.
12
+ */
13
+ export async function sendTransactionalSms(input, twilioConfig) {
14
+ const provider = getSmsProvider();
15
+ if (provider === "twilio") {
16
+ // Use organization-specific credentials if provided (BYOK)
17
+ if (twilioConfig) {
18
+ const client = createTwilioClientWithCredentials(twilioConfig.accountSid, twilioConfig.authToken);
19
+ // Prefer messaging service SID over phone number
20
+ const messagingServiceSid = twilioConfig.messagingServiceSid;
21
+ const fromNumber = twilioConfig.phoneNumber;
22
+ if (!messagingServiceSid && !fromNumber) {
23
+ throw new Error("BYOK Twilio config requires either phoneNumber or messagingServiceSid");
24
+ }
25
+ const res = await client.messages.create({
26
+ to: input.toE164,
27
+ body: input.body,
28
+ ...(messagingServiceSid ? { messagingServiceSid } : {}),
29
+ ...(fromNumber && !messagingServiceSid ? { from: fromNumber } : {}),
30
+ });
31
+ return { provider: "twilio", id: res.sid, raw: res };
32
+ }
33
+ // Fall back to global environment variables
34
+ const client = getTwilioClient();
35
+ const messagingServiceSid = process.env.TWILIO_MESSAGING_SERVICE_SID;
36
+ const fromNumber = process.env.TWILIO_PHONE_NUMBER;
37
+ if (!messagingServiceSid && !fromNumber) {
38
+ throw new Error("Configure TWILIO_MESSAGING_SERVICE_SID or TWILIO_PHONE_NUMBER");
39
+ }
40
+ const res = await client.messages.create({
41
+ to: input.toE164,
42
+ body: input.body,
43
+ ...(messagingServiceSid ? { messagingServiceSid } : {}),
44
+ ...(fromNumber ? { from: fromNumber } : {}),
45
+ });
46
+ return { provider: "twilio", id: res.sid, raw: res };
47
+ }
48
+ throw new Error("SNS is no longer supported");
49
+ }
50
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/sms/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAC,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAwBvF,SAAS,cAAc;IACrB,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;IAC9D,OAAO,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAA;AACvC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAgC,EAChC,YAA+B;IAE/B,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAA;IAEjC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,2DAA2D;QAC3D,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,MAAM,GAAG,iCAAiC,CAC9C,YAAY,CAAC,UAAU,EACvB,YAAY,CAAC,SAAS,CACvB,CAAA;YAED,iDAAiD;YACjD,MAAM,mBAAmB,GAAG,YAAY,CAAC,mBAAmB,CAAA;YAC5D,MAAM,UAAU,GAAG,YAAY,CAAC,WAAW,CAAA;YAE3C,IAAI,CAAC,mBAAmB,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAA;YACH,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACvC,EAAE,EAAE,KAAK,CAAC,MAAM;gBAChB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,CAAC,UAAU,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACpE,CAAC,CAAA;YACF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;QACtD,CAAC;QAED,4CAA4C;QAC5C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAA;QAChC,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAA;QACpE,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAA;QAElD,IAAI,CAAC,mBAAmB,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAA;QAClF,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACvC,EAAE,EAAE,KAAK,CAAC,MAAM;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5C,CAAC,CAAA;QACF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;IACtD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;AAC/C,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function isGsm7(text: string): boolean;
2
+ export declare function countSmsSegments(text: string): number;
3
+ //# sourceMappingURL=segments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segments.d.ts","sourceRoot":"","sources":["../../src/sms/segments.ts"],"names":[],"mappings":"AAUA,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAK5C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBrD"}
@@ -0,0 +1,33 @@
1
+ // Minimal GSM-7 detection and segment counting
2
+ const GSM_7_BASIC_CHARS = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ\u0020!\"#¤%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧabcdefghijklmnopqrstuvwxyzäöñüà";
3
+ const GSM_7_EXTENDED_CHARS = "^{}\\[~]|€";
4
+ function isGsm7Char(char) {
5
+ return GSM_7_BASIC_CHARS.includes(char) || GSM_7_EXTENDED_CHARS.includes(char);
6
+ }
7
+ export function isGsm7(text) {
8
+ for (const ch of text) {
9
+ if (!isGsm7Char(ch))
10
+ return false;
11
+ }
12
+ return true;
13
+ }
14
+ export function countSmsSegments(text) {
15
+ if (!text)
16
+ return 0;
17
+ const gsm = isGsm7(text);
18
+ // Extended table chars count as two septets in GSM-7
19
+ const gsmLength = gsm
20
+ ? Array.from(text).reduce((acc, ch) => acc + (GSM_7_EXTENDED_CHARS.includes(ch) ? 2 : 1), 0)
21
+ : 0;
22
+ if (gsm) {
23
+ if (gsmLength <= 160)
24
+ return 1;
25
+ return Math.ceil(gsmLength / 153);
26
+ }
27
+ // UCS-2
28
+ const ucsLen = Array.from(text).length;
29
+ if (ucsLen <= 70)
30
+ return 1;
31
+ return Math.ceil(ucsLen / 67);
32
+ }
33
+ //# sourceMappingURL=segments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segments.js","sourceRoot":"","sources":["../../src/sms/segments.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,iBAAiB,GACrB,mIAAmI,CAAA;AACrI,MAAM,oBAAoB,GAAG,YAAY,CAAA;AAEzC,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AAChF,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAAE,OAAO,KAAK,CAAA;IACnC,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAA;IACnB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IACxB,qDAAqD;IACrD,MAAM,SAAS,GAAG,GAAG;QACnB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5F,CAAC,CAAC,CAAC,CAAA;IAEL,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,SAAS,IAAI,GAAG;YAAE,OAAO,CAAC,CAAA;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,CAAA;IACnC,CAAC;IAED,QAAQ;IACR,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAA;IACtC,IAAI,MAAM,IAAI,EAAE;QAAE,OAAO,CAAC,CAAA;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAC/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function toIsoDateUtc(date: Date): string;
2
+ //# sourceMappingURL=temporal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../src/temporal.ts"],"names":[],"mappings":"AACA,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAG/C"}
@@ -0,0 +1,6 @@
1
+ // Minimal temporal helpers used by client apps
2
+ export function toIsoDateUtc(date) {
3
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
4
+ return d.toISOString().slice(0, 10);
5
+ }
6
+ //# sourceMappingURL=temporal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal.js","sourceRoot":"","sources":["../src/temporal.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IACjF,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AACrC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare const timezones: {
2
+ value: string;
3
+ abbr: string;
4
+ offset: number;
5
+ isdst: boolean;
6
+ text: string;
7
+ utc: string[];
8
+ }[];
9
+ //# sourceMappingURL=timezones.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timezones.d.ts","sourceRoot":"","sources":["../src/timezones.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;;;;GAgsCrB,CAAA"}