@zi2/relay-sdk 1.0.2 → 1.0.3

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.
@@ -1,4 +1,4 @@
1
- import { D as DatabaseAdapter, P as PhoneRelayRecord, c as CreateRelayInput, d as PhoneRelayPairingRecord, e as CreatePairingInput, R as RelayMessageRecord, f as CreateMessageInput } from '../types-CPJUrmcy.js';
1
+ import { D as DatabaseAdapter, P as PhoneRelayRecord, c as CreateRelayInput, d as PhoneRelayPairingRecord, e as CreatePairingInput, R as RelayMessageRecord, f as CreateMessageInput } from '../types-sIoVYfJj.js';
2
2
  import 'ws';
3
3
 
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { E as EncryptionAdapter, B as BroadcastAdapter, L as LoggerAdapter, A as AuditAdapter, a as AuditEntry, D as DatabaseAdapter, S as SmsProviderAdapter, b as SmsSendResponse, F as FallbackConfig, C as ConnectionBroker, P as PhoneRelayRecord, c as CreateRelayInput, d as PhoneRelayPairingRecord, e as CreatePairingInput, R as RelayMessageRecord, f as CreateMessageInput, g as RelaySDKConfig, h as RelaySDK } from './types-CPJUrmcy.js';
2
- export { M as MessageList, i as PairingCompleteResult, j as PairingResult, k as RelayDetail, l as RelayListItem, m as SendResult } from './types-CPJUrmcy.js';
1
+ import { E as EncryptionAdapter, B as BroadcastAdapter, L as LoggerAdapter, A as AuditAdapter, a as AuditEntry, D as DatabaseAdapter, S as SmsProviderAdapter, b as SmsSendResponse, F as FallbackConfig, C as ConnectionBroker, P as PhoneRelayRecord, c as CreateRelayInput, d as PhoneRelayPairingRecord, e as CreatePairingInput, R as RelayMessageRecord, f as CreateMessageInput, g as RelaySDKConfig, h as RelaySDK } from './types-sIoVYfJj.js';
2
+ export { M as MessageList, i as PairingCompleteResult, j as PairingResult, k as RelayDetail, l as RelayListItem, m as SendResult } from './types-sIoVYfJj.js';
3
3
  import { z } from 'zod';
4
4
  import { WebSocket } from 'ws';
5
5
 
package/dist/index.js CHANGED
@@ -326,9 +326,17 @@ function createPairingService(deps) {
326
326
  const sharedKey = deriveSharedKey(serverPrivateKey, devicePublicKey);
327
327
  const authToken = generateSecureToken(64);
328
328
  const authTokenHashed = hashToken(authToken);
329
+ const existingRelays = await db.findRelays(pairing.organizationId, "revoked");
330
+ let uniqueName = deviceName;
331
+ const existingNames = existingRelays.map((r) => r.deviceName);
332
+ if (existingNames.includes(uniqueName)) {
333
+ let counter = 2;
334
+ while (existingNames.includes(`${deviceName} (${counter})`)) counter++;
335
+ uniqueName = `${deviceName} (${counter})`;
336
+ }
329
337
  const relay = await db.createRelay({
330
338
  organizationId: pairing.organizationId,
331
- deviceName,
339
+ deviceName: uniqueName,
332
340
  platform,
333
341
  phoneNumber: phoneNumber || null,
334
342
  devicePublicKey,
@@ -348,7 +356,7 @@ function createPairingService(deps) {
348
356
  });
349
357
  await db.updatePairingStatus(pairingId, RELAY_PAIRING_STATUS.COMPLETED);
350
358
  try {
351
- await deps.onPairingComplete?.({ relayId: relay.id, orgId: pairing.organizationId, deviceName, phoneNumber });
359
+ await deps.onPairingComplete?.({ relayId: relay.id, orgId: pairing.organizationId, deviceName: uniqueName, phoneNumber });
352
360
  } catch (err) {
353
361
  deps.logger.error("onPairingComplete callback failed", { relayId: relay.id, error: String(err) });
354
362
  }
@@ -2446,6 +2454,38 @@ function createRelay(config) {
2446
2454
  async sendSMS(options) {
2447
2455
  return queue.enqueueAndWait(options);
2448
2456
  },
2457
+ async sendSMSToOrg(options) {
2458
+ const { orgId, to, body, timeoutMs } = options;
2459
+ const allRelays = await config.db.findRelays(orgId, "revoked");
2460
+ const activeRelays = allRelays.filter((r) => r.status === "active" || r.status === "degraded");
2461
+ if (activeRelays.length === 0) {
2462
+ throw new Error("No active relays available for this organization");
2463
+ }
2464
+ const todayUTC = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2465
+ const onlineRelays = activeRelays.filter((r) => isRelayOnline(r.id));
2466
+ const offlineRelays = activeRelays.filter((r) => !isRelayOnline(r.id));
2467
+ const sortedOnline = [...onlineRelays].sort((a, b) => {
2468
+ const aDaily = a.dailyResetAt && a.dailyResetAt.toISOString().slice(0, 10) === todayUTC ? a.dailySmsSent : 0;
2469
+ const bDaily = b.dailyResetAt && b.dailyResetAt.toISOString().slice(0, 10) === todayUTC ? b.dailySmsSent : 0;
2470
+ return aDaily - bDaily;
2471
+ });
2472
+ const sortedOffline = [...offlineRelays].sort((a, b) => {
2473
+ const aTime = a.lastSeenAt ? a.lastSeenAt.getTime() : 0;
2474
+ const bTime = b.lastSeenAt ? b.lastSeenAt.getTime() : 0;
2475
+ return bTime - aTime;
2476
+ });
2477
+ const candidates = [...sortedOnline, ...sortedOffline];
2478
+ let lastError;
2479
+ for (const candidate of candidates) {
2480
+ try {
2481
+ return await queue.enqueueAndWait({ relayId: candidate.id, orgId, to, body, timeoutMs });
2482
+ } catch (err) {
2483
+ lastError = err instanceof Error ? err : new Error(String(err));
2484
+ logger.warn("sendSMSToOrg: relay failed, trying next", { relayId: candidate.id, error: lastError.message });
2485
+ }
2486
+ }
2487
+ throw lastError || new Error("All relays failed");
2488
+ },
2449
2489
  async getMessages(relayId, orgId, limit = 50, offset = 0) {
2450
2490
  const relay = await config.db.findRelay(relayId, orgId);
2451
2491
  if (!relay) throw new Error("Relay not found");
@@ -1,4 +1,4 @@
1
- import { h as RelaySDK } from '../types-CPJUrmcy.js';
1
+ import { h as RelaySDK } from '../types-sIoVYfJj.js';
2
2
  import 'ws';
3
3
 
4
4
  /**
@@ -263,6 +263,12 @@ interface RelaySDK {
263
263
  body: string;
264
264
  timeoutMs?: number;
265
265
  }): Promise<SendResult>;
266
+ sendSMSToOrg(options: {
267
+ orgId: string;
268
+ to: string;
269
+ body: string;
270
+ timeoutMs?: number;
271
+ }): Promise<SendResult>;
266
272
  getMessages(relayId: string, orgId: string, limit?: number, offset?: number): Promise<MessageList>;
267
273
  isRelayOnline(relayId: string): boolean;
268
274
  getRelaySocket(relayId: string): WebSocket | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zi2/relay-sdk",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Enterprise SMS relay SDK with E2E encryption, provider fallback, and PCI DSS v4 compliance",
5
5
  "author": "Zenith Intelligence Technologies <dev@zisquare.app>",
6
6
  "license": "SEE LICENSE IN LICENSE",