@reachflow/sdk 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ReachFlow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @reachflow/sdk
2
+
3
+ Client officiel **Node.js / TypeScript** pour l’[API publique ReachFlow](https://docs.reachflow.me/developpeurs) (REST v1).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @reachflow/sdk
9
+ ```
10
+
11
+ **Prérequis :** Node.js ≥ 18 (utilise `fetch` natif).
12
+
13
+ ## Configuration
14
+
15
+ ```typescript
16
+ import { ReachFlow } from '@reachflow/sdk';
17
+
18
+ const client = new ReachFlow({
19
+ apiKey: process.env.REACHFLOW_API_KEY!, // rfl_live_… ou rfl_test_…
20
+ baseUrl: 'https://sandbox-api.reachflow.me', // optionnel
21
+ timeoutMs: 30_000, // optionnel
22
+ maxRetries: 2, // optionnel — 429 / 5xx
23
+ });
24
+ ```
25
+
26
+ ## Exemples
27
+
28
+ ### Envoyer un message
29
+
30
+ ```typescript
31
+ const { messageId } = await client.messages.send({
32
+ providerId: 'uuid-du-provider',
33
+ to: '22996123456',
34
+ message: 'Votre commande est confirmée.',
35
+ });
36
+
37
+ const status = await client.messages.waitForTerminal(messageId);
38
+ console.log(status.status); // sent | delivered | failed | …
39
+ ```
40
+
41
+ ### OTP
42
+
43
+ ```typescript
44
+ const { otpId } = await client.otp.send({
45
+ providerId: 'uuid-du-provider',
46
+ phoneNumber: '22996123456',
47
+ brandName: 'Mon App',
48
+ });
49
+
50
+ // Le code arrive sur WhatsApp — jamais dans la réponse JSON.
51
+ const result = await client.otp.verify({ otpId, code: '482910' });
52
+ console.log(result.valid);
53
+ ```
54
+
55
+ ### Providers
56
+
57
+ ```typescript
58
+ const { providers } = await client.providers.list();
59
+ const connected = await client.providers.findConnected();
60
+ ```
61
+
62
+ ## Gestion des erreurs
63
+
64
+ ```typescript
65
+ import { ReachFlow, ReachFlowError } from '@reachflow/sdk';
66
+
67
+ try {
68
+ await client.messages.send({ /* … */ });
69
+ } catch (err) {
70
+ if (err instanceof ReachFlowError) {
71
+ console.error(err.statusCode, err.code, err.message);
72
+ if (err.retryable) {
73
+ // retry manuel possible
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ | Code | Signification |
80
+ |------|---------------|
81
+ | `unauthorized` | Clé API invalide ou révoquée |
82
+ | `plan_required` | Plan ou add-on API manquant |
83
+ | `insufficient_scope` | Scope clé insuffisant |
84
+ | `rate_limit_exceeded` | Limite req/min dépassée |
85
+ | `validation_error` | Corps de requête invalide |
86
+ | `not_found` | Ressource introuvable |
87
+
88
+ ## Idempotence
89
+
90
+ Passez `idempotencyKey` sur `messages.send`, `sendMedia` ou `sendBulk` :
91
+
92
+ ```typescript
93
+ await client.messages.send({
94
+ providerId, to, message,
95
+ idempotencyKey: 'order-12345',
96
+ });
97
+ ```
98
+
99
+ ## Développement
100
+
101
+ ```bash
102
+ npm install
103
+ npm test
104
+ npm run build
105
+ ```
106
+
107
+ ## Licence
108
+
109
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,382 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
24
+ ReachFlow: () => ReachFlow,
25
+ ReachFlowError: () => ReachFlowError,
26
+ TERMINAL_MESSAGE_STATUSES: () => TERMINAL_MESSAGE_STATUSES
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/errors.ts
31
+ var ReachFlowError = class _ReachFlowError extends Error {
32
+ statusCode;
33
+ code;
34
+ retryable;
35
+ retryAfterMs;
36
+ body;
37
+ constructor(params) {
38
+ super(params.message, params.cause ? { cause: params.cause } : void 0);
39
+ this.name = "ReachFlowError";
40
+ this.statusCode = params.statusCode;
41
+ this.code = params.code;
42
+ this.retryable = params.retryable ?? false;
43
+ this.retryAfterMs = params.retryAfterMs;
44
+ this.body = params.body;
45
+ }
46
+ static fromResponse(status, body, fallbackMessage) {
47
+ const parsed = body ?? {};
48
+ const apiError = parsed.error;
49
+ const message = parsed.message ?? fallbackMessage ?? `ReachFlow API error (HTTP ${status})`;
50
+ const code = mapApiErrorToCode(status, apiError);
51
+ const retryable = status === 429 || status === 408 || status >= 500 && status < 600;
52
+ return new _ReachFlowError({
53
+ message,
54
+ statusCode: status,
55
+ code,
56
+ retryable,
57
+ body
58
+ });
59
+ }
60
+ static network(cause) {
61
+ return new _ReachFlowError({
62
+ message: "Network error while calling ReachFlow API",
63
+ statusCode: 0,
64
+ code: "network_error",
65
+ retryable: true,
66
+ cause
67
+ });
68
+ }
69
+ static timeout(timeoutMs) {
70
+ return new _ReachFlowError({
71
+ message: `Request timed out after ${timeoutMs}ms`,
72
+ statusCode: 408,
73
+ code: "timeout",
74
+ retryable: true
75
+ });
76
+ }
77
+ };
78
+ function mapApiErrorToCode(status, apiError) {
79
+ switch (apiError) {
80
+ case "unauthorized":
81
+ return "unauthorized";
82
+ case "plan_required":
83
+ return "plan_required";
84
+ case "insufficient_scope":
85
+ return "insufficient_scope";
86
+ case "rate_limit_exceeded":
87
+ return "rate_limit_exceeded";
88
+ case "too_many_auth_failures":
89
+ return "too_many_auth_failures";
90
+ default:
91
+ break;
92
+ }
93
+ if (status === 401) return "unauthorized";
94
+ if (status === 403) return "insufficient_scope";
95
+ if (status === 404) return "not_found";
96
+ if (status === 400 || status === 422) return "validation_error";
97
+ if (status === 429) return "rate_limit_exceeded";
98
+ return "api_error";
99
+ }
100
+ function parseRetryAfterMs(header) {
101
+ if (!header) return void 0;
102
+ const seconds = Number(header);
103
+ if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1e3);
104
+ const date = Date.parse(header);
105
+ if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
106
+ return void 0;
107
+ }
108
+
109
+ // src/types.ts
110
+ var TERMINAL_MESSAGE_STATUSES = /* @__PURE__ */ new Set([
111
+ "sent",
112
+ "delivered",
113
+ "failed",
114
+ "cancelled"
115
+ ]);
116
+ var DEFAULT_BASE_URL = "https://sandbox-api.reachflow.me";
117
+
118
+ // src/http.ts
119
+ function resolveConfig(options) {
120
+ const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
121
+ return {
122
+ apiKey: options.apiKey.trim(),
123
+ baseUrl,
124
+ apiPrefix: `${baseUrl}/api/v1`,
125
+ timeoutMs: options.timeoutMs ?? 3e4,
126
+ fetchImpl: options.fetch ?? globalThis.fetch,
127
+ maxRetries: options.maxRetries ?? 2
128
+ };
129
+ }
130
+ var HttpClient = class {
131
+ constructor(config) {
132
+ this.config = config;
133
+ }
134
+ config;
135
+ async request(options) {
136
+ let attempt = 0;
137
+ let lastError;
138
+ while (attempt <= this.config.maxRetries) {
139
+ try {
140
+ return await this.requestOnce(options);
141
+ } catch (err) {
142
+ if (!(err instanceof ReachFlowError)) throw err;
143
+ lastError = err;
144
+ if (!err.retryable || attempt >= this.config.maxRetries) throw err;
145
+ const delayMs = err.retryAfterMs ?? backoffMs(attempt);
146
+ await sleep(delayMs);
147
+ attempt += 1;
148
+ }
149
+ }
150
+ throw lastError ?? new ReachFlowError({
151
+ message: "Request failed",
152
+ statusCode: 0,
153
+ code: "api_error"
154
+ });
155
+ }
156
+ async requestOnce(options) {
157
+ const url = `${this.config.apiPrefix}${options.path}`;
158
+ const headers = {
159
+ Accept: "application/json",
160
+ "X-API-Key": this.config.apiKey
161
+ };
162
+ if (options.body !== void 0) {
163
+ headers["Content-Type"] = "application/json";
164
+ }
165
+ if (options.idempotencyKey) {
166
+ headers["Idempotency-Key"] = options.idempotencyKey;
167
+ }
168
+ const controller = new AbortController();
169
+ const timer = setTimeout(() => controller.abort(), this.config.timeoutMs);
170
+ try {
171
+ const response = await this.config.fetchImpl(url, {
172
+ method: options.method,
173
+ headers,
174
+ body: options.body !== void 0 ? JSON.stringify(options.body) : void 0,
175
+ signal: controller.signal
176
+ });
177
+ const text = await response.text();
178
+ let data = null;
179
+ if (text) {
180
+ try {
181
+ data = JSON.parse(text);
182
+ } catch {
183
+ data = { raw: text.slice(0, 500) };
184
+ }
185
+ }
186
+ if (!response.ok) {
187
+ const err = ReachFlowError.fromResponse(
188
+ response.status,
189
+ data
190
+ );
191
+ const retryAfterMs = parseRetryAfterMs(
192
+ response.headers.get("Retry-After")
193
+ );
194
+ if (retryAfterMs !== void 0) {
195
+ throw new ReachFlowError({
196
+ message: err.message,
197
+ statusCode: err.statusCode,
198
+ code: err.code,
199
+ retryable: err.retryable,
200
+ retryAfterMs,
201
+ body: err.body
202
+ });
203
+ }
204
+ throw err;
205
+ }
206
+ return data;
207
+ } catch (err) {
208
+ if (err instanceof ReachFlowError) throw err;
209
+ if (err instanceof Error && err.name === "AbortError") {
210
+ throw ReachFlowError.timeout(this.config.timeoutMs);
211
+ }
212
+ throw ReachFlowError.network(err);
213
+ } finally {
214
+ clearTimeout(timer);
215
+ }
216
+ }
217
+ };
218
+ function backoffMs(attempt) {
219
+ return Math.min(1e3 * 2 ** attempt, 1e4);
220
+ }
221
+ function sleep(ms) {
222
+ return new Promise((resolve) => setTimeout(resolve, ms));
223
+ }
224
+
225
+ // src/resources/messages.ts
226
+ var MessagesResource = class {
227
+ constructor(http) {
228
+ this.http = http;
229
+ }
230
+ http;
231
+ /** Envoie un message texte (réponse HTTP 202). */
232
+ async send(params) {
233
+ const { idempotencyKey, ...body } = params;
234
+ return this.http.request({
235
+ method: "POST",
236
+ path: "/messages/send",
237
+ body,
238
+ idempotencyKey
239
+ });
240
+ }
241
+ /** Envoie un média via URL HTTPS publique (réponse HTTP 202). */
242
+ async sendMedia(params) {
243
+ const { idempotencyKey, ...body } = params;
244
+ return this.http.request({
245
+ method: "POST",
246
+ path: "/messages/send-media",
247
+ body,
248
+ idempotencyKey
249
+ });
250
+ }
251
+ /** Envoie un lot de messages (même modèle, destinataires multiples). */
252
+ async sendBulk(params) {
253
+ const { idempotencyKey, ...body } = params;
254
+ return this.http.request({
255
+ method: "POST",
256
+ path: "/messages/send-bulk",
257
+ body,
258
+ idempotencyKey
259
+ });
260
+ }
261
+ /** Consulte le statut d'un message précédemment accepté. */
262
+ async getStatus(messageId) {
263
+ return this.http.request({
264
+ method: "GET",
265
+ path: `/messages/${messageId}`
266
+ });
267
+ }
268
+ /**
269
+ * Poll jusqu'à un statut terminal (`sent`, `delivered`, `failed`, `cancelled`).
270
+ * Lance `ReachFlowError` si timeout.
271
+ */
272
+ async waitForTerminal(messageId, options) {
273
+ const pollIntervalMs = options?.pollIntervalMs ?? 2e3;
274
+ const timeoutMs = options?.timeoutMs ?? 12e4;
275
+ const started = Date.now();
276
+ while (Date.now() - started < timeoutMs) {
277
+ const status = await this.getStatus(messageId);
278
+ if (TERMINAL_MESSAGE_STATUSES.has(status.status)) {
279
+ return status;
280
+ }
281
+ await sleep2(pollIntervalMs);
282
+ }
283
+ throw new ReachFlowError({
284
+ message: `Message ${messageId} did not reach a terminal status within ${timeoutMs}ms`,
285
+ statusCode: 408,
286
+ code: "timeout",
287
+ retryable: false
288
+ });
289
+ }
290
+ };
291
+ function sleep2(ms) {
292
+ return new Promise((resolve) => setTimeout(resolve, ms));
293
+ }
294
+
295
+ // src/resources/otp.ts
296
+ var OtpResource = class {
297
+ constructor(http) {
298
+ this.http = http;
299
+ }
300
+ http;
301
+ /**
302
+ * Génère et envoie un code OTP par WhatsApp.
303
+ * Le code n'est jamais retourné par l'API — uniquement sur WhatsApp.
304
+ */
305
+ async send(params) {
306
+ return this.http.request({
307
+ method: "POST",
308
+ path: "/otp/send",
309
+ body: params
310
+ });
311
+ }
312
+ /** Vérifie un code saisi par l'utilisateur final. */
313
+ async verify(params) {
314
+ return this.http.request({
315
+ method: "POST",
316
+ path: "/otp/verify",
317
+ body: params
318
+ });
319
+ }
320
+ };
321
+
322
+ // src/resources/providers.ts
323
+ var ProvidersResource = class {
324
+ constructor(http) {
325
+ this.http = http;
326
+ }
327
+ http;
328
+ /** Liste les numéros WhatsApp accessibles via l'API. */
329
+ async list() {
330
+ return this.http.request({
331
+ method: "GET",
332
+ path: "/providers"
333
+ });
334
+ }
335
+ /** Détail d'un provider avec statistiques journalières. */
336
+ async get(providerId) {
337
+ return this.http.request({
338
+ method: "GET",
339
+ path: `/providers/${providerId}`
340
+ });
341
+ }
342
+ /**
343
+ * Retourne le premier provider au statut `connected`, ou le premier de la liste.
344
+ * Utile pour les scripts de test / démarrage rapide.
345
+ */
346
+ async findConnected() {
347
+ const { providers } = await this.list();
348
+ if (providers.length === 0) return null;
349
+ return providers.find((p) => p.status.toLowerCase() === "connected") ?? providers[0] ?? null;
350
+ }
351
+ };
352
+
353
+ // src/client.ts
354
+ var ReachFlow = class {
355
+ messages;
356
+ providers;
357
+ otp;
358
+ http;
359
+ config;
360
+ constructor(options) {
361
+ if (!options.apiKey?.trim()) {
362
+ throw new Error("ReachFlow: apiKey is required");
363
+ }
364
+ this.config = resolveConfig(options);
365
+ this.http = new HttpClient(this.config);
366
+ this.messages = new MessagesResource(this.http);
367
+ this.providers = new ProvidersResource(this.http);
368
+ this.otp = new OtpResource(this.http);
369
+ }
370
+ /** URL de base configurée (sans `/api/v1`). */
371
+ get baseUrl() {
372
+ return this.config.baseUrl;
373
+ }
374
+ };
375
+ // Annotate the CommonJS export names for ESM import in node:
376
+ 0 && (module.exports = {
377
+ DEFAULT_BASE_URL,
378
+ ReachFlow,
379
+ ReachFlowError,
380
+ TERMINAL_MESSAGE_STATUSES
381
+ });
382
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/types.ts","../src/http.ts","../src/resources/messages.ts","../src/resources/otp.ts","../src/resources/providers.ts","../src/client.ts"],"sourcesContent":["export { ReachFlow } from './client.js';\nexport { ReachFlowError } from './errors.js';\nexport type { ReachFlowErrorCode } from './errors.js';\nexport type {\n BulkRecipient,\n FailureCode,\n MediaType,\n MessageStatus,\n MessageStatusResponse,\n OtpSendParams,\n OtpSendResponse,\n OtpVerifyParams,\n OtpVerifyResponse,\n OtpVerifyReason,\n ProviderDailyStats,\n ProviderDetail,\n ProviderListResponse,\n ProviderSummary,\n ReachFlowClientOptions,\n SendAcceptedResponse,\n SendBulkParams,\n SendBulkResponse,\n SendMediaParams,\n SendMessageParams,\n WaitForTerminalOptions,\n} from './types.js';\nexport {\n DEFAULT_BASE_URL,\n TERMINAL_MESSAGE_STATUSES,\n} from './types.js';\n","export type ReachFlowErrorCode =\n | 'unauthorized'\n | 'plan_required'\n | 'insufficient_scope'\n | 'rate_limit_exceeded'\n | 'too_many_auth_failures'\n | 'validation_error'\n | 'not_found'\n | 'api_error'\n | 'network_error'\n | 'timeout';\n\nexport interface ReachFlowErrorBody {\n statusCode?: number;\n error?: string;\n message?: string;\n}\n\nexport class ReachFlowError extends Error {\n readonly statusCode: number;\n readonly code: ReachFlowErrorCode;\n readonly retryable: boolean;\n readonly retryAfterMs?: number;\n readonly body?: unknown;\n\n constructor(params: {\n message: string;\n statusCode: number;\n code: ReachFlowErrorCode;\n retryable?: boolean;\n retryAfterMs?: number;\n body?: unknown;\n cause?: unknown;\n }) {\n super(params.message, params.cause ? { cause: params.cause } : undefined);\n this.name = 'ReachFlowError';\n this.statusCode = params.statusCode;\n this.code = params.code;\n this.retryable = params.retryable ?? false;\n this.retryAfterMs = params.retryAfterMs;\n this.body = params.body;\n }\n\n static fromResponse(\n status: number,\n body: unknown,\n fallbackMessage?: string,\n ): ReachFlowError {\n const parsed = (body ?? {}) as ReachFlowErrorBody;\n const apiError = parsed.error;\n const message =\n parsed.message ??\n fallbackMessage ??\n `ReachFlow API error (HTTP ${status})`;\n\n const code = mapApiErrorToCode(status, apiError);\n const retryable =\n status === 429 || status === 408 || (status >= 500 && status < 600);\n\n return new ReachFlowError({\n message,\n statusCode: status,\n code,\n retryable,\n body,\n });\n }\n\n static network(cause: unknown): ReachFlowError {\n return new ReachFlowError({\n message: 'Network error while calling ReachFlow API',\n statusCode: 0,\n code: 'network_error',\n retryable: true,\n cause,\n });\n }\n\n static timeout(timeoutMs: number): ReachFlowError {\n return new ReachFlowError({\n message: `Request timed out after ${timeoutMs}ms`,\n statusCode: 408,\n code: 'timeout',\n retryable: true,\n });\n }\n}\n\nfunction mapApiErrorToCode(\n status: number,\n apiError?: string,\n): ReachFlowErrorCode {\n switch (apiError) {\n case 'unauthorized':\n return 'unauthorized';\n case 'plan_required':\n return 'plan_required';\n case 'insufficient_scope':\n return 'insufficient_scope';\n case 'rate_limit_exceeded':\n return 'rate_limit_exceeded';\n case 'too_many_auth_failures':\n return 'too_many_auth_failures';\n default:\n break;\n }\n\n if (status === 401) return 'unauthorized';\n if (status === 403) return 'insufficient_scope';\n if (status === 404) return 'not_found';\n if (status === 400 || status === 422) return 'validation_error';\n if (status === 429) return 'rate_limit_exceeded';\n return 'api_error';\n}\n\nexport function parseRetryAfterMs(header: string | null): number | undefined {\n if (!header) return undefined;\n const seconds = Number(header);\n if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1000);\n const date = Date.parse(header);\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now());\n return undefined;\n}\n","/** Statut de cycle de vie d'un message API. */\nexport type MessageStatus =\n | 'queued'\n | 'processing'\n | 'sent'\n | 'delivered'\n | 'failed'\n | 'cancelled';\n\nexport type MediaType = 'image' | 'document' | 'audio' | 'video';\n\nexport type FailureCode =\n | 'warmup_daily_limit'\n | 'risk_circuit_open'\n | 'provider_disconnected'\n | 'provider_banned'\n | 'send_not_allowed'\n | 'instance_busy'\n | 'delivery_timeout'\n | 'delivery_failed'\n | 'send_error'\n | 'provider_not_found';\n\nexport type OtpVerifyReason =\n | 'invalidated'\n | 'already_used'\n | 'expired'\n | 'max_attempts_reached'\n | 'invalid_code'\n | 'not_found';\n\nexport interface ReachFlowClientOptions {\n /** Clé API `rfl_live_…` ou `rfl_test_…`. */\n apiKey: string;\n /**\n * URL de base sans `/api/v1` (défaut : sandbox ReachFlow).\n * @default \"https://sandbox-api.reachflow.me\"\n */\n baseUrl?: string;\n /** Timeout HTTP en millisecondes. @default 30000 */\n timeoutMs?: number;\n /** Implémentation fetch (tests, Node < 18). @default global fetch */\n fetch?: typeof fetch;\n /** Nombre max de retries sur 429 / 5xx retryables. @default 2 */\n maxRetries?: number;\n}\n\nexport interface SendMessageParams {\n providerId: string;\n to: string;\n message: string;\n variables?: Record<string, string>;\n scheduleAt?: string;\n saveContact?: boolean;\n idempotencyKey?: string;\n}\n\nexport interface SendMediaParams {\n providerId: string;\n to: string;\n mediaUrl: string;\n mediaType: MediaType;\n caption?: string;\n saveContact?: boolean;\n idempotencyKey?: string;\n}\n\nexport interface BulkRecipient {\n to: string;\n variables?: Record<string, string>;\n}\n\nexport interface SendBulkParams {\n providerId: string;\n messageTemplate: string;\n recipients: BulkRecipient[];\n scheduleAt?: string;\n saveContact?: boolean;\n idempotencyKey?: string;\n}\n\nexport interface SendAcceptedResponse {\n messageId: string;\n status: 'queued';\n queuedAt: string;\n}\n\nexport interface BulkRejection {\n to: string;\n reason: string;\n}\n\nexport interface SendBulkResponse {\n bulkId: string;\n accepted: number;\n rejected: number;\n rejections: BulkRejection[];\n messageIds: string[];\n}\n\nexport interface MessageStatusResponse {\n messageId: string;\n status: MessageStatus;\n to: string;\n providerId: string;\n queuedAt: string;\n sentAt: string | null;\n deliveredAt: string | null;\n failedAt: string | null;\n failureCode: FailureCode | null;\n failureReason: string | null;\n}\n\nexport interface ProviderSummary {\n id: string;\n name: string;\n phoneNumber: string | null;\n status: string;\n warmupDay: number;\n riskScore: number;\n}\n\nexport interface ProviderDailyStats {\n sent: number;\n delivered: number;\n failed: number;\n messagesLimit: number | null;\n newContactsLimit: number | null;\n}\n\nexport interface ProviderDetail extends ProviderSummary {\n dailyStats: ProviderDailyStats;\n}\n\nexport interface ProviderListResponse {\n providers: ProviderSummary[];\n}\n\nexport interface OtpSendParams {\n providerId: string;\n phoneNumber: string;\n codeLength?: number;\n expiresIn?: number;\n brandName?: string;\n template?: string;\n saveContact?: boolean;\n}\n\nexport interface OtpSendResponse {\n otpId: string;\n messageId: string;\n expiresAt: string;\n}\n\nexport interface OtpVerifyParams {\n otpId: string;\n code: string;\n}\n\nexport interface OtpVerifyResponse {\n valid: boolean;\n reason?: OtpVerifyReason;\n attemptsLeft?: number;\n}\n\nexport interface WaitForTerminalOptions {\n /** Intervalle entre polls en ms. @default 2000 */\n pollIntervalMs?: number;\n /** Timeout total en ms. @default 120000 */\n timeoutMs?: number;\n}\n\nexport const TERMINAL_MESSAGE_STATUSES: ReadonlySet<MessageStatus> = new Set([\n 'sent',\n 'delivered',\n 'failed',\n 'cancelled',\n]);\n\nexport const DEFAULT_BASE_URL = 'https://sandbox-api.reachflow.me';\n","import { ReachFlowError, parseRetryAfterMs } from './errors.js';\nimport type { ReachFlowClientOptions } from './types.js';\nimport { DEFAULT_BASE_URL } from './types.js';\n\nexport interface RequestOptions {\n method: 'GET' | 'POST';\n path: string;\n body?: unknown;\n idempotencyKey?: string;\n}\n\nexport interface ResolvedClientConfig {\n apiKey: string;\n baseUrl: string;\n apiPrefix: string;\n timeoutMs: number;\n fetchImpl: typeof fetch;\n maxRetries: number;\n}\n\nexport function resolveConfig(\n options: ReachFlowClientOptions,\n): ResolvedClientConfig {\n const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n return {\n apiKey: options.apiKey.trim(),\n baseUrl,\n apiPrefix: `${baseUrl}/api/v1`,\n timeoutMs: options.timeoutMs ?? 30_000,\n fetchImpl: options.fetch ?? globalThis.fetch,\n maxRetries: options.maxRetries ?? 2,\n };\n}\n\nexport class HttpClient {\n constructor(private readonly config: ResolvedClientConfig) {}\n\n async request<T>(options: RequestOptions): Promise<T> {\n let attempt = 0;\n let lastError: ReachFlowError | undefined;\n\n while (attempt <= this.config.maxRetries) {\n try {\n return await this.requestOnce<T>(options);\n } catch (err) {\n if (!(err instanceof ReachFlowError)) throw err;\n lastError = err;\n if (!err.retryable || attempt >= this.config.maxRetries) throw err;\n const delayMs = err.retryAfterMs ?? backoffMs(attempt);\n await sleep(delayMs);\n attempt += 1;\n }\n }\n\n throw lastError ?? new ReachFlowError({\n message: 'Request failed',\n statusCode: 0,\n code: 'api_error',\n });\n }\n\n private async requestOnce<T>(options: RequestOptions): Promise<T> {\n const url = `${this.config.apiPrefix}${options.path}`;\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'X-API-Key': this.config.apiKey,\n };\n\n if (options.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n if (options.idempotencyKey) {\n headers['Idempotency-Key'] = options.idempotencyKey;\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.config.timeoutMs);\n\n try {\n const response = await this.config.fetchImpl(url, {\n method: options.method,\n headers,\n body:\n options.body !== undefined\n ? JSON.stringify(options.body)\n : undefined,\n signal: controller.signal,\n });\n\n const text = await response.text();\n let data: unknown = null;\n if (text) {\n try {\n data = JSON.parse(text) as unknown;\n } catch {\n data = { raw: text.slice(0, 500) };\n }\n }\n\n if (!response.ok) {\n const err = ReachFlowError.fromResponse(\n response.status,\n data,\n );\n const retryAfterMs = parseRetryAfterMs(\n response.headers.get('Retry-After'),\n );\n if (retryAfterMs !== undefined) {\n throw new ReachFlowError({\n message: err.message,\n statusCode: err.statusCode,\n code: err.code,\n retryable: err.retryable,\n retryAfterMs,\n body: err.body,\n });\n }\n throw err;\n }\n\n return data as T;\n } catch (err) {\n if (err instanceof ReachFlowError) throw err;\n if (err instanceof Error && err.name === 'AbortError') {\n throw ReachFlowError.timeout(this.config.timeoutMs);\n }\n throw ReachFlowError.network(err);\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\nfunction backoffMs(attempt: number): number {\n return Math.min(1000 * 2 ** attempt, 10_000);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { HttpClient } from '../http.js';\nimport { ReachFlowError } from '../errors.js';\nimport type {\n MessageStatusResponse,\n SendAcceptedResponse,\n SendBulkParams,\n SendBulkResponse,\n SendMediaParams,\n SendMessageParams,\n WaitForTerminalOptions,\n} from '../types.js';\nimport { TERMINAL_MESSAGE_STATUSES } from '../types.js';\n\nexport class MessagesResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Envoie un message texte (réponse HTTP 202). */\n async send(params: SendMessageParams): Promise<SendAcceptedResponse> {\n const { idempotencyKey, ...body } = params;\n return this.http.request<SendAcceptedResponse>({\n method: 'POST',\n path: '/messages/send',\n body,\n idempotencyKey,\n });\n }\n\n /** Envoie un média via URL HTTPS publique (réponse HTTP 202). */\n async sendMedia(params: SendMediaParams): Promise<SendAcceptedResponse> {\n const { idempotencyKey, ...body } = params;\n return this.http.request<SendAcceptedResponse>({\n method: 'POST',\n path: '/messages/send-media',\n body,\n idempotencyKey,\n });\n }\n\n /** Envoie un lot de messages (même modèle, destinataires multiples). */\n async sendBulk(params: SendBulkParams): Promise<SendBulkResponse> {\n const { idempotencyKey, ...body } = params;\n return this.http.request<SendBulkResponse>({\n method: 'POST',\n path: '/messages/send-bulk',\n body,\n idempotencyKey,\n });\n }\n\n /** Consulte le statut d'un message précédemment accepté. */\n async getStatus(messageId: string): Promise<MessageStatusResponse> {\n return this.http.request<MessageStatusResponse>({\n method: 'GET',\n path: `/messages/${messageId}`,\n });\n }\n\n /**\n * Poll jusqu'à un statut terminal (`sent`, `delivered`, `failed`, `cancelled`).\n * Lance `ReachFlowError` si timeout.\n */\n async waitForTerminal(\n messageId: string,\n options?: WaitForTerminalOptions,\n ): Promise<MessageStatusResponse> {\n const pollIntervalMs = options?.pollIntervalMs ?? 2_000;\n const timeoutMs = options?.timeoutMs ?? 120_000;\n const started = Date.now();\n\n while (Date.now() - started < timeoutMs) {\n const status = await this.getStatus(messageId);\n if (TERMINAL_MESSAGE_STATUSES.has(status.status)) {\n return status;\n }\n await sleep(pollIntervalMs);\n }\n\n throw new ReachFlowError({\n message: `Message ${messageId} did not reach a terminal status within ${timeoutMs}ms`,\n statusCode: 408,\n code: 'timeout',\n retryable: false,\n });\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { HttpClient } from '../http.js';\nimport type {\n OtpSendParams,\n OtpSendResponse,\n OtpVerifyParams,\n OtpVerifyResponse,\n} from '../types.js';\n\nexport class OtpResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Génère et envoie un code OTP par WhatsApp.\n * Le code n'est jamais retourné par l'API — uniquement sur WhatsApp.\n */\n async send(params: OtpSendParams): Promise<OtpSendResponse> {\n return this.http.request<OtpSendResponse>({\n method: 'POST',\n path: '/otp/send',\n body: params,\n });\n }\n\n /** Vérifie un code saisi par l'utilisateur final. */\n async verify(params: OtpVerifyParams): Promise<OtpVerifyResponse> {\n return this.http.request<OtpVerifyResponse>({\n method: 'POST',\n path: '/otp/verify',\n body: params,\n });\n }\n}\n","import type { HttpClient } from '../http.js';\nimport type { ProviderDetail, ProviderListResponse } from '../types.js';\n\nexport class ProvidersResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Liste les numéros WhatsApp accessibles via l'API. */\n async list(): Promise<ProviderListResponse> {\n return this.http.request<ProviderListResponse>({\n method: 'GET',\n path: '/providers',\n });\n }\n\n /** Détail d'un provider avec statistiques journalières. */\n async get(providerId: string): Promise<ProviderDetail> {\n return this.http.request<ProviderDetail>({\n method: 'GET',\n path: `/providers/${providerId}`,\n });\n }\n\n /**\n * Retourne le premier provider au statut `connected`, ou le premier de la liste.\n * Utile pour les scripts de test / démarrage rapide.\n */\n async findConnected(): Promise<ProviderDetail | ProviderListResponse['providers'][number] | null> {\n const { providers } = await this.list();\n if (providers.length === 0) return null;\n return (\n providers.find((p) => p.status.toLowerCase() === 'connected') ??\n providers[0] ??\n null\n );\n }\n}\n","import { HttpClient, resolveConfig } from './http.js';\nimport { MessagesResource } from './resources/messages.js';\nimport { OtpResource } from './resources/otp.js';\nimport { ProvidersResource } from './resources/providers.js';\nimport type { ReachFlowClientOptions } from './types.js';\n\n/**\n * Client officiel pour l'API publique ReachFlow (REST v1).\n *\n * @example\n * ```ts\n * const client = new ReachFlow({ apiKey: process.env.REACHFLOW_API_KEY! });\n * const { providers } = await client.providers.list();\n * ```\n */\nexport class ReachFlow {\n readonly messages: MessagesResource;\n readonly providers: ProvidersResource;\n readonly otp: OtpResource;\n\n private readonly http: HttpClient;\n private readonly config: ReturnType<typeof resolveConfig>;\n\n constructor(options: ReachFlowClientOptions) {\n if (!options.apiKey?.trim()) {\n throw new Error('ReachFlow: apiKey is required');\n }\n\n this.config = resolveConfig(options);\n this.http = new HttpClient(this.config);\n this.messages = new MessagesResource(this.http);\n this.providers = new ProvidersResource(this.http);\n this.otp = new OtpResource(this.http);\n }\n\n /** URL de base configurée (sans `/api/v1`). */\n get baseUrl(): string {\n return this.config.baseUrl;\n }\n}\n"],"mappings":"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","names":["sleep"]}