@scell/sdk 1.0.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/dist/index.js ADDED
@@ -0,0 +1,1755 @@
1
+ 'use strict';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
11
+ var __esm = (fn, res) => function __init() {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+
19
+ // src/errors.ts
20
+ var errors_exports = {};
21
+ __export(errors_exports, {
22
+ ScellAuthenticationError: () => exports.ScellAuthenticationError,
23
+ ScellAuthorizationError: () => exports.ScellAuthorizationError,
24
+ ScellError: () => exports.ScellError,
25
+ ScellInsufficientBalanceError: () => exports.ScellInsufficientBalanceError,
26
+ ScellNetworkError: () => exports.ScellNetworkError,
27
+ ScellNotFoundError: () => exports.ScellNotFoundError,
28
+ ScellRateLimitError: () => exports.ScellRateLimitError,
29
+ ScellServerError: () => exports.ScellServerError,
30
+ ScellTimeoutError: () => exports.ScellTimeoutError,
31
+ ScellValidationError: () => exports.ScellValidationError,
32
+ parseApiError: () => parseApiError
33
+ });
34
+ function parseApiError(status, body, headers) {
35
+ const errorBody = body;
36
+ const message = errorBody?.message ?? "Unknown error";
37
+ const errors = errorBody?.errors ?? {};
38
+ const code = errorBody?.code;
39
+ switch (status) {
40
+ case 401:
41
+ throw new exports.ScellAuthenticationError(message, body);
42
+ case 402:
43
+ throw new exports.ScellInsufficientBalanceError(message, body);
44
+ case 403:
45
+ throw new exports.ScellAuthorizationError(message, body);
46
+ case 404:
47
+ throw new exports.ScellNotFoundError(message, body);
48
+ case 422:
49
+ throw new exports.ScellValidationError(message, errors, body);
50
+ case 429: {
51
+ const retryAfter = headers?.get("Retry-After");
52
+ throw new exports.ScellRateLimitError(
53
+ message,
54
+ retryAfter ? parseInt(retryAfter, 10) : void 0,
55
+ body
56
+ );
57
+ }
58
+ default:
59
+ if (status >= 500) {
60
+ throw new exports.ScellServerError(message, status, body);
61
+ }
62
+ throw new exports.ScellError(message, status, code, body);
63
+ }
64
+ }
65
+ exports.ScellError = void 0; exports.ScellAuthenticationError = void 0; exports.ScellAuthorizationError = void 0; exports.ScellValidationError = void 0; exports.ScellRateLimitError = void 0; exports.ScellNotFoundError = void 0; exports.ScellServerError = void 0; exports.ScellInsufficientBalanceError = void 0; exports.ScellNetworkError = void 0; exports.ScellTimeoutError = void 0;
66
+ var init_errors = __esm({
67
+ "src/errors.ts"() {
68
+ exports.ScellError = class extends Error {
69
+ /** HTTP status code */
70
+ status;
71
+ /** Error code from API */
72
+ code;
73
+ /** Original response body */
74
+ body;
75
+ constructor(message, status, code, body) {
76
+ super(message);
77
+ this.name = "ScellError";
78
+ this.status = status;
79
+ this.code = code;
80
+ this.body = body;
81
+ if (Error.captureStackTrace) {
82
+ Error.captureStackTrace(this, this.constructor);
83
+ }
84
+ }
85
+ };
86
+ exports.ScellAuthenticationError = class extends exports.ScellError {
87
+ constructor(message = "Authentication failed", body) {
88
+ super(message, 401, "AUTHENTICATION_ERROR", body);
89
+ this.name = "ScellAuthenticationError";
90
+ }
91
+ };
92
+ exports.ScellAuthorizationError = class extends exports.ScellError {
93
+ constructor(message = "Access denied", body) {
94
+ super(message, 403, "AUTHORIZATION_ERROR", body);
95
+ this.name = "ScellAuthorizationError";
96
+ }
97
+ };
98
+ exports.ScellValidationError = class extends exports.ScellError {
99
+ /** Field-level validation errors */
100
+ errors;
101
+ constructor(message, errors = {}, body) {
102
+ super(message, 422, "VALIDATION_ERROR", body);
103
+ this.name = "ScellValidationError";
104
+ this.errors = errors;
105
+ }
106
+ /**
107
+ * Get all error messages as a flat array
108
+ */
109
+ getAllMessages() {
110
+ return Object.values(this.errors).flat();
111
+ }
112
+ /**
113
+ * Get error messages for a specific field
114
+ */
115
+ getFieldErrors(field) {
116
+ return this.errors[field] ?? [];
117
+ }
118
+ /**
119
+ * Check if a specific field has errors
120
+ */
121
+ hasFieldError(field) {
122
+ const fieldErrors = this.errors[field];
123
+ return fieldErrors !== void 0 && fieldErrors.length > 0;
124
+ }
125
+ };
126
+ exports.ScellRateLimitError = class extends exports.ScellError {
127
+ /** Seconds to wait before retrying */
128
+ retryAfter;
129
+ constructor(message = "Rate limit exceeded", retryAfter, body) {
130
+ super(message, 429, "RATE_LIMIT_EXCEEDED", body);
131
+ this.name = "ScellRateLimitError";
132
+ this.retryAfter = retryAfter;
133
+ }
134
+ };
135
+ exports.ScellNotFoundError = class extends exports.ScellError {
136
+ constructor(message = "Resource not found", body) {
137
+ super(message, 404, "NOT_FOUND", body);
138
+ this.name = "ScellNotFoundError";
139
+ }
140
+ };
141
+ exports.ScellServerError = class extends exports.ScellError {
142
+ constructor(message = "Internal server error", status = 500, body) {
143
+ super(message, status, "SERVER_ERROR", body);
144
+ this.name = "ScellServerError";
145
+ }
146
+ };
147
+ exports.ScellInsufficientBalanceError = class extends exports.ScellError {
148
+ constructor(message = "Insufficient balance", body) {
149
+ super(message, 402, "INSUFFICIENT_BALANCE", body);
150
+ this.name = "ScellInsufficientBalanceError";
151
+ }
152
+ };
153
+ exports.ScellNetworkError = class extends exports.ScellError {
154
+ originalError;
155
+ constructor(message, originalError) {
156
+ super(message, 0, "NETWORK_ERROR");
157
+ this.name = "ScellNetworkError";
158
+ this.originalError = originalError;
159
+ }
160
+ };
161
+ exports.ScellTimeoutError = class extends exports.ScellError {
162
+ constructor(message = "Request timed out") {
163
+ super(message, 0, "TIMEOUT");
164
+ this.name = "ScellTimeoutError";
165
+ }
166
+ };
167
+ }
168
+ });
169
+
170
+ // src/client.ts
171
+ init_errors();
172
+
173
+ // src/utils/retry.ts
174
+ init_errors();
175
+ var DEFAULT_RETRY_OPTIONS = {
176
+ maxRetries: 3,
177
+ baseDelay: 1e3,
178
+ maxDelay: 3e4,
179
+ jitterFactor: 0.1
180
+ };
181
+ function isRetryableError(error) {
182
+ if (error instanceof exports.ScellRateLimitError) {
183
+ return true;
184
+ }
185
+ if (error instanceof exports.ScellServerError) {
186
+ return true;
187
+ }
188
+ if (error instanceof Error && error.name === "ScellNetworkError") {
189
+ return true;
190
+ }
191
+ return false;
192
+ }
193
+ function calculateDelay(attempt, baseDelay, maxDelay, jitterFactor, retryAfter) {
194
+ if (retryAfter !== void 0 && retryAfter > 0) {
195
+ return retryAfter * 1e3;
196
+ }
197
+ const exponentialDelay = baseDelay * Math.pow(2, attempt);
198
+ const cappedDelay = Math.min(exponentialDelay, maxDelay);
199
+ const jitter = cappedDelay * jitterFactor * (Math.random() * 2 - 1);
200
+ return Math.floor(cappedDelay + jitter);
201
+ }
202
+ function sleep(ms) {
203
+ return new Promise((resolve) => setTimeout(resolve, ms));
204
+ }
205
+ async function withRetry(fn, options = {}) {
206
+ const maxRetries = options.maxRetries ?? DEFAULT_RETRY_OPTIONS.maxRetries;
207
+ const baseDelay = options.baseDelay ?? DEFAULT_RETRY_OPTIONS.baseDelay;
208
+ const maxDelay = options.maxDelay ?? DEFAULT_RETRY_OPTIONS.maxDelay;
209
+ const jitterFactor = options.jitterFactor ?? DEFAULT_RETRY_OPTIONS.jitterFactor;
210
+ const isRetryable = options.isRetryable ?? isRetryableError;
211
+ let lastError;
212
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
213
+ try {
214
+ return await fn();
215
+ } catch (error) {
216
+ lastError = error;
217
+ if (attempt >= maxRetries || !isRetryable(error)) {
218
+ throw error;
219
+ }
220
+ const retryAfter = error instanceof exports.ScellRateLimitError ? error.retryAfter : void 0;
221
+ const delay = calculateDelay(
222
+ attempt,
223
+ baseDelay,
224
+ maxDelay,
225
+ jitterFactor,
226
+ retryAfter
227
+ );
228
+ await sleep(delay);
229
+ }
230
+ }
231
+ throw lastError;
232
+ }
233
+ function createRetryWrapper(defaultOptions = {}) {
234
+ return (fn, options = {}) => withRetry(fn, { ...defaultOptions, ...options });
235
+ }
236
+
237
+ // src/client.ts
238
+ var HttpClient = class {
239
+ baseUrl;
240
+ timeout;
241
+ retryOptions;
242
+ enableRetry;
243
+ fetchFn;
244
+ authMode;
245
+ authToken;
246
+ constructor(authMode, authToken, config = {}) {
247
+ this.authMode = authMode;
248
+ this.authToken = authToken;
249
+ this.baseUrl = config.baseUrl ?? "https://api.scell.io/api/v1";
250
+ this.timeout = config.timeout ?? 3e4;
251
+ this.retryOptions = config.retry ?? {};
252
+ this.enableRetry = config.enableRetry ?? true;
253
+ this.fetchFn = config.fetch ?? fetch;
254
+ }
255
+ /**
256
+ * Build URL with query parameters
257
+ */
258
+ buildUrl(path, query) {
259
+ const url = new URL(path, this.baseUrl);
260
+ if (query) {
261
+ for (const [key, value] of Object.entries(query)) {
262
+ if (value !== void 0) {
263
+ url.searchParams.set(key, String(value));
264
+ }
265
+ }
266
+ }
267
+ return url.toString();
268
+ }
269
+ /**
270
+ * Build headers for request
271
+ */
272
+ buildHeaders(additionalHeaders) {
273
+ const headers = {
274
+ "Content-Type": "application/json",
275
+ Accept: "application/json",
276
+ ...additionalHeaders
277
+ };
278
+ if (this.authMode === "bearer") {
279
+ headers["Authorization"] = `Bearer ${this.authToken}`;
280
+ } else {
281
+ headers["X-API-Key"] = this.authToken;
282
+ }
283
+ return headers;
284
+ }
285
+ /**
286
+ * Execute HTTP request
287
+ */
288
+ async executeRequest(config) {
289
+ const { method, path, body, query, headers, timeout, signal } = config;
290
+ const url = this.buildUrl(path, query);
291
+ const requestHeaders = this.buildHeaders(headers);
292
+ const requestTimeout = timeout ?? this.timeout;
293
+ const controller = new AbortController();
294
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
295
+ const combinedSignal = signal ? new AbortController().signal : controller.signal;
296
+ if (signal) {
297
+ signal.addEventListener("abort", () => controller.abort());
298
+ }
299
+ try {
300
+ const fetchOptions = {
301
+ method,
302
+ headers: requestHeaders,
303
+ signal: combinedSignal
304
+ };
305
+ if (body !== void 0) {
306
+ fetchOptions.body = JSON.stringify(body);
307
+ }
308
+ const response = await this.fetchFn(url, fetchOptions);
309
+ clearTimeout(timeoutId);
310
+ const contentType = response.headers.get("Content-Type") ?? "";
311
+ let responseBody;
312
+ if (contentType.includes("application/json")) {
313
+ responseBody = await response.json();
314
+ } else {
315
+ responseBody = await response.text();
316
+ }
317
+ if (!response.ok) {
318
+ parseApiError(response.status, responseBody, response.headers);
319
+ }
320
+ return responseBody;
321
+ } catch (error) {
322
+ clearTimeout(timeoutId);
323
+ if (error instanceof Error) {
324
+ if (error.name === "AbortError") {
325
+ throw new exports.ScellTimeoutError(
326
+ `Request timed out after ${requestTimeout}ms`
327
+ );
328
+ }
329
+ if (error.name === "TypeError" && error.message.includes("fetch")) {
330
+ throw new exports.ScellNetworkError("Network request failed", error);
331
+ }
332
+ }
333
+ throw error;
334
+ }
335
+ }
336
+ /**
337
+ * Execute request with optional retry
338
+ */
339
+ async request(config) {
340
+ const shouldRetry = this.enableRetry && !config.skipRetry;
341
+ if (shouldRetry) {
342
+ return withRetry(
343
+ () => this.executeRequest(config),
344
+ this.retryOptions
345
+ );
346
+ }
347
+ return this.executeRequest(config);
348
+ }
349
+ /**
350
+ * GET request
351
+ */
352
+ async get(path, query, options) {
353
+ const config = {
354
+ method: "GET",
355
+ path,
356
+ ...options
357
+ };
358
+ if (query !== void 0) {
359
+ config.query = query;
360
+ }
361
+ return this.request(config);
362
+ }
363
+ /**
364
+ * POST request
365
+ */
366
+ async post(path, body, options) {
367
+ return this.request({
368
+ method: "POST",
369
+ path,
370
+ body,
371
+ ...options
372
+ });
373
+ }
374
+ /**
375
+ * PUT request
376
+ */
377
+ async put(path, body, options) {
378
+ return this.request({
379
+ method: "PUT",
380
+ path,
381
+ body,
382
+ ...options
383
+ });
384
+ }
385
+ /**
386
+ * PATCH request
387
+ */
388
+ async patch(path, body, options) {
389
+ return this.request({
390
+ method: "PATCH",
391
+ path,
392
+ body,
393
+ ...options
394
+ });
395
+ }
396
+ /**
397
+ * DELETE request
398
+ */
399
+ async delete(path, options) {
400
+ return this.request({
401
+ method: "DELETE",
402
+ path,
403
+ ...options
404
+ });
405
+ }
406
+ };
407
+
408
+ // src/resources/api-keys.ts
409
+ var ApiKeysResource = class {
410
+ constructor(http) {
411
+ this.http = http;
412
+ }
413
+ /**
414
+ * List all API keys
415
+ *
416
+ * @param requestOptions - Request options
417
+ * @returns List of API keys (without secrets)
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * const { data: keys } = await client.apiKeys.list();
422
+ * keys.forEach(key => {
423
+ * console.log(`${key.name}: ${key.key_prefix}...`);
424
+ * });
425
+ * ```
426
+ */
427
+ async list(requestOptions) {
428
+ return this.http.get(
429
+ "/api-keys",
430
+ void 0,
431
+ requestOptions
432
+ );
433
+ }
434
+ /**
435
+ * Get a specific API key
436
+ *
437
+ * @param id - API Key UUID
438
+ * @param requestOptions - Request options
439
+ * @returns API key details (without secret)
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * const { data: key } = await client.apiKeys.get('key-uuid');
444
+ * console.log(`Last used: ${key.last_used_at}`);
445
+ * ```
446
+ */
447
+ async get(id, requestOptions) {
448
+ return this.http.get(
449
+ `/api-keys/${id}`,
450
+ void 0,
451
+ requestOptions
452
+ );
453
+ }
454
+ /**
455
+ * Create a new API key
456
+ *
457
+ * Important: The full key is only returned once during creation.
458
+ * Store it securely - you won't be able to retrieve it again.
459
+ *
460
+ * @param input - API key configuration
461
+ * @param requestOptions - Request options
462
+ * @returns Created API key with full key value
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * const { data: apiKey } = await client.apiKeys.create({
467
+ * name: 'Production Integration',
468
+ * company_id: 'company-uuid',
469
+ * environment: 'production',
470
+ * permissions: ['invoices:write', 'signatures:write']
471
+ * });
472
+ *
473
+ * // IMPORTANT: Store this key securely!
474
+ * // You won't be able to see it again.
475
+ * console.log('Save this key:', apiKey.key);
476
+ * ```
477
+ */
478
+ async create(input, requestOptions) {
479
+ return this.http.post(
480
+ "/api-keys",
481
+ input,
482
+ requestOptions
483
+ );
484
+ }
485
+ /**
486
+ * Delete an API key
487
+ *
488
+ * Warning: This will immediately revoke the key and all
489
+ * requests using it will fail.
490
+ *
491
+ * @param id - API Key UUID
492
+ * @param requestOptions - Request options
493
+ * @returns Deletion confirmation
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * await client.apiKeys.delete('key-uuid');
498
+ * console.log('API key revoked');
499
+ * ```
500
+ */
501
+ async delete(id, requestOptions) {
502
+ return this.http.delete(`/api-keys/${id}`, requestOptions);
503
+ }
504
+ };
505
+
506
+ // src/resources/auth.ts
507
+ var AuthResource = class {
508
+ constructor(http) {
509
+ this.http = http;
510
+ }
511
+ /**
512
+ * Get current authenticated user
513
+ *
514
+ * @param requestOptions - Request options
515
+ * @returns Current user details
516
+ *
517
+ * @example
518
+ * ```typescript
519
+ * const { data: user } = await client.auth.me();
520
+ * console.log(`Logged in as: ${user.name} (${user.email})`);
521
+ * ```
522
+ */
523
+ async me(requestOptions) {
524
+ return this.http.get(
525
+ "/auth/me",
526
+ void 0,
527
+ requestOptions
528
+ );
529
+ }
530
+ /**
531
+ * Logout (revoke current token)
532
+ *
533
+ * @param requestOptions - Request options
534
+ * @returns Logout confirmation
535
+ *
536
+ * @example
537
+ * ```typescript
538
+ * await client.auth.logout();
539
+ * // Token is now invalid
540
+ * ```
541
+ */
542
+ async logout(requestOptions) {
543
+ return this.http.post(
544
+ "/auth/logout",
545
+ void 0,
546
+ requestOptions
547
+ );
548
+ }
549
+ };
550
+ var ScellAuth = {
551
+ /**
552
+ * Default base URL for auth requests
553
+ */
554
+ baseUrl: "https://api.scell.io/api/v1",
555
+ /**
556
+ * Register a new user
557
+ *
558
+ * @param input - Registration data
559
+ * @param baseUrl - Optional base URL override
560
+ * @returns Auth response with token
561
+ *
562
+ * @example
563
+ * ```typescript
564
+ * const auth = await ScellAuth.register({
565
+ * name: 'Jane Doe',
566
+ * email: 'jane@example.com',
567
+ * password: 'MySecurePassword123!',
568
+ * password_confirmation: 'MySecurePassword123!'
569
+ * });
570
+ *
571
+ * console.log('Welcome,', auth.user.name);
572
+ * const client = new ScellClient(auth.token);
573
+ * ```
574
+ */
575
+ async register(input, baseUrl) {
576
+ const url = `${baseUrl ?? this.baseUrl}/auth/register`;
577
+ const response = await fetch(url, {
578
+ method: "POST",
579
+ headers: {
580
+ "Content-Type": "application/json",
581
+ Accept: "application/json"
582
+ },
583
+ body: JSON.stringify(input)
584
+ });
585
+ const body = await response.json();
586
+ if (!response.ok) {
587
+ const { parseApiError: parseApiError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
588
+ parseApiError2(response.status, body, response.headers);
589
+ }
590
+ return body;
591
+ },
592
+ /**
593
+ * Login an existing user
594
+ *
595
+ * @param credentials - Login credentials
596
+ * @param baseUrl - Optional base URL override
597
+ * @returns Auth response with token
598
+ *
599
+ * @example
600
+ * ```typescript
601
+ * const auth = await ScellAuth.login({
602
+ * email: 'user@example.com',
603
+ * password: 'password'
604
+ * });
605
+ *
606
+ * // Store the token securely
607
+ * localStorage.setItem('scell_token', auth.token);
608
+ *
609
+ * // Create client
610
+ * const client = new ScellClient(auth.token);
611
+ * ```
612
+ */
613
+ async login(credentials, baseUrl) {
614
+ const url = `${baseUrl ?? this.baseUrl}/auth/login`;
615
+ const response = await fetch(url, {
616
+ method: "POST",
617
+ headers: {
618
+ "Content-Type": "application/json",
619
+ Accept: "application/json"
620
+ },
621
+ body: JSON.stringify(credentials)
622
+ });
623
+ const body = await response.json();
624
+ if (!response.ok) {
625
+ const { parseApiError: parseApiError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
626
+ parseApiError2(response.status, body, response.headers);
627
+ }
628
+ return body;
629
+ },
630
+ /**
631
+ * Request password reset email
632
+ *
633
+ * @param input - Email address
634
+ * @param baseUrl - Optional base URL override
635
+ * @returns Confirmation message
636
+ *
637
+ * @example
638
+ * ```typescript
639
+ * await ScellAuth.forgotPassword({
640
+ * email: 'user@example.com'
641
+ * });
642
+ * console.log('Check your email for reset link');
643
+ * ```
644
+ */
645
+ async forgotPassword(input, baseUrl) {
646
+ const url = `${baseUrl ?? this.baseUrl}/auth/forgot-password`;
647
+ const response = await fetch(url, {
648
+ method: "POST",
649
+ headers: {
650
+ "Content-Type": "application/json",
651
+ Accept: "application/json"
652
+ },
653
+ body: JSON.stringify(input)
654
+ });
655
+ const body = await response.json();
656
+ if (!response.ok) {
657
+ const { parseApiError: parseApiError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
658
+ parseApiError2(response.status, body, response.headers);
659
+ }
660
+ return body;
661
+ },
662
+ /**
663
+ * Reset password with token from email
664
+ *
665
+ * @param input - Reset password data
666
+ * @param baseUrl - Optional base URL override
667
+ * @returns Confirmation message
668
+ *
669
+ * @example
670
+ * ```typescript
671
+ * await ScellAuth.resetPassword({
672
+ * email: 'user@example.com',
673
+ * token: 'reset-token-from-email',
674
+ * password: 'NewSecurePassword123!',
675
+ * password_confirmation: 'NewSecurePassword123!'
676
+ * });
677
+ * ```
678
+ */
679
+ async resetPassword(input, baseUrl) {
680
+ const url = `${baseUrl ?? this.baseUrl}/auth/reset-password`;
681
+ const response = await fetch(url, {
682
+ method: "POST",
683
+ headers: {
684
+ "Content-Type": "application/json",
685
+ Accept: "application/json"
686
+ },
687
+ body: JSON.stringify(input)
688
+ });
689
+ const body = await response.json();
690
+ if (!response.ok) {
691
+ const { parseApiError: parseApiError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
692
+ parseApiError2(response.status, body, response.headers);
693
+ }
694
+ return body;
695
+ }
696
+ };
697
+
698
+ // src/resources/balance.ts
699
+ var BalanceResource = class {
700
+ constructor(http) {
701
+ this.http = http;
702
+ }
703
+ /**
704
+ * Get current balance and settings
705
+ *
706
+ * @param requestOptions - Request options
707
+ * @returns Current balance details
708
+ *
709
+ * @example
710
+ * ```typescript
711
+ * const { data: balance } = await client.balance.get();
712
+ * console.log(`Balance: ${balance.amount} ${balance.currency}`);
713
+ *
714
+ * if (balance.amount < balance.low_balance_alert_threshold) {
715
+ * console.log('Warning: Low balance!');
716
+ * }
717
+ * ```
718
+ */
719
+ async get(requestOptions) {
720
+ return this.http.get(
721
+ "/balance",
722
+ void 0,
723
+ requestOptions
724
+ );
725
+ }
726
+ /**
727
+ * Reload balance
728
+ *
729
+ * Note: This is a simulation endpoint. In production, use Stripe integration.
730
+ *
731
+ * @param input - Reload amount (10-10000 EUR)
732
+ * @param requestOptions - Request options
733
+ * @returns Reload transaction details
734
+ *
735
+ * @example
736
+ * ```typescript
737
+ * const { transaction } = await client.balance.reload({ amount: 100 });
738
+ * console.log(`New balance: ${transaction.balance_after}`);
739
+ * ```
740
+ */
741
+ async reload(input, requestOptions) {
742
+ return this.http.post(
743
+ "/balance/reload",
744
+ input,
745
+ requestOptions
746
+ );
747
+ }
748
+ /**
749
+ * Update balance settings
750
+ *
751
+ * Configure auto-reload and alert thresholds.
752
+ *
753
+ * @param input - Settings to update
754
+ * @param requestOptions - Request options
755
+ * @returns Updated settings
756
+ *
757
+ * @example
758
+ * ```typescript
759
+ * await client.balance.updateSettings({
760
+ * auto_reload_enabled: true,
761
+ * auto_reload_threshold: 50,
762
+ * auto_reload_amount: 200,
763
+ * low_balance_alert_threshold: 100,
764
+ * critical_balance_alert_threshold: 25
765
+ * });
766
+ * ```
767
+ */
768
+ async updateSettings(input, requestOptions) {
769
+ return this.http.put(
770
+ "/balance/settings",
771
+ input,
772
+ requestOptions
773
+ );
774
+ }
775
+ /**
776
+ * List balance transactions
777
+ *
778
+ * @param options - Filter and pagination options
779
+ * @param requestOptions - Request options
780
+ * @returns Paginated list of transactions
781
+ *
782
+ * @example
783
+ * ```typescript
784
+ * // List all invoice debits
785
+ * const { data, meta } = await client.balance.transactions({
786
+ * type: 'debit',
787
+ * service: 'invoice',
788
+ * from: '2024-01-01',
789
+ * to: '2024-01-31'
790
+ * });
791
+ *
792
+ * data.forEach(tx => {
793
+ * console.log(`${tx.description}: -${tx.amount} EUR`);
794
+ * });
795
+ * ```
796
+ */
797
+ async transactions(options = {}, requestOptions) {
798
+ return this.http.get(
799
+ "/balance/transactions",
800
+ options,
801
+ requestOptions
802
+ );
803
+ }
804
+ };
805
+
806
+ // src/resources/companies.ts
807
+ var CompaniesResource = class {
808
+ constructor(http) {
809
+ this.http = http;
810
+ }
811
+ /**
812
+ * List all companies for the authenticated user
813
+ *
814
+ * @param requestOptions - Request options
815
+ * @returns List of companies
816
+ *
817
+ * @example
818
+ * ```typescript
819
+ * const { data: companies } = await client.companies.list();
820
+ * companies.forEach(c => console.log(c.name, c.status));
821
+ * ```
822
+ */
823
+ async list(requestOptions) {
824
+ return this.http.get(
825
+ "/companies",
826
+ void 0,
827
+ requestOptions
828
+ );
829
+ }
830
+ /**
831
+ * Get a specific company by ID
832
+ *
833
+ * @param id - Company UUID
834
+ * @param requestOptions - Request options
835
+ * @returns Company details
836
+ *
837
+ * @example
838
+ * ```typescript
839
+ * const { data: company } = await client.companies.get('uuid');
840
+ * console.log(company.name, company.siret);
841
+ * ```
842
+ */
843
+ async get(id, requestOptions) {
844
+ return this.http.get(
845
+ `/companies/${id}`,
846
+ void 0,
847
+ requestOptions
848
+ );
849
+ }
850
+ /**
851
+ * Create a new company
852
+ *
853
+ * @param input - Company creation data
854
+ * @param requestOptions - Request options
855
+ * @returns Created company
856
+ *
857
+ * @example
858
+ * ```typescript
859
+ * const { data: company } = await client.companies.create({
860
+ * name: 'Acme Corp',
861
+ * siret: '12345678901234',
862
+ * vat_number: 'FR12345678901',
863
+ * legal_form: 'SAS',
864
+ * address_line1: '123 Business Street',
865
+ * postal_code: '75001',
866
+ * city: 'Paris',
867
+ * country: 'FR',
868
+ * email: 'contact@acme.com',
869
+ * phone: '+33 1 23 45 67 89'
870
+ * });
871
+ * ```
872
+ */
873
+ async create(input, requestOptions) {
874
+ return this.http.post(
875
+ "/companies",
876
+ input,
877
+ requestOptions
878
+ );
879
+ }
880
+ /**
881
+ * Update a company
882
+ *
883
+ * @param id - Company UUID
884
+ * @param input - Fields to update
885
+ * @param requestOptions - Request options
886
+ * @returns Updated company
887
+ *
888
+ * @example
889
+ * ```typescript
890
+ * const { data: company } = await client.companies.update('uuid', {
891
+ * email: 'new-email@acme.com',
892
+ * phone: '+33 1 98 76 54 32'
893
+ * });
894
+ * ```
895
+ */
896
+ async update(id, input, requestOptions) {
897
+ return this.http.put(
898
+ `/companies/${id}`,
899
+ input,
900
+ requestOptions
901
+ );
902
+ }
903
+ /**
904
+ * Delete a company
905
+ *
906
+ * @param id - Company UUID
907
+ * @param requestOptions - Request options
908
+ * @returns Deletion confirmation
909
+ *
910
+ * @example
911
+ * ```typescript
912
+ * await client.companies.delete('company-uuid');
913
+ * ```
914
+ */
915
+ async delete(id, requestOptions) {
916
+ return this.http.delete(
917
+ `/companies/${id}`,
918
+ requestOptions
919
+ );
920
+ }
921
+ /**
922
+ * Initiate KYC verification for a company
923
+ *
924
+ * @param id - Company UUID
925
+ * @param requestOptions - Request options
926
+ * @returns KYC reference and redirect URL
927
+ *
928
+ * @example
929
+ * ```typescript
930
+ * const { kyc_reference, redirect_url } = await client.companies.initiateKyc(
931
+ * 'company-uuid'
932
+ * );
933
+ * // Redirect user to redirect_url for KYC verification
934
+ * ```
935
+ */
936
+ async initiateKyc(id, requestOptions) {
937
+ return this.http.post(
938
+ `/companies/${id}/kyc`,
939
+ void 0,
940
+ requestOptions
941
+ );
942
+ }
943
+ /**
944
+ * Get KYC verification status
945
+ *
946
+ * @param id - Company UUID
947
+ * @param requestOptions - Request options
948
+ * @returns Current KYC status
949
+ *
950
+ * @example
951
+ * ```typescript
952
+ * const status = await client.companies.kycStatus('company-uuid');
953
+ * if (status.status === 'active') {
954
+ * console.log('KYC completed at:', status.kyc_completed_at);
955
+ * }
956
+ * ```
957
+ */
958
+ async kycStatus(id, requestOptions) {
959
+ return this.http.get(
960
+ `/companies/${id}/kyc/status`,
961
+ void 0,
962
+ requestOptions
963
+ );
964
+ }
965
+ };
966
+
967
+ // src/resources/invoices.ts
968
+ var InvoicesResource = class {
969
+ constructor(http) {
970
+ this.http = http;
971
+ }
972
+ /**
973
+ * List invoices with optional filtering
974
+ *
975
+ * @param options - Filter and pagination options
976
+ * @param requestOptions - Request options
977
+ * @returns Paginated list of invoices
978
+ *
979
+ * @example
980
+ * ```typescript
981
+ * // List all outgoing invoices
982
+ * const { data, meta } = await client.invoices.list({
983
+ * direction: 'outgoing',
984
+ * per_page: 50
985
+ * });
986
+ * console.log(`Found ${meta.total} invoices`);
987
+ * ```
988
+ */
989
+ async list(options = {}, requestOptions) {
990
+ return this.http.get(
991
+ "/invoices",
992
+ options,
993
+ requestOptions
994
+ );
995
+ }
996
+ /**
997
+ * Get a specific invoice by ID
998
+ *
999
+ * @param id - Invoice UUID
1000
+ * @param requestOptions - Request options
1001
+ * @returns Invoice details
1002
+ *
1003
+ * @example
1004
+ * ```typescript
1005
+ * const { data: invoice } = await client.invoices.get('uuid-here');
1006
+ * console.log('Invoice number:', invoice.invoice_number);
1007
+ * ```
1008
+ */
1009
+ async get(id, requestOptions) {
1010
+ return this.http.get(
1011
+ `/invoices/${id}`,
1012
+ void 0,
1013
+ requestOptions
1014
+ );
1015
+ }
1016
+ /**
1017
+ * Create a new invoice
1018
+ *
1019
+ * Note: This endpoint requires API key authentication.
1020
+ * Creating an invoice in production mode will debit your balance.
1021
+ *
1022
+ * @param input - Invoice creation data
1023
+ * @param requestOptions - Request options
1024
+ * @returns Created invoice
1025
+ *
1026
+ * @example
1027
+ * ```typescript
1028
+ * const { data: invoice } = await client.invoices.create({
1029
+ * invoice_number: 'FACT-2024-001',
1030
+ * direction: 'outgoing',
1031
+ * output_format: 'facturx',
1032
+ * issue_date: '2024-01-15',
1033
+ * total_ht: 100.00,
1034
+ * total_tax: 20.00,
1035
+ * total_ttc: 120.00,
1036
+ * seller_siret: '12345678901234',
1037
+ * seller_name: 'My Company',
1038
+ * seller_address: {
1039
+ * line1: '1 Rue Example',
1040
+ * postal_code: '75001',
1041
+ * city: 'Paris',
1042
+ * country: 'FR'
1043
+ * },
1044
+ * buyer_siret: '98765432109876',
1045
+ * buyer_name: 'Client Company',
1046
+ * buyer_address: {
1047
+ * line1: '2 Avenue Test',
1048
+ * postal_code: '75002',
1049
+ * city: 'Paris',
1050
+ * country: 'FR'
1051
+ * },
1052
+ * lines: [{
1053
+ * description: 'Service prestation',
1054
+ * quantity: 1,
1055
+ * unit_price: 100.00,
1056
+ * tax_rate: 20.00,
1057
+ * total_ht: 100.00,
1058
+ * total_tax: 20.00,
1059
+ * total_ttc: 120.00
1060
+ * }]
1061
+ * });
1062
+ * ```
1063
+ */
1064
+ async create(input, requestOptions) {
1065
+ return this.http.post(
1066
+ "/invoices",
1067
+ input,
1068
+ requestOptions
1069
+ );
1070
+ }
1071
+ /**
1072
+ * Download invoice file
1073
+ *
1074
+ * @param id - Invoice UUID
1075
+ * @param type - File type to download
1076
+ * @param requestOptions - Request options
1077
+ * @returns Temporary download URL
1078
+ *
1079
+ * @example
1080
+ * ```typescript
1081
+ * // Download PDF version
1082
+ * const { url, expires_at } = await client.invoices.download(
1083
+ * 'invoice-uuid',
1084
+ * 'pdf'
1085
+ * );
1086
+ * console.log('Download before:', expires_at);
1087
+ * ```
1088
+ */
1089
+ async download(id, type, requestOptions) {
1090
+ return this.http.get(
1091
+ `/invoices/${id}/download/${type}`,
1092
+ void 0,
1093
+ requestOptions
1094
+ );
1095
+ }
1096
+ /**
1097
+ * Get invoice audit trail (Piste d'Audit Fiable)
1098
+ *
1099
+ * @param id - Invoice UUID
1100
+ * @param requestOptions - Request options
1101
+ * @returns Audit trail entries with integrity validation
1102
+ *
1103
+ * @example
1104
+ * ```typescript
1105
+ * const { data: entries, integrity_valid } = await client.invoices.auditTrail(
1106
+ * 'invoice-uuid'
1107
+ * );
1108
+ *
1109
+ * if (integrity_valid) {
1110
+ * console.log('Audit trail is valid');
1111
+ * entries.forEach(e => console.log(e.action, e.created_at));
1112
+ * }
1113
+ * ```
1114
+ */
1115
+ async auditTrail(id, requestOptions) {
1116
+ return this.http.get(
1117
+ `/invoices/${id}/audit-trail`,
1118
+ void 0,
1119
+ requestOptions
1120
+ );
1121
+ }
1122
+ /**
1123
+ * Convert invoice to another format
1124
+ *
1125
+ * @param input - Conversion parameters
1126
+ * @param requestOptions - Request options
1127
+ * @returns Conversion status
1128
+ *
1129
+ * @example
1130
+ * ```typescript
1131
+ * await client.invoices.convert({
1132
+ * invoice_id: 'invoice-uuid',
1133
+ * target_format: 'ubl'
1134
+ * });
1135
+ * ```
1136
+ */
1137
+ async convert(input, requestOptions) {
1138
+ return this.http.post("/invoices/convert", input, requestOptions);
1139
+ }
1140
+ };
1141
+
1142
+ // src/resources/signatures.ts
1143
+ var SignaturesResource = class {
1144
+ constructor(http) {
1145
+ this.http = http;
1146
+ }
1147
+ /**
1148
+ * List signature requests with optional filtering
1149
+ *
1150
+ * @param options - Filter and pagination options
1151
+ * @param requestOptions - Request options
1152
+ * @returns Paginated list of signatures
1153
+ *
1154
+ * @example
1155
+ * ```typescript
1156
+ * const { data, meta } = await client.signatures.list({
1157
+ * status: 'pending',
1158
+ * per_page: 25
1159
+ * });
1160
+ * console.log(`${meta.total} pending signatures`);
1161
+ * ```
1162
+ */
1163
+ async list(options = {}, requestOptions) {
1164
+ return this.http.get(
1165
+ "/signatures",
1166
+ options,
1167
+ requestOptions
1168
+ );
1169
+ }
1170
+ /**
1171
+ * Get a specific signature by ID
1172
+ *
1173
+ * @param id - Signature UUID
1174
+ * @param requestOptions - Request options
1175
+ * @returns Signature details with signers
1176
+ *
1177
+ * @example
1178
+ * ```typescript
1179
+ * const { data: signature } = await client.signatures.get('uuid-here');
1180
+ * signature.signers?.forEach(signer => {
1181
+ * console.log(`${signer.full_name}: ${signer.status}`);
1182
+ * });
1183
+ * ```
1184
+ */
1185
+ async get(id, requestOptions) {
1186
+ return this.http.get(
1187
+ `/signatures/${id}`,
1188
+ void 0,
1189
+ requestOptions
1190
+ );
1191
+ }
1192
+ /**
1193
+ * Create a new signature request
1194
+ *
1195
+ * Note: This endpoint requires API key authentication.
1196
+ * Creating a signature in production mode will debit your balance.
1197
+ *
1198
+ * @param input - Signature creation data
1199
+ * @param requestOptions - Request options
1200
+ * @returns Created signature
1201
+ *
1202
+ * @example
1203
+ * ```typescript
1204
+ * import { readFileSync } from 'fs';
1205
+ *
1206
+ * const pdfContent = readFileSync('contract.pdf');
1207
+ * const { data: signature } = await client.signatures.create({
1208
+ * title: 'Service Agreement',
1209
+ * description: 'Annual service contract',
1210
+ * document: pdfContent.toString('base64'),
1211
+ * document_name: 'contract.pdf',
1212
+ * signers: [
1213
+ * {
1214
+ * first_name: 'Alice',
1215
+ * last_name: 'Smith',
1216
+ * email: 'alice@example.com',
1217
+ * auth_method: 'email'
1218
+ * },
1219
+ * {
1220
+ * first_name: 'Bob',
1221
+ * last_name: 'Jones',
1222
+ * phone: '+33612345678',
1223
+ * auth_method: 'sms'
1224
+ * }
1225
+ * ],
1226
+ * ui_config: {
1227
+ * logo_url: 'https://mycompany.com/logo.png',
1228
+ * primary_color: '#3b82f6',
1229
+ * company_name: 'My Company'
1230
+ * },
1231
+ * redirect_complete_url: 'https://myapp.com/signed',
1232
+ * redirect_cancel_url: 'https://myapp.com/cancelled'
1233
+ * });
1234
+ *
1235
+ * // Send signing URLs to signers
1236
+ * signature.signers?.forEach(signer => {
1237
+ * console.log(`${signer.email}: ${signer.signing_url}`);
1238
+ * });
1239
+ * ```
1240
+ */
1241
+ async create(input, requestOptions) {
1242
+ return this.http.post(
1243
+ "/signatures",
1244
+ input,
1245
+ requestOptions
1246
+ );
1247
+ }
1248
+ /**
1249
+ * Download signature files
1250
+ *
1251
+ * @param id - Signature UUID
1252
+ * @param type - File type to download
1253
+ * @param requestOptions - Request options
1254
+ * @returns Temporary download URL
1255
+ *
1256
+ * @example
1257
+ * ```typescript
1258
+ * // Download signed document
1259
+ * const { url } = await client.signatures.download(
1260
+ * 'signature-uuid',
1261
+ * 'signed'
1262
+ * );
1263
+ *
1264
+ * // Download audit trail (proof file)
1265
+ * const { url: auditUrl } = await client.signatures.download(
1266
+ * 'signature-uuid',
1267
+ * 'audit_trail'
1268
+ * );
1269
+ * ```
1270
+ */
1271
+ async download(id, type, requestOptions) {
1272
+ return this.http.get(
1273
+ `/signatures/${id}/download/${type}`,
1274
+ void 0,
1275
+ requestOptions
1276
+ );
1277
+ }
1278
+ /**
1279
+ * Send reminder to pending signers
1280
+ *
1281
+ * @param id - Signature UUID
1282
+ * @param requestOptions - Request options
1283
+ * @returns Number of signers reminded
1284
+ *
1285
+ * @example
1286
+ * ```typescript
1287
+ * const { signers_reminded } = await client.signatures.remind('uuid');
1288
+ * console.log(`Reminded ${signers_reminded} signers`);
1289
+ * ```
1290
+ */
1291
+ async remind(id, requestOptions) {
1292
+ return this.http.post(
1293
+ `/signatures/${id}/remind`,
1294
+ void 0,
1295
+ requestOptions
1296
+ );
1297
+ }
1298
+ /**
1299
+ * Cancel a signature request
1300
+ *
1301
+ * Note: Cannot cancel completed signatures.
1302
+ *
1303
+ * @param id - Signature UUID
1304
+ * @param requestOptions - Request options
1305
+ * @returns Cancellation confirmation
1306
+ *
1307
+ * @example
1308
+ * ```typescript
1309
+ * await client.signatures.cancel('signature-uuid');
1310
+ * console.log('Signature cancelled');
1311
+ * ```
1312
+ */
1313
+ async cancel(id, requestOptions) {
1314
+ return this.http.post(
1315
+ `/signatures/${id}/cancel`,
1316
+ void 0,
1317
+ requestOptions
1318
+ );
1319
+ }
1320
+ };
1321
+
1322
+ // src/resources/webhooks.ts
1323
+ var WebhooksResource = class {
1324
+ constructor(http) {
1325
+ this.http = http;
1326
+ }
1327
+ /**
1328
+ * List all webhooks
1329
+ *
1330
+ * @param options - Filter options
1331
+ * @param requestOptions - Request options
1332
+ * @returns List of webhooks
1333
+ *
1334
+ * @example
1335
+ * ```typescript
1336
+ * const { data: webhooks } = await client.webhooks.list();
1337
+ * webhooks.forEach(wh => {
1338
+ * console.log(`${wh.url}: ${wh.is_active ? 'active' : 'inactive'}`);
1339
+ * });
1340
+ * ```
1341
+ */
1342
+ async list(options = {}, requestOptions) {
1343
+ return this.http.get(
1344
+ "/webhooks",
1345
+ options,
1346
+ requestOptions
1347
+ );
1348
+ }
1349
+ /**
1350
+ * Create a new webhook
1351
+ *
1352
+ * Important: The secret is only returned once during creation.
1353
+ * Store it securely - you'll need it to verify webhook signatures.
1354
+ *
1355
+ * @param input - Webhook configuration
1356
+ * @param requestOptions - Request options
1357
+ * @returns Created webhook with secret
1358
+ *
1359
+ * @example
1360
+ * ```typescript
1361
+ * const { data: webhook } = await client.webhooks.create({
1362
+ * url: 'https://myapp.com/webhooks/scell',
1363
+ * events: [
1364
+ * 'invoice.created',
1365
+ * 'invoice.validated',
1366
+ * 'signature.completed',
1367
+ * 'balance.low'
1368
+ * ],
1369
+ * environment: 'production',
1370
+ * headers: {
1371
+ * 'X-Custom-Auth': 'my-secret-token'
1372
+ * },
1373
+ * retry_count: 5,
1374
+ * timeout_seconds: 30
1375
+ * });
1376
+ *
1377
+ * // IMPORTANT: Store this secret securely!
1378
+ * await saveWebhookSecret(webhook.id, webhook.secret);
1379
+ * ```
1380
+ */
1381
+ async create(input, requestOptions) {
1382
+ return this.http.post(
1383
+ "/webhooks",
1384
+ input,
1385
+ requestOptions
1386
+ );
1387
+ }
1388
+ /**
1389
+ * Update a webhook
1390
+ *
1391
+ * @param id - Webhook UUID
1392
+ * @param input - Fields to update
1393
+ * @param requestOptions - Request options
1394
+ * @returns Updated webhook
1395
+ *
1396
+ * @example
1397
+ * ```typescript
1398
+ * // Disable a webhook temporarily
1399
+ * await client.webhooks.update('webhook-uuid', {
1400
+ * is_active: false
1401
+ * });
1402
+ *
1403
+ * // Update events
1404
+ * await client.webhooks.update('webhook-uuid', {
1405
+ * events: ['invoice.validated', 'signature.completed']
1406
+ * });
1407
+ * ```
1408
+ */
1409
+ async update(id, input, requestOptions) {
1410
+ return this.http.put(
1411
+ `/webhooks/${id}`,
1412
+ input,
1413
+ requestOptions
1414
+ );
1415
+ }
1416
+ /**
1417
+ * Delete a webhook
1418
+ *
1419
+ * @param id - Webhook UUID
1420
+ * @param requestOptions - Request options
1421
+ * @returns Deletion confirmation
1422
+ *
1423
+ * @example
1424
+ * ```typescript
1425
+ * await client.webhooks.delete('webhook-uuid');
1426
+ * ```
1427
+ */
1428
+ async delete(id, requestOptions) {
1429
+ return this.http.delete(`/webhooks/${id}`, requestOptions);
1430
+ }
1431
+ /**
1432
+ * Regenerate webhook secret
1433
+ *
1434
+ * Use this if your secret has been compromised.
1435
+ * The old secret will immediately stop working.
1436
+ *
1437
+ * @param id - Webhook UUID
1438
+ * @param requestOptions - Request options
1439
+ * @returns Webhook with new secret
1440
+ *
1441
+ * @example
1442
+ * ```typescript
1443
+ * const { data: webhook } = await client.webhooks.regenerateSecret(
1444
+ * 'webhook-uuid'
1445
+ * );
1446
+ *
1447
+ * // Update your stored secret
1448
+ * await updateWebhookSecret(webhook.id, webhook.secret);
1449
+ * ```
1450
+ */
1451
+ async regenerateSecret(id, requestOptions) {
1452
+ return this.http.post(
1453
+ `/webhooks/${id}/regenerate-secret`,
1454
+ void 0,
1455
+ requestOptions
1456
+ );
1457
+ }
1458
+ /**
1459
+ * Test webhook by sending a test event
1460
+ *
1461
+ * @param id - Webhook UUID
1462
+ * @param requestOptions - Request options
1463
+ * @returns Test result
1464
+ *
1465
+ * @example
1466
+ * ```typescript
1467
+ * const result = await client.webhooks.test('webhook-uuid');
1468
+ *
1469
+ * if (result.success) {
1470
+ * console.log(`Success! Response time: ${result.response_time_ms}ms`);
1471
+ * } else {
1472
+ * console.log(`Failed: ${result.error}`);
1473
+ * }
1474
+ * ```
1475
+ */
1476
+ async test(id, requestOptions) {
1477
+ return this.http.post(
1478
+ `/webhooks/${id}/test`,
1479
+ void 0,
1480
+ requestOptions
1481
+ );
1482
+ }
1483
+ /**
1484
+ * Get webhook delivery logs
1485
+ *
1486
+ * @param id - Webhook UUID
1487
+ * @param options - Pagination options
1488
+ * @param requestOptions - Request options
1489
+ * @returns Paginated list of logs
1490
+ *
1491
+ * @example
1492
+ * ```typescript
1493
+ * const { data: logs } = await client.webhooks.logs('webhook-uuid', {
1494
+ * per_page: 50
1495
+ * });
1496
+ *
1497
+ * logs.forEach(log => {
1498
+ * const status = log.success ? 'OK' : 'FAILED';
1499
+ * console.log(`${log.event} - ${status} (${log.response_time_ms}ms)`);
1500
+ * });
1501
+ * ```
1502
+ */
1503
+ async logs(id, options = {}, requestOptions) {
1504
+ return this.http.get(
1505
+ `/webhooks/${id}/logs`,
1506
+ options,
1507
+ requestOptions
1508
+ );
1509
+ }
1510
+ };
1511
+
1512
+ // src/utils/webhook-verify.ts
1513
+ function parseSignatureHeader(header) {
1514
+ const parts = header.split(",");
1515
+ let timestamp;
1516
+ let signature;
1517
+ for (const part of parts) {
1518
+ const splitIndex = part.indexOf("=");
1519
+ if (splitIndex === -1) continue;
1520
+ const key = part.substring(0, splitIndex);
1521
+ const value = part.substring(splitIndex + 1);
1522
+ if (key === "t") {
1523
+ timestamp = parseInt(value, 10);
1524
+ } else if (key === "v1") {
1525
+ signature = value;
1526
+ }
1527
+ }
1528
+ if (timestamp === void 0 || signature === void 0) {
1529
+ return null;
1530
+ }
1531
+ return { timestamp, signature };
1532
+ }
1533
+ async function computeSignature(payload, timestamp, secret) {
1534
+ const signedPayload = `${timestamp}.${payload}`;
1535
+ const encoder = new TextEncoder();
1536
+ const keyData = encoder.encode(secret);
1537
+ const messageData = encoder.encode(signedPayload);
1538
+ const cryptoKey = await crypto.subtle.importKey(
1539
+ "raw",
1540
+ keyData,
1541
+ { name: "HMAC", hash: "SHA-256" },
1542
+ false,
1543
+ ["sign"]
1544
+ );
1545
+ const signatureBuffer = await crypto.subtle.sign(
1546
+ "HMAC",
1547
+ cryptoKey,
1548
+ messageData
1549
+ );
1550
+ return Array.from(new Uint8Array(signatureBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
1551
+ }
1552
+ function secureCompare(a, b) {
1553
+ if (a.length !== b.length) {
1554
+ return false;
1555
+ }
1556
+ let result = 0;
1557
+ for (let i = 0; i < a.length; i++) {
1558
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
1559
+ }
1560
+ return result === 0;
1561
+ }
1562
+ var ScellWebhooks = {
1563
+ /**
1564
+ * Verify webhook signature
1565
+ *
1566
+ * @param payload - Raw request body as string
1567
+ * @param signature - Value of X-Scell-Signature header
1568
+ * @param secret - Your webhook secret (whsec_...)
1569
+ * @param options - Verification options
1570
+ * @returns True if signature is valid
1571
+ *
1572
+ * @example
1573
+ * ```typescript
1574
+ * const isValid = await ScellWebhooks.verifySignature(
1575
+ * rawBody,
1576
+ * req.headers['x-scell-signature'],
1577
+ * 'whsec_abc123...'
1578
+ * );
1579
+ * ```
1580
+ */
1581
+ async verifySignature(payload, signature, secret, options = {}) {
1582
+ const { tolerance = 300 } = options;
1583
+ const parsed = parseSignatureHeader(signature);
1584
+ if (!parsed) {
1585
+ return false;
1586
+ }
1587
+ const { timestamp, signature: providedSignature } = parsed;
1588
+ const now = Math.floor(Date.now() / 1e3);
1589
+ if (Math.abs(now - timestamp) > tolerance) {
1590
+ return false;
1591
+ }
1592
+ const expectedSignature = await computeSignature(payload, timestamp, secret);
1593
+ return secureCompare(expectedSignature, providedSignature);
1594
+ },
1595
+ /**
1596
+ * Verify webhook signature synchronously using Node.js crypto
1597
+ * (Only works in Node.js environment)
1598
+ *
1599
+ * @param payload - Raw request body as string
1600
+ * @param signature - Value of X-Scell-Signature header
1601
+ * @param secret - Your webhook secret (whsec_...)
1602
+ * @param options - Verification options
1603
+ * @returns True if signature is valid
1604
+ */
1605
+ verifySignatureSync(payload, signature, secret, options = {}) {
1606
+ const { tolerance = 300 } = options;
1607
+ const parsed = parseSignatureHeader(signature);
1608
+ if (!parsed) {
1609
+ return false;
1610
+ }
1611
+ const { timestamp, signature: providedSignature } = parsed;
1612
+ const now = Math.floor(Date.now() / 1e3);
1613
+ if (Math.abs(now - timestamp) > tolerance) {
1614
+ return false;
1615
+ }
1616
+ const crypto2 = __require("crypto");
1617
+ const signedPayload = `${timestamp}.${payload}`;
1618
+ const expectedSignature = crypto2.createHmac("sha256", secret).update(signedPayload).digest("hex");
1619
+ try {
1620
+ return crypto2.timingSafeEqual(
1621
+ Buffer.from(expectedSignature),
1622
+ Buffer.from(providedSignature)
1623
+ );
1624
+ } catch {
1625
+ return false;
1626
+ }
1627
+ },
1628
+ /**
1629
+ * Parse webhook payload
1630
+ *
1631
+ * @param payload - Raw request body as string
1632
+ * @returns Parsed webhook payload
1633
+ *
1634
+ * @example
1635
+ * ```typescript
1636
+ * const event = ScellWebhooks.parsePayload<InvoiceWebhookData>(rawBody);
1637
+ * if (event.event === 'invoice.validated') {
1638
+ * console.log('Invoice validated:', event.data.invoice_number);
1639
+ * }
1640
+ * ```
1641
+ */
1642
+ parsePayload(payload) {
1643
+ return JSON.parse(payload);
1644
+ },
1645
+ /**
1646
+ * Construct a test webhook event for local testing
1647
+ *
1648
+ * @param event - Event type
1649
+ * @param data - Event data
1650
+ * @param secret - Webhook secret for signing
1651
+ * @returns Object with payload and headers for testing
1652
+ */
1653
+ async constructTestEvent(event, data, secret) {
1654
+ const timestamp = Math.floor(Date.now() / 1e3);
1655
+ const webhookPayload = {
1656
+ event,
1657
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1658
+ data
1659
+ };
1660
+ const payload = JSON.stringify(webhookPayload);
1661
+ const signature = await computeSignature(payload, timestamp, secret);
1662
+ return {
1663
+ payload,
1664
+ headers: {
1665
+ "X-Scell-Signature": `t=${timestamp},v1=${signature}`,
1666
+ "X-Scell-Event": event,
1667
+ "X-Scell-Delivery": crypto.randomUUID(),
1668
+ "Content-Type": "application/json"
1669
+ }
1670
+ };
1671
+ }
1672
+ };
1673
+
1674
+ // src/index.ts
1675
+ init_errors();
1676
+ var ScellClient = class {
1677
+ http;
1678
+ /** Authentication operations */
1679
+ auth;
1680
+ /** Company management */
1681
+ companies;
1682
+ /** API key management */
1683
+ apiKeys;
1684
+ /** Balance and transactions */
1685
+ balance;
1686
+ /** Webhook management */
1687
+ webhooks;
1688
+ /** Invoice listing (read-only via dashboard) */
1689
+ invoices;
1690
+ /** Signature listing (read-only via dashboard) */
1691
+ signatures;
1692
+ /**
1693
+ * Create a new Scell Dashboard Client
1694
+ *
1695
+ * @param token - Bearer token from login
1696
+ * @param config - Client configuration
1697
+ *
1698
+ * @example
1699
+ * ```typescript
1700
+ * const client = new ScellClient('your-bearer-token', {
1701
+ * baseUrl: 'https://api.scell.io/api/v1',
1702
+ * timeout: 30000,
1703
+ * retry: { maxRetries: 3 }
1704
+ * });
1705
+ * ```
1706
+ */
1707
+ constructor(token, config = {}) {
1708
+ this.http = new HttpClient("bearer", token, config);
1709
+ this.auth = new AuthResource(this.http);
1710
+ this.companies = new CompaniesResource(this.http);
1711
+ this.apiKeys = new ApiKeysResource(this.http);
1712
+ this.balance = new BalanceResource(this.http);
1713
+ this.webhooks = new WebhooksResource(this.http);
1714
+ this.invoices = new InvoicesResource(this.http);
1715
+ this.signatures = new SignaturesResource(this.http);
1716
+ }
1717
+ };
1718
+ var ScellApiClient = class {
1719
+ http;
1720
+ /** Invoice operations (create, download, convert) */
1721
+ invoices;
1722
+ /** Signature operations (create, download, remind, cancel) */
1723
+ signatures;
1724
+ /**
1725
+ * Create a new Scell API Client
1726
+ *
1727
+ * @param apiKey - Your API key (from dashboard)
1728
+ * @param config - Client configuration
1729
+ *
1730
+ * @example
1731
+ * ```typescript
1732
+ * // Production client
1733
+ * const client = new ScellApiClient('sk_live_xxx');
1734
+ *
1735
+ * // Sandbox client
1736
+ * const sandboxClient = new ScellApiClient('sk_test_xxx', {
1737
+ * baseUrl: 'https://api.scell.io/api/v1/sandbox'
1738
+ * });
1739
+ * ```
1740
+ */
1741
+ constructor(apiKey, config = {}) {
1742
+ this.http = new HttpClient("api-key", apiKey, config);
1743
+ this.invoices = new InvoicesResource(this.http);
1744
+ this.signatures = new SignaturesResource(this.http);
1745
+ }
1746
+ };
1747
+
1748
+ exports.ScellApiClient = ScellApiClient;
1749
+ exports.ScellAuth = ScellAuth;
1750
+ exports.ScellClient = ScellClient;
1751
+ exports.ScellWebhooks = ScellWebhooks;
1752
+ exports.createRetryWrapper = createRetryWrapper;
1753
+ exports.withRetry = withRetry;
1754
+ //# sourceMappingURL=index.js.map
1755
+ //# sourceMappingURL=index.js.map