@verixo/sdk 0.1.0 → 0.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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/resources/analytics.ts","../src/resources/numbers.ts","../src/resources/sessions.ts","../src/subscribe.ts"],"sourcesContent":["import { HttpClient } from \"./client.js\";\nimport { Analytics } from \"./resources/analytics.js\";\nimport { Numbers } from \"./resources/numbers.js\";\nimport { Sessions } from \"./resources/sessions.js\";\nimport { subscribe } from \"./subscribe.js\";\nimport type { OtpPush, VerixoOptions } from \"./types.js\";\n\nexport { VerixoError } from \"./errors.js\";\nexport type {\n DeliveryRate,\n OtpPush,\n PurchaseNumberParams,\n PurchaseResult,\n SearchNumbersParams,\n SearchNumbersResult,\n SessionState,\n SessionStatus,\n VerixoOptions,\n VirtualNumber,\n} from \"./types.js\";\n\nexport default class Verixo {\n readonly numbers: Numbers;\n readonly sessions: Sessions;\n readonly analytics: Analytics;\n private readonly http: HttpClient;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n this.http = new HttpClient(apiKey, options);\n this.numbers = new Numbers(this.http);\n this.sessions = new Sessions(this.http);\n this.analytics = new Analytics(this.http);\n }\n\n /**\n * Get pushed the OTP for a session in real time, instead of polling\n * `sessions.get()`. Returns an unsubscribe function.\n *\n * @example\n * const session = await vc.numbers.purchase({ serviceSlug: 'whatsapp', countryCode: 'NG' })\n * vc.subscribe(session.sessionToken, ({ otp, latencyMs }) => {\n * console.log(`OTP: ${otp} in ${latencyMs}ms`)\n * })\n */\n subscribe(sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n return subscribe(this.http, sessionToken, onOtp);\n }\n}\n","export interface VerixoErrorOptions {\n status: number;\n code?: string;\n detail?: string;\n raw?: unknown;\n}\n\n/**\n * Thrown for any non-2xx response from the Verixo API. `status` is always\n * present; `code`/`detail` are populated when the gateway returns a JSON\n * error body (most do) -- a small number of paths (e.g. an invalid API key\n * rejected before reaching a controller) return an empty body, in which case\n * only `status` and a generic `message` are available.\n */\nexport class VerixoError extends Error {\n readonly status: number;\n readonly code?: string;\n readonly detail?: string;\n readonly raw?: unknown;\n\n constructor(message: string, options: VerixoErrorOptions) {\n super(message);\n this.name = \"VerixoError\";\n this.status = options.status;\n this.code = options.code;\n this.detail = options.detail;\n this.raw = options.raw;\n }\n}\n\nconst STATUS_FALLBACKS: Record<number, string> = {\n 401: \"Missing or invalid API key.\",\n 402: \"Insufficient wallet balance.\",\n 403: \"You don't have access to this resource.\",\n 404: \"Not found.\",\n 408: \"Request timed out.\",\n 422: \"The request did not meet a required condition (e.g. minScore).\",\n 429: \"Rate limit exceeded.\",\n};\n\nexport async function errorFromResponse(res: Response): Promise<VerixoError> {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = undefined;\n }\n\n const obj = (body && typeof body === \"object\" ? body : {}) as Record<string, unknown>;\n const detail = (obj.detail ?? obj.error ?? obj.message) as string | undefined;\n const code = (obj.grpcCode ?? obj.code) as string | undefined;\n const message = detail ?? STATUS_FALLBACKS[res.status] ?? `Request failed with status ${res.status}`;\n\n return new VerixoError(message, { status: res.status, code, detail, raw: body });\n}\n","import { errorFromResponse } from \"./errors.js\";\nimport type { VerixoOptions } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.verixo.com\";\n\nexport class HttpClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n if (!apiKey) {\n throw new Error(\"Verixo: an API key (or JWT) is required, e.g. new Verixo('vc_test_...')\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n }\n\n async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n // The gateway classifies the credential by sniffing the raw Authorization header for a\n // vc_test_/vc_live_ prefix -- a \"Bearer \" prefix on an API key would make it misclassify\n // the request as a (malformed) JWT and reject it, so API keys go out unprefixed.\n const isApiKey = this.apiKey.startsWith(\"vc_test_\") || this.apiKey.startsWith(\"vc_live_\");\n const authorization = isApiKey ? this.apiKey : `Bearer ${this.apiKey}`;\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n Authorization: authorization,\n ...(init.body ? { \"Content-Type\": \"application/json\" } : {}),\n ...init.headers,\n },\n });\n\n if (!res.ok) {\n throw await errorFromResponse(res);\n }\n\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n\n get<T>(path: string): Promise<T> {\n return this.request<T>(path, { method: \"GET\" });\n }\n\n post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(path, { method: \"POST\", body: body ? JSON.stringify(body) : undefined });\n }\n\n /** ws:// or wss:// origin derived from baseUrl, for the OTP push subscription. */\n get wsOrigin(): string {\n return this.baseUrl.replace(/^http/, \"ws\");\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { DeliveryRate } from \"../types.js\";\n\nexport class Analytics {\n constructor(private readonly http: HttpClient) {}\n\n /** Public delivery-rate stats by country for a service. No auth required by the API itself. */\n rates(serviceSlug = \"whatsapp\"): Promise<{ rates: DeliveryRate[]; updatedAt: string }> {\n return this.http.get(`/api/v1/analytics/rates?serviceSlug=${encodeURIComponent(serviceSlug)}`);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { PurchaseNumberParams, PurchaseResult, SearchNumbersParams, SearchNumbersResult } from \"../types.js\";\n\nexport class Numbers {\n constructor(private readonly http: HttpClient) {}\n\n /** Browse available numbers ranked by Health Score (TM). No purchase is made. */\n search(params: SearchNumbersParams): Promise<SearchNumbersResult> {\n const q = new URLSearchParams({ serviceSlug: params.serviceSlug });\n if (params.countryCode) q.set(\"countryCode\", params.countryCode);\n if (params.minScore != null) q.set(\"minScore\", String(params.minScore));\n if (params.limit != null) q.set(\"limit\", String(params.limit));\n return this.http.get<SearchNumbersResult>(`/api/v1/numbers/search?${q}`);\n }\n\n /**\n * Buy a number for a service + country. The server picks the best available\n * candidate by Health Score automatically -- there's no numberId parameter,\n * since by the time you'd pass one back the number may already be gone.\n */\n purchase(params: PurchaseNumberParams): Promise<PurchaseResult> {\n return this.http.post<PurchaseResult>(\"/api/v1/numbers/purchase\", params);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { SessionStatus } from \"../types.js\";\n\nexport class Sessions {\n constructor(private readonly http: HttpClient) {}\n\n /** Poll a session's current delivery status. */\n get(sessionToken: string): Promise<SessionStatus> {\n return this.http.get<SessionStatus>(`/api/v1/numbers/session/${encodeURIComponent(sessionToken)}`);\n }\n\n /**\n * Poll until the session reaches a terminal state (DELIVERED, REFUNDED, EXPIRED, FAILED)\n * or the timeout elapses. Prefer `vc.subscribe()` for real-time push -- this is a fallback\n * for environments where a persistent WebSocket isn't practical (e.g. serverless functions).\n */\n async waitForOtp(sessionToken: string, timeoutMs = 90_000, intervalMs = 2_000): Promise<SessionStatus> {\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const session = await this.get(sessionToken);\n if (session.status !== \"PENDING\") return session;\n if (Date.now() >= deadline) return session;\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n}\n","import { Client } from \"@stomp/stompjs\";\nimport type { HttpClient } from \"./client.js\";\nimport type { OtpPush } from \"./types.js\";\n\n/**\n * Subscribes to real-time OTP push for a session over the gateway's WebSocket\n * proxy (wss://.../ws -> delivery-service's STOMP broker, topic\n * /topic/otp/{sessionToken}). Requires a global WebSocket implementation --\n * present natively in browsers and Node 22+; on older Node, pass a `ws`\n * instance via globalThis.WebSocket before calling subscribe().\n *\n * Returns an unsubscribe function. The callback fires at most once per\n * session (a session only ever delivers one OTP).\n */\nexport function subscribe(http: HttpClient, sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\n \"Verixo.subscribe() requires a global WebSocket implementation. \" +\n \"This is built into browsers and Node 22+; on older Node, polyfill \" +\n \"globalThis.WebSocket (e.g. with the 'ws' package) before calling subscribe().\"\n );\n }\n\n const subscribedAt = Date.now();\n const client = new Client({\n brokerURL: `${http.wsOrigin}/ws`,\n reconnectDelay: 5_000,\n onConnect: () => {\n client.subscribe(`/topic/otp/${sessionToken}`, (message) => {\n try {\n const payload = JSON.parse(message.body) as Omit<OtpPush, \"latencyMs\">;\n onOtp({ ...payload, latencyMs: Date.now() - subscribedAt });\n } catch {\n // Ignore malformed frames rather than crashing the caller's process.\n }\n });\n },\n });\n\n client.activate();\n return () => {\n void client.deactivate();\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/resources/analytics.ts","../src/resources/numbers.ts","../src/resources/sessions.ts","../src/subscribe.ts"],"sourcesContent":["import { HttpClient } from \"./client.js\";\nimport { Analytics } from \"./resources/analytics.js\";\nimport { Numbers } from \"./resources/numbers.js\";\nimport { Sessions } from \"./resources/sessions.js\";\nimport { subscribe } from \"./subscribe.js\";\nimport type { OtpPush, VerixoOptions } from \"./types.js\";\n\nexport { VerixoError } from \"./errors.js\";\nexport type {\n DeliveryRate,\n OtpPush,\n PurchaseNumberParams,\n PurchaseResult,\n SearchNumbersParams,\n SearchNumbersResult,\n SessionState,\n SessionStatus,\n VerixoOptions,\n VirtualNumber,\n} from \"./types.js\";\n\nexport default class Verixo {\n readonly numbers: Numbers;\n readonly sessions: Sessions;\n readonly analytics: Analytics;\n private readonly http: HttpClient;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n this.http = new HttpClient(apiKey, options);\n this.numbers = new Numbers(this.http);\n this.sessions = new Sessions(this.http);\n this.analytics = new Analytics(this.http);\n }\n\n /**\n * Get pushed the OTP for a session in real time, instead of polling\n * `sessions.get()`. Returns an unsubscribe function.\n *\n * @example\n * const session = await vc.numbers.purchase({ serviceSlug: 'whatsapp', countryCode: 'NG' })\n * vc.subscribe(session.sessionToken, ({ otp, latencyMs }) => {\n * console.log(`OTP: ${otp} in ${latencyMs}ms`)\n * })\n */\n subscribe(sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n return subscribe(this.http, sessionToken, onOtp);\n }\n}\n","export interface VerixoErrorOptions {\n status: number;\n code?: string;\n detail?: string;\n raw?: unknown;\n}\n\n/**\n * Thrown for any non-2xx response from the Verixo API. `status` is always\n * present; `code`/`detail` are populated when the gateway returns a JSON\n * error body (most do) -- a small number of paths (e.g. an invalid API key\n * rejected before reaching a controller) return an empty body, in which case\n * only `status` and a generic `message` are available.\n */\nexport class VerixoError extends Error {\n readonly status: number;\n readonly code?: string;\n readonly detail?: string;\n readonly raw?: unknown;\n\n constructor(message: string, options: VerixoErrorOptions) {\n super(message);\n this.name = \"VerixoError\";\n this.status = options.status;\n this.code = options.code;\n this.detail = options.detail;\n this.raw = options.raw;\n }\n}\n\nconst STATUS_FALLBACKS: Record<number, string> = {\n 401: \"Missing or invalid API key.\",\n 402: \"Insufficient wallet balance.\",\n 403: \"You don't have access to this resource.\",\n 404: \"Not found.\",\n 408: \"Request timed out.\",\n 422: \"The request did not meet a required condition (e.g. minScore).\",\n 429: \"Rate limit exceeded.\",\n};\n\nexport async function errorFromResponse(res: Response): Promise<VerixoError> {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = undefined;\n }\n\n const obj = (body && typeof body === \"object\" ? body : {}) as Record<string, unknown>;\n const detail = (obj.detail ?? obj.error ?? obj.message) as string | undefined;\n const code = (obj.grpcCode ?? obj.code) as string | undefined;\n const message = detail ?? STATUS_FALLBACKS[res.status] ?? `Request failed with status ${res.status}`;\n\n return new VerixoError(message, { status: res.status, code, detail, raw: body });\n}\n","import { errorFromResponse } from \"./errors.js\";\nimport type { VerixoOptions } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.verifiedcore.com\";\n\nexport class HttpClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n if (!apiKey) {\n throw new Error(\"Verixo: an API key (or JWT) is required, e.g. new Verixo('vc_test_...')\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n }\n\n async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n // The gateway classifies the credential by sniffing the raw Authorization header for a\n // vc_test_/vc_live_ prefix -- a \"Bearer \" prefix on an API key would make it misclassify\n // the request as a (malformed) JWT and reject it, so API keys go out unprefixed.\n const isApiKey = this.apiKey.startsWith(\"vc_test_\") || this.apiKey.startsWith(\"vc_live_\");\n const authorization = isApiKey ? this.apiKey : `Bearer ${this.apiKey}`;\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n Authorization: authorization,\n ...(init.body ? { \"Content-Type\": \"application/json\" } : {}),\n ...init.headers,\n },\n });\n\n if (!res.ok) {\n throw await errorFromResponse(res);\n }\n\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n\n get<T>(path: string): Promise<T> {\n return this.request<T>(path, { method: \"GET\" });\n }\n\n post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(path, { method: \"POST\", body: body ? JSON.stringify(body) : undefined });\n }\n\n /** ws:// or wss:// origin derived from baseUrl, for the OTP push subscription. */\n get wsOrigin(): string {\n return this.baseUrl.replace(/^http/, \"ws\");\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { DeliveryRate } from \"../types.js\";\n\nexport class Analytics {\n constructor(private readonly http: HttpClient) {}\n\n /** Public delivery-rate stats by country for a service. No auth required by the API itself. */\n rates(serviceSlug = \"whatsapp\"): Promise<{ rates: DeliveryRate[]; updatedAt: string }> {\n return this.http.get(`/api/v1/analytics/rates?serviceSlug=${encodeURIComponent(serviceSlug)}`);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { PurchaseNumberParams, PurchaseResult, SearchNumbersParams, SearchNumbersResult } from \"../types.js\";\n\nexport class Numbers {\n constructor(private readonly http: HttpClient) {}\n\n /** Browse available numbers ranked by Health Score (TM). No purchase is made. */\n search(params: SearchNumbersParams): Promise<SearchNumbersResult> {\n const q = new URLSearchParams({ serviceSlug: params.serviceSlug });\n if (params.countryCode) q.set(\"countryCode\", params.countryCode);\n if (params.minScore != null) q.set(\"minScore\", String(params.minScore));\n if (params.limit != null) q.set(\"limit\", String(params.limit));\n return this.http.get<SearchNumbersResult>(`/api/v1/numbers/search?${q}`);\n }\n\n /**\n * Buy a number for a service + country. The server picks the best available\n * candidate by Health Score automatically -- there's no numberId parameter,\n * since by the time you'd pass one back the number may already be gone.\n */\n purchase(params: PurchaseNumberParams): Promise<PurchaseResult> {\n return this.http.post<PurchaseResult>(\"/api/v1/numbers/purchase\", params);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { SessionStatus } from \"../types.js\";\n\nexport class Sessions {\n constructor(private readonly http: HttpClient) {}\n\n /** Poll a session's current delivery status. */\n get(sessionToken: string): Promise<SessionStatus> {\n return this.http.get<SessionStatus>(`/api/v1/numbers/session/${encodeURIComponent(sessionToken)}`);\n }\n\n /**\n * Poll until the session reaches a terminal state (DELIVERED, REFUNDED, EXPIRED, FAILED)\n * or the timeout elapses. Prefer `vc.subscribe()` for real-time push -- this is a fallback\n * for environments where a persistent WebSocket isn't practical (e.g. serverless functions).\n */\n async waitForOtp(sessionToken: string, timeoutMs = 90_000, intervalMs = 2_000): Promise<SessionStatus> {\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const session = await this.get(sessionToken);\n if (session.status !== \"PENDING\") return session;\n if (Date.now() >= deadline) return session;\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n}\n","import { Client } from \"@stomp/stompjs\";\nimport type { HttpClient } from \"./client.js\";\nimport type { OtpPush } from \"./types.js\";\n\n/**\n * Subscribes to real-time OTP push for a session over the gateway's WebSocket\n * proxy (wss://.../ws -> delivery-service's STOMP broker, topic\n * /topic/otp/{sessionToken}). Requires a global WebSocket implementation --\n * present natively in browsers and Node 22+; on older Node, pass a `ws`\n * instance via globalThis.WebSocket before calling subscribe().\n *\n * Returns an unsubscribe function. The callback fires at most once per\n * session (a session only ever delivers one OTP).\n */\nexport function subscribe(http: HttpClient, sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\n \"Verixo.subscribe() requires a global WebSocket implementation. \" +\n \"This is built into browsers and Node 22+; on older Node, polyfill \" +\n \"globalThis.WebSocket (e.g. with the 'ws' package) before calling subscribe().\"\n );\n }\n\n const subscribedAt = Date.now();\n const client = new Client({\n brokerURL: `${http.wsOrigin}/ws`,\n reconnectDelay: 5_000,\n onConnect: () => {\n client.subscribe(`/topic/otp/${sessionToken}`, (message) => {\n try {\n const payload = JSON.parse(message.body) as Omit<OtpPush, \"latencyMs\">;\n onOtp({ ...payload, latencyMs: Date.now() - subscribedAt });\n } catch {\n // Ignore malformed frames rather than crashing the caller's process.\n }\n });\n },\n });\n\n client.activate();\n return () => {\n void client.deactivate();\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/resources/analytics.ts","../src/resources/numbers.ts","../src/resources/sessions.ts","../src/subscribe.ts","../src/index.ts"],"sourcesContent":["export interface VerixoErrorOptions {\n status: number;\n code?: string;\n detail?: string;\n raw?: unknown;\n}\n\n/**\n * Thrown for any non-2xx response from the Verixo API. `status` is always\n * present; `code`/`detail` are populated when the gateway returns a JSON\n * error body (most do) -- a small number of paths (e.g. an invalid API key\n * rejected before reaching a controller) return an empty body, in which case\n * only `status` and a generic `message` are available.\n */\nexport class VerixoError extends Error {\n readonly status: number;\n readonly code?: string;\n readonly detail?: string;\n readonly raw?: unknown;\n\n constructor(message: string, options: VerixoErrorOptions) {\n super(message);\n this.name = \"VerixoError\";\n this.status = options.status;\n this.code = options.code;\n this.detail = options.detail;\n this.raw = options.raw;\n }\n}\n\nconst STATUS_FALLBACKS: Record<number, string> = {\n 401: \"Missing or invalid API key.\",\n 402: \"Insufficient wallet balance.\",\n 403: \"You don't have access to this resource.\",\n 404: \"Not found.\",\n 408: \"Request timed out.\",\n 422: \"The request did not meet a required condition (e.g. minScore).\",\n 429: \"Rate limit exceeded.\",\n};\n\nexport async function errorFromResponse(res: Response): Promise<VerixoError> {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = undefined;\n }\n\n const obj = (body && typeof body === \"object\" ? body : {}) as Record<string, unknown>;\n const detail = (obj.detail ?? obj.error ?? obj.message) as string | undefined;\n const code = (obj.grpcCode ?? obj.code) as string | undefined;\n const message = detail ?? STATUS_FALLBACKS[res.status] ?? `Request failed with status ${res.status}`;\n\n return new VerixoError(message, { status: res.status, code, detail, raw: body });\n}\n","import { errorFromResponse } from \"./errors.js\";\nimport type { VerixoOptions } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.verixo.com\";\n\nexport class HttpClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n if (!apiKey) {\n throw new Error(\"Verixo: an API key (or JWT) is required, e.g. new Verixo('vc_test_...')\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n }\n\n async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n // The gateway classifies the credential by sniffing the raw Authorization header for a\n // vc_test_/vc_live_ prefix -- a \"Bearer \" prefix on an API key would make it misclassify\n // the request as a (malformed) JWT and reject it, so API keys go out unprefixed.\n const isApiKey = this.apiKey.startsWith(\"vc_test_\") || this.apiKey.startsWith(\"vc_live_\");\n const authorization = isApiKey ? this.apiKey : `Bearer ${this.apiKey}`;\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n Authorization: authorization,\n ...(init.body ? { \"Content-Type\": \"application/json\" } : {}),\n ...init.headers,\n },\n });\n\n if (!res.ok) {\n throw await errorFromResponse(res);\n }\n\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n\n get<T>(path: string): Promise<T> {\n return this.request<T>(path, { method: \"GET\" });\n }\n\n post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(path, { method: \"POST\", body: body ? JSON.stringify(body) : undefined });\n }\n\n /** ws:// or wss:// origin derived from baseUrl, for the OTP push subscription. */\n get wsOrigin(): string {\n return this.baseUrl.replace(/^http/, \"ws\");\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { DeliveryRate } from \"../types.js\";\n\nexport class Analytics {\n constructor(private readonly http: HttpClient) {}\n\n /** Public delivery-rate stats by country for a service. No auth required by the API itself. */\n rates(serviceSlug = \"whatsapp\"): Promise<{ rates: DeliveryRate[]; updatedAt: string }> {\n return this.http.get(`/api/v1/analytics/rates?serviceSlug=${encodeURIComponent(serviceSlug)}`);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { PurchaseNumberParams, PurchaseResult, SearchNumbersParams, SearchNumbersResult } from \"../types.js\";\n\nexport class Numbers {\n constructor(private readonly http: HttpClient) {}\n\n /** Browse available numbers ranked by Health Score (TM). No purchase is made. */\n search(params: SearchNumbersParams): Promise<SearchNumbersResult> {\n const q = new URLSearchParams({ serviceSlug: params.serviceSlug });\n if (params.countryCode) q.set(\"countryCode\", params.countryCode);\n if (params.minScore != null) q.set(\"minScore\", String(params.minScore));\n if (params.limit != null) q.set(\"limit\", String(params.limit));\n return this.http.get<SearchNumbersResult>(`/api/v1/numbers/search?${q}`);\n }\n\n /**\n * Buy a number for a service + country. The server picks the best available\n * candidate by Health Score automatically -- there's no numberId parameter,\n * since by the time you'd pass one back the number may already be gone.\n */\n purchase(params: PurchaseNumberParams): Promise<PurchaseResult> {\n return this.http.post<PurchaseResult>(\"/api/v1/numbers/purchase\", params);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { SessionStatus } from \"../types.js\";\n\nexport class Sessions {\n constructor(private readonly http: HttpClient) {}\n\n /** Poll a session's current delivery status. */\n get(sessionToken: string): Promise<SessionStatus> {\n return this.http.get<SessionStatus>(`/api/v1/numbers/session/${encodeURIComponent(sessionToken)}`);\n }\n\n /**\n * Poll until the session reaches a terminal state (DELIVERED, REFUNDED, EXPIRED, FAILED)\n * or the timeout elapses. Prefer `vc.subscribe()` for real-time push -- this is a fallback\n * for environments where a persistent WebSocket isn't practical (e.g. serverless functions).\n */\n async waitForOtp(sessionToken: string, timeoutMs = 90_000, intervalMs = 2_000): Promise<SessionStatus> {\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const session = await this.get(sessionToken);\n if (session.status !== \"PENDING\") return session;\n if (Date.now() >= deadline) return session;\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n}\n","import { Client } from \"@stomp/stompjs\";\nimport type { HttpClient } from \"./client.js\";\nimport type { OtpPush } from \"./types.js\";\n\n/**\n * Subscribes to real-time OTP push for a session over the gateway's WebSocket\n * proxy (wss://.../ws -> delivery-service's STOMP broker, topic\n * /topic/otp/{sessionToken}). Requires a global WebSocket implementation --\n * present natively in browsers and Node 22+; on older Node, pass a `ws`\n * instance via globalThis.WebSocket before calling subscribe().\n *\n * Returns an unsubscribe function. The callback fires at most once per\n * session (a session only ever delivers one OTP).\n */\nexport function subscribe(http: HttpClient, sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\n \"Verixo.subscribe() requires a global WebSocket implementation. \" +\n \"This is built into browsers and Node 22+; on older Node, polyfill \" +\n \"globalThis.WebSocket (e.g. with the 'ws' package) before calling subscribe().\"\n );\n }\n\n const subscribedAt = Date.now();\n const client = new Client({\n brokerURL: `${http.wsOrigin}/ws`,\n reconnectDelay: 5_000,\n onConnect: () => {\n client.subscribe(`/topic/otp/${sessionToken}`, (message) => {\n try {\n const payload = JSON.parse(message.body) as Omit<OtpPush, \"latencyMs\">;\n onOtp({ ...payload, latencyMs: Date.now() - subscribedAt });\n } catch {\n // Ignore malformed frames rather than crashing the caller's process.\n }\n });\n },\n });\n\n client.activate();\n return () => {\n void client.deactivate();\n };\n}\n","import { HttpClient } from \"./client.js\";\nimport { Analytics } from \"./resources/analytics.js\";\nimport { Numbers } from \"./resources/numbers.js\";\nimport { Sessions } from \"./resources/sessions.js\";\nimport { subscribe } from \"./subscribe.js\";\nimport type { OtpPush, VerixoOptions } from \"./types.js\";\n\nexport { VerixoError } from \"./errors.js\";\nexport type {\n DeliveryRate,\n OtpPush,\n PurchaseNumberParams,\n PurchaseResult,\n SearchNumbersParams,\n SearchNumbersResult,\n SessionState,\n SessionStatus,\n VerixoOptions,\n VirtualNumber,\n} from \"./types.js\";\n\nexport default class Verixo {\n readonly numbers: Numbers;\n readonly sessions: Sessions;\n readonly analytics: Analytics;\n private readonly http: HttpClient;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n this.http = new HttpClient(apiKey, options);\n this.numbers = new Numbers(this.http);\n this.sessions = new Sessions(this.http);\n this.analytics = new Analytics(this.http);\n }\n\n /**\n * Get pushed the OTP for a session in real time, instead of polling\n * `sessions.get()`. Returns an unsubscribe function.\n *\n * @example\n * const session = await vc.numbers.purchase({ serviceSlug: 'whatsapp', countryCode: 'NG' })\n * vc.subscribe(session.sessionToken, ({ otp, latencyMs }) => {\n * console.log(`OTP: ${otp} in ${latencyMs}ms`)\n * })\n */\n subscribe(sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n return subscribe(this.http, sessionToken, onOtp);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/resources/analytics.ts","../src/resources/numbers.ts","../src/resources/sessions.ts","../src/subscribe.ts","../src/index.ts"],"sourcesContent":["export interface VerixoErrorOptions {\n status: number;\n code?: string;\n detail?: string;\n raw?: unknown;\n}\n\n/**\n * Thrown for any non-2xx response from the Verixo API. `status` is always\n * present; `code`/`detail` are populated when the gateway returns a JSON\n * error body (most do) -- a small number of paths (e.g. an invalid API key\n * rejected before reaching a controller) return an empty body, in which case\n * only `status` and a generic `message` are available.\n */\nexport class VerixoError extends Error {\n readonly status: number;\n readonly code?: string;\n readonly detail?: string;\n readonly raw?: unknown;\n\n constructor(message: string, options: VerixoErrorOptions) {\n super(message);\n this.name = \"VerixoError\";\n this.status = options.status;\n this.code = options.code;\n this.detail = options.detail;\n this.raw = options.raw;\n }\n}\n\nconst STATUS_FALLBACKS: Record<number, string> = {\n 401: \"Missing or invalid API key.\",\n 402: \"Insufficient wallet balance.\",\n 403: \"You don't have access to this resource.\",\n 404: \"Not found.\",\n 408: \"Request timed out.\",\n 422: \"The request did not meet a required condition (e.g. minScore).\",\n 429: \"Rate limit exceeded.\",\n};\n\nexport async function errorFromResponse(res: Response): Promise<VerixoError> {\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n body = undefined;\n }\n\n const obj = (body && typeof body === \"object\" ? body : {}) as Record<string, unknown>;\n const detail = (obj.detail ?? obj.error ?? obj.message) as string | undefined;\n const code = (obj.grpcCode ?? obj.code) as string | undefined;\n const message = detail ?? STATUS_FALLBACKS[res.status] ?? `Request failed with status ${res.status}`;\n\n return new VerixoError(message, { status: res.status, code, detail, raw: body });\n}\n","import { errorFromResponse } from \"./errors.js\";\nimport type { VerixoOptions } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.verifiedcore.com\";\n\nexport class HttpClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n if (!apiKey) {\n throw new Error(\"Verixo: an API key (or JWT) is required, e.g. new Verixo('vc_test_...')\");\n }\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, \"\");\n }\n\n async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n // The gateway classifies the credential by sniffing the raw Authorization header for a\n // vc_test_/vc_live_ prefix -- a \"Bearer \" prefix on an API key would make it misclassify\n // the request as a (malformed) JWT and reject it, so API keys go out unprefixed.\n const isApiKey = this.apiKey.startsWith(\"vc_test_\") || this.apiKey.startsWith(\"vc_live_\");\n const authorization = isApiKey ? this.apiKey : `Bearer ${this.apiKey}`;\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n Authorization: authorization,\n ...(init.body ? { \"Content-Type\": \"application/json\" } : {}),\n ...init.headers,\n },\n });\n\n if (!res.ok) {\n throw await errorFromResponse(res);\n }\n\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n\n get<T>(path: string): Promise<T> {\n return this.request<T>(path, { method: \"GET\" });\n }\n\n post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(path, { method: \"POST\", body: body ? JSON.stringify(body) : undefined });\n }\n\n /** ws:// or wss:// origin derived from baseUrl, for the OTP push subscription. */\n get wsOrigin(): string {\n return this.baseUrl.replace(/^http/, \"ws\");\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { DeliveryRate } from \"../types.js\";\n\nexport class Analytics {\n constructor(private readonly http: HttpClient) {}\n\n /** Public delivery-rate stats by country for a service. No auth required by the API itself. */\n rates(serviceSlug = \"whatsapp\"): Promise<{ rates: DeliveryRate[]; updatedAt: string }> {\n return this.http.get(`/api/v1/analytics/rates?serviceSlug=${encodeURIComponent(serviceSlug)}`);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { PurchaseNumberParams, PurchaseResult, SearchNumbersParams, SearchNumbersResult } from \"../types.js\";\n\nexport class Numbers {\n constructor(private readonly http: HttpClient) {}\n\n /** Browse available numbers ranked by Health Score (TM). No purchase is made. */\n search(params: SearchNumbersParams): Promise<SearchNumbersResult> {\n const q = new URLSearchParams({ serviceSlug: params.serviceSlug });\n if (params.countryCode) q.set(\"countryCode\", params.countryCode);\n if (params.minScore != null) q.set(\"minScore\", String(params.minScore));\n if (params.limit != null) q.set(\"limit\", String(params.limit));\n return this.http.get<SearchNumbersResult>(`/api/v1/numbers/search?${q}`);\n }\n\n /**\n * Buy a number for a service + country. The server picks the best available\n * candidate by Health Score automatically -- there's no numberId parameter,\n * since by the time you'd pass one back the number may already be gone.\n */\n purchase(params: PurchaseNumberParams): Promise<PurchaseResult> {\n return this.http.post<PurchaseResult>(\"/api/v1/numbers/purchase\", params);\n }\n}\n","import type { HttpClient } from \"../client.js\";\nimport type { SessionStatus } from \"../types.js\";\n\nexport class Sessions {\n constructor(private readonly http: HttpClient) {}\n\n /** Poll a session's current delivery status. */\n get(sessionToken: string): Promise<SessionStatus> {\n return this.http.get<SessionStatus>(`/api/v1/numbers/session/${encodeURIComponent(sessionToken)}`);\n }\n\n /**\n * Poll until the session reaches a terminal state (DELIVERED, REFUNDED, EXPIRED, FAILED)\n * or the timeout elapses. Prefer `vc.subscribe()` for real-time push -- this is a fallback\n * for environments where a persistent WebSocket isn't practical (e.g. serverless functions).\n */\n async waitForOtp(sessionToken: string, timeoutMs = 90_000, intervalMs = 2_000): Promise<SessionStatus> {\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const session = await this.get(sessionToken);\n if (session.status !== \"PENDING\") return session;\n if (Date.now() >= deadline) return session;\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n}\n","import { Client } from \"@stomp/stompjs\";\nimport type { HttpClient } from \"./client.js\";\nimport type { OtpPush } from \"./types.js\";\n\n/**\n * Subscribes to real-time OTP push for a session over the gateway's WebSocket\n * proxy (wss://.../ws -> delivery-service's STOMP broker, topic\n * /topic/otp/{sessionToken}). Requires a global WebSocket implementation --\n * present natively in browsers and Node 22+; on older Node, pass a `ws`\n * instance via globalThis.WebSocket before calling subscribe().\n *\n * Returns an unsubscribe function. The callback fires at most once per\n * session (a session only ever delivers one OTP).\n */\nexport function subscribe(http: HttpClient, sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\n \"Verixo.subscribe() requires a global WebSocket implementation. \" +\n \"This is built into browsers and Node 22+; on older Node, polyfill \" +\n \"globalThis.WebSocket (e.g. with the 'ws' package) before calling subscribe().\"\n );\n }\n\n const subscribedAt = Date.now();\n const client = new Client({\n brokerURL: `${http.wsOrigin}/ws`,\n reconnectDelay: 5_000,\n onConnect: () => {\n client.subscribe(`/topic/otp/${sessionToken}`, (message) => {\n try {\n const payload = JSON.parse(message.body) as Omit<OtpPush, \"latencyMs\">;\n onOtp({ ...payload, latencyMs: Date.now() - subscribedAt });\n } catch {\n // Ignore malformed frames rather than crashing the caller's process.\n }\n });\n },\n });\n\n client.activate();\n return () => {\n void client.deactivate();\n };\n}\n","import { HttpClient } from \"./client.js\";\nimport { Analytics } from \"./resources/analytics.js\";\nimport { Numbers } from \"./resources/numbers.js\";\nimport { Sessions } from \"./resources/sessions.js\";\nimport { subscribe } from \"./subscribe.js\";\nimport type { OtpPush, VerixoOptions } from \"./types.js\";\n\nexport { VerixoError } from \"./errors.js\";\nexport type {\n DeliveryRate,\n OtpPush,\n PurchaseNumberParams,\n PurchaseResult,\n SearchNumbersParams,\n SearchNumbersResult,\n SessionState,\n SessionStatus,\n VerixoOptions,\n VirtualNumber,\n} from \"./types.js\";\n\nexport default class Verixo {\n readonly numbers: Numbers;\n readonly sessions: Sessions;\n readonly analytics: Analytics;\n private readonly http: HttpClient;\n\n constructor(apiKey: string, options: VerixoOptions = {}) {\n this.http = new HttpClient(apiKey, options);\n this.numbers = new Numbers(this.http);\n this.sessions = new Sessions(this.http);\n this.analytics = new Analytics(this.http);\n }\n\n /**\n * Get pushed the OTP for a session in real time, instead of polling\n * `sessions.get()`. Returns an unsubscribe function.\n *\n * @example\n * const session = await vc.numbers.purchase({ serviceSlug: 'whatsapp', countryCode: 'NG' })\n * vc.subscribe(session.sessionToken, ({ otp, latencyMs }) => {\n * console.log(`OTP: ${otp} in ${latencyMs}ms`)\n * })\n */\n subscribe(sessionToken: string, onOtp: (push: OtpPush) => void): () => void {\n return subscribe(this.http, sessionToken, onOtp);\n }\n}\n"],"mappings":"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","names":[]}
|