sms-panel-manager 0.0.0-stage → 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.
@@ -0,0 +1,16 @@
1
+ export { D as DateParameterOptions, I as InferActionPayload, N as NumberParameterOptions, P as ParameterDescriptor, a as ParameterMetadata, S as SerializableActionMetadata, b as SmsActionDefinition, c as SmsActionMap, d as SmsManager, e as SmsParameterMap, f as SmsParameterType, g as SmsSendCommand, h as SmsSendExecutor, i as SmsSendOptions, j as SmsSendResult, k as StringParameterOptions, l as createActionPayloadSchema, m as createSmsManager, n as defineSmsActions, s as serializeSmsActions, o as sms } from './manager-B3b12wET.cjs';
2
+ export { C as CredentialEncryptionContext, a as CredentialEncryptionError, E as EncryptedCredentialEnvelope, b as EncryptionKeyring, I as InvalidParameterBindingError, O as OperationSnapshot, P as ParameterBinding, R as ResolvedSendConfiguration, S as SendConfigurationResolver, c as SendOperationStore, d as SmsOrchestrator, e as SmsOrchestratorOptions, f as applyParameterBindings, g as createEnvironmentKeyring, h as createStaticKeyring, i as decryptCredentials, j as encryptCredentials } from './encryption-BUH96uQn.cjs';
3
+ export { C as CredentialVerificationResult, P as ProviderCallContext, a as ProviderCapabilities, b as ProviderSubmissionResult, c as ProviderTemplateCapability, d as ProviderTemplateSendInput, S as SmsProviderAdapter } from './provider-QoH6qlAe.cjs';
4
+ import 'zod';
5
+
6
+ declare class InvalidIranianMobileNumberError extends TypeError {
7
+ readonly code = "invalid_recipient";
8
+ constructor();
9
+ }
10
+ declare function normalizeIranianMobile(input: string): `+98${string}`;
11
+ declare function toIranianLocalMobile(input: string): `09${string}`;
12
+
13
+ declare function createPrivacyFingerprint(secret: Uint8Array, namespace: string, value: unknown): string;
14
+ declare function fingerprintsEqual(left: string, right: string): boolean;
15
+
16
+ export { InvalidIranianMobileNumberError, createPrivacyFingerprint, fingerprintsEqual, normalizeIranianMobile, toIranianLocalMobile };
@@ -0,0 +1,16 @@
1
+ export { D as DateParameterOptions, I as InferActionPayload, N as NumberParameterOptions, P as ParameterDescriptor, a as ParameterMetadata, S as SerializableActionMetadata, b as SmsActionDefinition, c as SmsActionMap, d as SmsManager, e as SmsParameterMap, f as SmsParameterType, g as SmsSendCommand, h as SmsSendExecutor, i as SmsSendOptions, j as SmsSendResult, k as StringParameterOptions, l as createActionPayloadSchema, m as createSmsManager, n as defineSmsActions, s as serializeSmsActions, o as sms } from './manager-B3b12wET.js';
2
+ export { C as CredentialEncryptionContext, a as CredentialEncryptionError, E as EncryptedCredentialEnvelope, b as EncryptionKeyring, I as InvalidParameterBindingError, O as OperationSnapshot, P as ParameterBinding, R as ResolvedSendConfiguration, S as SendConfigurationResolver, c as SendOperationStore, d as SmsOrchestrator, e as SmsOrchestratorOptions, f as applyParameterBindings, g as createEnvironmentKeyring, h as createStaticKeyring, i as decryptCredentials, j as encryptCredentials } from './encryption-Ckv6RYE0.js';
3
+ export { C as CredentialVerificationResult, P as ProviderCallContext, a as ProviderCapabilities, b as ProviderSubmissionResult, c as ProviderTemplateCapability, d as ProviderTemplateSendInput, S as SmsProviderAdapter } from './provider-QoH6qlAe.js';
4
+ import 'zod';
5
+
6
+ declare class InvalidIranianMobileNumberError extends TypeError {
7
+ readonly code = "invalid_recipient";
8
+ constructor();
9
+ }
10
+ declare function normalizeIranianMobile(input: string): `+98${string}`;
11
+ declare function toIranianLocalMobile(input: string): `09${string}`;
12
+
13
+ declare function createPrivacyFingerprint(secret: Uint8Array, namespace: string, value: unknown): string;
14
+ declare function fingerprintsEqual(left: string, right: string): boolean;
15
+
16
+ export { InvalidIranianMobileNumberError, createPrivacyFingerprint, fingerprintsEqual, normalizeIranianMobile, toIranianLocalMobile };
package/dist/index.js ADDED
@@ -0,0 +1,546 @@
1
+ import { z } from 'zod';
2
+ import { createHmac, timingSafeEqual, randomUUID, randomBytes, createCipheriv, createDecipheriv } from 'crypto';
3
+
4
+ // src/core/actions.ts
5
+ var RESERVED_PARAMETER_KEYS = /* @__PURE__ */ new Set([
6
+ "recipient",
7
+ "idempotencyKey",
8
+ "signal",
9
+ "correlationId",
10
+ "metadata"
11
+ ]);
12
+ function defineSmsActions(actions) {
13
+ for (const [actionKey, action] of Object.entries(actions)) {
14
+ if (!/^[a-z][a-z0-9_]*$/.test(actionKey)) {
15
+ throw new TypeError(
16
+ `Invalid SMS action key "${actionKey}". Use lower snake_case.`
17
+ );
18
+ }
19
+ for (const parameterKey of Object.keys(action.params)) {
20
+ if (RESERVED_PARAMETER_KEYS.has(parameterKey)) {
21
+ throw new TypeError(
22
+ `SMS action "${actionKey}" uses reserved parameter "${parameterKey}".`
23
+ );
24
+ }
25
+ }
26
+ }
27
+ return actions;
28
+ }
29
+ function createActionPayloadSchema(action) {
30
+ const shape = {
31
+ recipient: z.string().min(1)
32
+ };
33
+ for (const [key, parameter] of Object.entries(action.params)) {
34
+ shape[key] = parameter.schema;
35
+ }
36
+ return z.object(shape).strict();
37
+ }
38
+ function serializeSmsActions(actions) {
39
+ return Object.entries(actions).map(([key, action]) => ({
40
+ key,
41
+ title: action.title,
42
+ ...action.description === void 0 ? {} : { description: action.description },
43
+ parameters: Object.entries(action.params).map(
44
+ ([parameterKey, parameter]) => ({
45
+ key: parameterKey,
46
+ title: parameter.metadata.title,
47
+ ...parameter.metadata.description === void 0 ? {} : { description: parameter.metadata.description },
48
+ type: parameter.type,
49
+ required: !parameter.isOptional
50
+ })
51
+ )
52
+ }));
53
+ }
54
+
55
+ // src/core/bindings.ts
56
+ var InvalidParameterBindingError = class extends TypeError {
57
+ code = "template_binding_invalid";
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = "InvalidParameterBindingError";
61
+ }
62
+ };
63
+ function assertSafeKey(value, label) {
64
+ if (value.length === 0 || value === "__proto__" || value === "prototype" || value === "constructor") {
65
+ throw new InvalidParameterBindingError(`Unsafe or empty ${label}.`);
66
+ }
67
+ }
68
+ function applyParameterBindings(parameters, bindings) {
69
+ if (bindings.length === 0) {
70
+ throw new InvalidParameterBindingError(
71
+ "At least one parameter binding is required."
72
+ );
73
+ }
74
+ const kind = bindings[0]?.kind;
75
+ if (bindings.some((binding) => binding.kind !== kind)) {
76
+ throw new InvalidParameterBindingError(
77
+ "Parameter binding kinds cannot be mixed."
78
+ );
79
+ }
80
+ const sources = /* @__PURE__ */ new Set();
81
+ const destinations = /* @__PURE__ */ new Set();
82
+ for (const binding of bindings) {
83
+ assertSafeKey(binding.sourceParameter, "source parameter");
84
+ if (sources.has(binding.sourceParameter)) {
85
+ throw new InvalidParameterBindingError(
86
+ `Source parameter "${binding.sourceParameter}" is mapped more than once.`
87
+ );
88
+ }
89
+ sources.add(binding.sourceParameter);
90
+ const destination = binding.kind === "named" ? binding.providerParameter : binding.kind === "fixed-slot" ? binding.slot : binding.position;
91
+ if (typeof destination === "string")
92
+ assertSafeKey(destination, "destination");
93
+ if (destinations.has(destination)) {
94
+ throw new InvalidParameterBindingError(
95
+ `Provider destination "${String(destination)}" is mapped more than once.`
96
+ );
97
+ }
98
+ destinations.add(destination);
99
+ }
100
+ if (Object.keys(parameters).some((parameter) => !sources.has(parameter))) {
101
+ throw new InvalidParameterBindingError(
102
+ "Every supplied action parameter must be mapped exactly once."
103
+ );
104
+ }
105
+ if (kind === "ordered") {
106
+ const ordered = bindings.map((binding) => {
107
+ if (binding.kind !== "ordered")
108
+ throw new InvalidParameterBindingError("Invalid binding.");
109
+ if (!Number.isSafeInteger(binding.position) || binding.position < 1) {
110
+ throw new InvalidParameterBindingError(
111
+ "Ordered positions must be positive integers."
112
+ );
113
+ }
114
+ return binding;
115
+ }).sort((left, right) => left.position - right.position);
116
+ if (ordered.some((binding, index) => binding.position !== index + 1)) {
117
+ throw new InvalidParameterBindingError(
118
+ "Ordered positions must be contiguous from one."
119
+ );
120
+ }
121
+ const values = ordered.map(
122
+ (binding) => parameters[binding.sourceParameter]
123
+ );
124
+ while (values.at(-1) === void 0) values.pop();
125
+ if (values.some((value) => value === void 0)) {
126
+ throw new InvalidParameterBindingError(
127
+ "An omitted ordered parameter cannot precede a supplied parameter."
128
+ );
129
+ }
130
+ return values;
131
+ }
132
+ const result = /* @__PURE__ */ Object.create(null);
133
+ for (const binding of bindings) {
134
+ if (binding.kind === "ordered") {
135
+ throw new InvalidParameterBindingError("Invalid ordered binding state.");
136
+ }
137
+ const destination = binding.kind === "named" ? binding.providerParameter : binding.slot;
138
+ if (binding.sourceParameter in parameters) {
139
+ result[destination] = parameters[binding.sourceParameter];
140
+ }
141
+ }
142
+ return result;
143
+ }
144
+
145
+ // src/core/phone.ts
146
+ var IRAN_MOBILE_LOCAL = /^09\d{9}$/;
147
+ var InvalidIranianMobileNumberError = class extends TypeError {
148
+ code = "invalid_recipient";
149
+ constructor() {
150
+ super("Recipient must be a valid Iranian mobile number.");
151
+ this.name = "InvalidIranianMobileNumberError";
152
+ }
153
+ };
154
+ function normalizeIranianMobile(input) {
155
+ const normalized = input.trim().replace(/^0098/, "0").replace(/^\+98/, "0").replace(/^98/, "0");
156
+ if (!IRAN_MOBILE_LOCAL.test(normalized)) {
157
+ throw new InvalidIranianMobileNumberError();
158
+ }
159
+ return `+98${normalized.slice(1)}`;
160
+ }
161
+ function toIranianLocalMobile(input) {
162
+ const canonical = normalizeIranianMobile(input);
163
+ return `0${canonical.slice(3)}`;
164
+ }
165
+
166
+ // src/core/manager.ts
167
+ function createSmsManager(options) {
168
+ return {
169
+ async send(actionKey, payload, sendOptions = {}) {
170
+ const action = options.actions[actionKey];
171
+ if (action === void 0) {
172
+ throw new TypeError(`Unknown SMS action "${actionKey}".`);
173
+ }
174
+ const validated = createActionPayloadSchema(action).parse(payload);
175
+ const { recipient, ...parameters } = validated;
176
+ return options.executor.execute({
177
+ actionKey,
178
+ recipient: normalizeIranianMobile(recipient),
179
+ parameters,
180
+ options: sendOptions
181
+ });
182
+ }
183
+ };
184
+ }
185
+ function canonicalize(value) {
186
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
187
+ return value;
188
+ }
189
+ if (typeof value === "number") {
190
+ if (!Number.isFinite(value)) {
191
+ throw new TypeError("Cannot fingerprint a non-finite number.");
192
+ }
193
+ return value;
194
+ }
195
+ if (value instanceof Date) {
196
+ if (Number.isNaN(value.getTime())) {
197
+ throw new TypeError("Cannot fingerprint an invalid date.");
198
+ }
199
+ return { $date: value.toISOString() };
200
+ }
201
+ if (Array.isArray(value)) return value.map(canonicalize);
202
+ if (typeof value === "object") {
203
+ const prototype = Object.getPrototypeOf(value);
204
+ if (prototype !== Object.prototype && prototype !== null) {
205
+ throw new TypeError("Only plain objects can be fingerprinted.");
206
+ }
207
+ const result = {};
208
+ for (const key of Object.keys(value).sort()) {
209
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
210
+ throw new TypeError("Unsafe object key cannot be fingerprinted.");
211
+ }
212
+ const item = value[key];
213
+ if (item === void 0) {
214
+ throw new TypeError("Undefined values cannot be fingerprinted.");
215
+ }
216
+ result[key] = canonicalize(item);
217
+ }
218
+ return result;
219
+ }
220
+ throw new TypeError(`Unsupported fingerprint value: ${typeof value}.`);
221
+ }
222
+ function createPrivacyFingerprint(secret, namespace, value) {
223
+ if (secret.byteLength < 32) {
224
+ throw new TypeError("Fingerprint secret must contain at least 32 bytes.");
225
+ }
226
+ const canonical = JSON.stringify(canonicalize(value));
227
+ return createHmac("sha256", secret).update(namespace).update("\0").update(canonical).digest("base64url");
228
+ }
229
+ function fingerprintsEqual(left, right) {
230
+ const leftBuffer = Buffer.from(left);
231
+ const rightBuffer = Buffer.from(right);
232
+ return leftBuffer.byteLength === rightBuffer.byteLength && timingSafeEqual(leftBuffer, rightBuffer);
233
+ }
234
+
235
+ // src/core/orchestrator.ts
236
+ function publicResult(operation) {
237
+ const status = operation.state === "reserved" || operation.state === "processing" ? "pending" : operation.state;
238
+ return {
239
+ operationId: operation.id,
240
+ status,
241
+ ...operation.providerMessageId === void 0 ? {} : { providerMessageId: operation.providerMessageId }
242
+ };
243
+ }
244
+ var SmsOrchestrator = class {
245
+ constructor(options) {
246
+ this.options = options;
247
+ this.scopeKey = options.scopeKey ?? "global";
248
+ this.retentionMs = options.operationRetentionMs ?? 30 * 24 * 60 * 60 * 1e3;
249
+ this.now = options.now ?? (() => /* @__PURE__ */ new Date());
250
+ if (this.retentionMs <= 0 || !Number.isSafeInteger(this.retentionMs)) {
251
+ throw new TypeError(
252
+ "Operation retention must be a positive integer of milliseconds."
253
+ );
254
+ }
255
+ }
256
+ options;
257
+ scopeKey;
258
+ retentionMs;
259
+ now;
260
+ async execute(command) {
261
+ if (command.options.idempotencyKey !== void 0 && (command.options.idempotencyKey.length < 1 || command.options.idempotencyKey.length > 200)) {
262
+ throw new TypeError(
263
+ "Idempotency key must contain between 1 and 200 characters."
264
+ );
265
+ }
266
+ const configuration = await this.options.configurations.resolve(
267
+ this.scopeKey,
268
+ command.actionKey
269
+ );
270
+ const providerParameters = applyParameterBindings(
271
+ command.parameters,
272
+ configuration.bindings
273
+ );
274
+ const idempotencyKey = command.options.idempotencyKey ?? randomUUID();
275
+ const expiresAt = new Date(this.now().getTime() + this.retentionMs);
276
+ const requestFingerprint = createPrivacyFingerprint(
277
+ this.options.fingerprintSecret,
278
+ "sms-send-request",
279
+ {
280
+ actionKey: command.actionKey,
281
+ recipient: command.recipient,
282
+ parameters: command.parameters,
283
+ actionDefinitionVersion: this.options.actionDefinitionVersion,
284
+ configurationId: configuration.id,
285
+ configurationVersion: configuration.version
286
+ }
287
+ );
288
+ const recipientFingerprint = createPrivacyFingerprint(
289
+ this.options.fingerprintSecret,
290
+ "sms-recipient",
291
+ command.recipient
292
+ );
293
+ const reservation = await this.options.operations.reserve({
294
+ scopeKey: this.scopeKey,
295
+ actionKey: command.actionKey,
296
+ actionDefinitionVersion: this.options.actionDefinitionVersion,
297
+ configurationVersion: configuration.version,
298
+ idempotencyKey,
299
+ requestFingerprint,
300
+ recipientFingerprint,
301
+ expiresAt
302
+ });
303
+ if (!reservation.created) return publicResult(reservation.operation);
304
+ await this.options.operations.beginAttempt({
305
+ operationId: reservation.operation.id,
306
+ providerConfigurationId: configuration.id,
307
+ adapterId: configuration.adapter.id,
308
+ expiresAt
309
+ });
310
+ let result;
311
+ try {
312
+ result = await configuration.adapter.sendTemplate(
313
+ configuration.credentials,
314
+ {
315
+ recipient: command.recipient,
316
+ template: configuration.template,
317
+ parameters: providerParameters,
318
+ ...command.options.idempotencyKey === void 0 ? {} : { clientReferenceId: command.options.idempotencyKey }
319
+ },
320
+ {
321
+ ...command.options.signal === void 0 ? {} : { signal: command.options.signal },
322
+ ...command.options.correlationId === void 0 ? {} : { correlationId: command.options.correlationId }
323
+ }
324
+ );
325
+ } catch {
326
+ result = { status: "unknown", code: "unknown_outcome" };
327
+ }
328
+ return publicResult(
329
+ await this.options.operations.completeAttempt(
330
+ reservation.operation.id,
331
+ result
332
+ )
333
+ );
334
+ }
335
+ };
336
+ function descriptor(type, schema, metadata) {
337
+ return {
338
+ type,
339
+ schema,
340
+ metadata,
341
+ isOptional: false,
342
+ optional() {
343
+ return optionalDescriptor(type, schema.optional(), metadata);
344
+ }
345
+ };
346
+ }
347
+ function optionalDescriptor(type, schema, metadata) {
348
+ return {
349
+ type,
350
+ schema,
351
+ metadata,
352
+ isOptional: true,
353
+ optional() {
354
+ return optionalDescriptor(type, schema.optional(), metadata);
355
+ }
356
+ };
357
+ }
358
+ function stringParameter(options) {
359
+ let schema = z.string();
360
+ if (options.minLength !== void 0) schema = schema.min(options.minLength);
361
+ if (options.maxLength !== void 0) schema = schema.max(options.maxLength);
362
+ if (options.pattern !== void 0) schema = schema.regex(options.pattern);
363
+ return descriptor("string", schema, options);
364
+ }
365
+ function numberParameter(options) {
366
+ let schema = z.number();
367
+ if (options.min !== void 0) schema = schema.min(options.min);
368
+ if (options.max !== void 0) schema = schema.max(options.max);
369
+ return descriptor("number", schema, options);
370
+ }
371
+ function integerParameter(options) {
372
+ let schema = z.number().int();
373
+ if (options.min !== void 0) schema = schema.min(options.min);
374
+ if (options.max !== void 0) schema = schema.max(options.max);
375
+ return descriptor("integer", schema, options);
376
+ }
377
+ function booleanParameter(options) {
378
+ return descriptor("boolean", z.boolean(), options);
379
+ }
380
+ function dateParameter(options) {
381
+ let schema = z.date();
382
+ if (options.min !== void 0) schema = schema.min(options.min);
383
+ if (options.max !== void 0) schema = schema.max(options.max);
384
+ return descriptor("date", schema, options);
385
+ }
386
+ function enumParameter(values, options) {
387
+ return descriptor("enum", z.enum(values), options);
388
+ }
389
+ var sms = {
390
+ string: stringParameter,
391
+ number: numberParameter,
392
+ integer: integerParameter,
393
+ boolean: booleanParameter,
394
+ date: dateParameter,
395
+ enum: enumParameter
396
+ };
397
+ var ALGORITHM = "aes-256-gcm";
398
+ var NONCE_LENGTH = 12;
399
+ var AUTH_TAG_LENGTH = 16;
400
+ var KEY_LENGTH = 32;
401
+ var CredentialEncryptionError = class extends Error {
402
+ code = "credential_encryption_failed";
403
+ constructor(message, options) {
404
+ super(message, options);
405
+ this.name = "CredentialEncryptionError";
406
+ }
407
+ };
408
+ function associatedData(context, keyId) {
409
+ return Buffer.from(
410
+ JSON.stringify({
411
+ type: "sms-provider-credentials",
412
+ configurationId: context.configurationId,
413
+ adapterId: context.adapterId,
414
+ scopeKey: context.scopeKey,
415
+ credentialRevision: context.credentialRevision,
416
+ schemaVersion: context.schemaVersion,
417
+ keyId
418
+ }),
419
+ "utf8"
420
+ );
421
+ }
422
+ function validKey(key, keyId) {
423
+ if (key === void 0) {
424
+ throw new CredentialEncryptionError(
425
+ `Encryption key "${keyId}" is unavailable.`
426
+ );
427
+ }
428
+ if (key.byteLength !== KEY_LENGTH) {
429
+ throw new CredentialEncryptionError(
430
+ `Encryption key "${keyId}" must be exactly 32 bytes.`
431
+ );
432
+ }
433
+ return Buffer.from(key);
434
+ }
435
+ async function encryptCredentials(credentials, context, keyring) {
436
+ const keyId = keyring.activeKeyId;
437
+ const key = validKey(await keyring.getKey(keyId), keyId);
438
+ const nonce = randomBytes(NONCE_LENGTH);
439
+ try {
440
+ const cipher = createCipheriv(ALGORITHM, key, nonce, {
441
+ authTagLength: AUTH_TAG_LENGTH
442
+ });
443
+ cipher.setAAD(associatedData(context, keyId));
444
+ const plaintext = Buffer.from(JSON.stringify(credentials), "utf8");
445
+ const ciphertext = Buffer.concat([
446
+ cipher.update(plaintext),
447
+ cipher.final()
448
+ ]);
449
+ return {
450
+ algorithm: ALGORITHM,
451
+ keyId,
452
+ configurationId: context.configurationId,
453
+ adapterId: context.adapterId,
454
+ scopeKey: context.scopeKey,
455
+ credentialRevision: context.credentialRevision,
456
+ nonce: nonce.toString("base64"),
457
+ ciphertext: ciphertext.toString("base64"),
458
+ authTag: cipher.getAuthTag().toString("base64"),
459
+ schemaVersion: context.schemaVersion
460
+ };
461
+ } catch (cause) {
462
+ throw new CredentialEncryptionError(
463
+ "Could not encrypt provider credentials.",
464
+ {
465
+ cause
466
+ }
467
+ );
468
+ } finally {
469
+ key.fill(0);
470
+ }
471
+ }
472
+ async function decryptCredentials(envelope, context, keyring) {
473
+ if (envelope.algorithm !== ALGORITHM) {
474
+ throw new CredentialEncryptionError(
475
+ "Unsupported credential encryption algorithm."
476
+ );
477
+ }
478
+ if (envelope.schemaVersion !== context.schemaVersion) {
479
+ throw new CredentialEncryptionError("Credential schema version mismatch.");
480
+ }
481
+ if (envelope.configurationId !== context.configurationId || envelope.adapterId !== context.adapterId || envelope.scopeKey !== context.scopeKey || envelope.credentialRevision !== context.credentialRevision) {
482
+ throw new CredentialEncryptionError(
483
+ "Credential encryption context mismatch."
484
+ );
485
+ }
486
+ const nonce = Buffer.from(envelope.nonce, "base64");
487
+ const authTag = Buffer.from(envelope.authTag, "base64");
488
+ if (nonce.byteLength !== NONCE_LENGTH || authTag.byteLength !== AUTH_TAG_LENGTH) {
489
+ throw new CredentialEncryptionError(
490
+ "Credential envelope has invalid nonce or tag length."
491
+ );
492
+ }
493
+ const key = validKey(await keyring.getKey(envelope.keyId), envelope.keyId);
494
+ try {
495
+ const decipher = createDecipheriv(ALGORITHM, key, nonce, {
496
+ authTagLength: AUTH_TAG_LENGTH
497
+ });
498
+ decipher.setAAD(associatedData(context, envelope.keyId));
499
+ decipher.setAuthTag(authTag);
500
+ const plaintext = Buffer.concat([
501
+ decipher.update(Buffer.from(envelope.ciphertext, "base64")),
502
+ decipher.final()
503
+ ]);
504
+ return JSON.parse(plaintext.toString("utf8"));
505
+ } catch (cause) {
506
+ throw new CredentialEncryptionError(
507
+ "Provider credentials could not be authenticated or decrypted.",
508
+ { cause }
509
+ );
510
+ } finally {
511
+ key.fill(0);
512
+ }
513
+ }
514
+ function createStaticKeyring(options) {
515
+ if (!(options.activeKeyId in options.keys)) {
516
+ throw new CredentialEncryptionError(
517
+ `Active encryption key "${options.activeKeyId}" is unavailable.`
518
+ );
519
+ }
520
+ const keys = new Map(
521
+ Object.entries(options.keys).map(([id, key]) => [id, validKey(key, id)])
522
+ );
523
+ return {
524
+ activeKeyId: options.activeKeyId,
525
+ getKey(keyId) {
526
+ const key = keys.get(keyId);
527
+ return key === void 0 ? void 0 : Buffer.from(key);
528
+ }
529
+ };
530
+ }
531
+ function createEnvironmentKeyring(options) {
532
+ const encoding = options.encoding ?? "base64";
533
+ return createStaticKeyring({
534
+ activeKeyId: options.activeKeyId,
535
+ keys: Object.fromEntries(
536
+ Object.entries(options.keys).map(([keyId, value]) => [
537
+ keyId,
538
+ Buffer.from(value, encoding)
539
+ ])
540
+ )
541
+ });
542
+ }
543
+
544
+ export { CredentialEncryptionError, InvalidIranianMobileNumberError, InvalidParameterBindingError, SmsOrchestrator, applyParameterBindings, createActionPayloadSchema, createEnvironmentKeyring, createPrivacyFingerprint, createSmsManager, createStaticKeyring, decryptCredentials, defineSmsActions, encryptCredentials, fingerprintsEqual, normalizeIranianMobile, serializeSmsActions, sms, toIranianLocalMobile };
545
+ //# sourceMappingURL=index.js.map
546
+ //# sourceMappingURL=index.js.map