@fastermessage/sdk 0.0.0-stage → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,60 @@
1
+ import type { RequestOptions, Requester } from './http.js';
2
+ import type { Balance, Contact, ContactBatchResult, ContactGroup, ContactQuery, CreateContactBatchParams, CreateContactGroupParams, CreateContactParams, CreditMovement, CreditQuery, Message, MessageQuery, Otp, Page, PageQuery, RequestOtpParams, SendEmailParams, SendMessageParams, SendSmsBatchParams, SendSmsParams, SmsBatchResult, UpdateContactGroupParams, UpdateContactParams } from './types.js';
3
+ export declare class Sms {
4
+ #private;
5
+ constructor(http: Requester);
6
+ send(params: SendSmsParams, options?: RequestOptions): Promise<Message>;
7
+ /** Jusqu'à 500 lignes. Lisez toujours `errors` : un retour normal ne garantit pas que toutes soient parties. */
8
+ sendBatch(params: SendSmsBatchParams, options?: RequestOptions): Promise<SmsBatchResult>;
9
+ }
10
+ export declare class Email {
11
+ #private;
12
+ constructor(http: Requester);
13
+ send(params: SendEmailParams, options?: RequestOptions): Promise<Message>;
14
+ }
15
+ export declare class Messages {
16
+ #private;
17
+ constructor(http: Requester);
18
+ /** Envoi avec le canal en paramètre. WhatsApp et la voix répondent aujourd'hui `501`. */
19
+ send(params: SendMessageParams, options?: RequestOptions): Promise<Message>;
20
+ get(id: string): Promise<Message>;
21
+ list(query?: MessageQuery): Promise<Page<Message>>;
22
+ all(query?: MessageQuery): AsyncGenerator<Message, void, undefined>;
23
+ }
24
+ export declare class OtpResource {
25
+ #private;
26
+ constructor(http: Requester);
27
+ request(params: RequestOtpParams, options?: RequestOptions): Promise<Otp>;
28
+ verify(id: string, code: string): Promise<Otp>;
29
+ }
30
+ export declare class Contacts {
31
+ #private;
32
+ constructor(http: Requester);
33
+ create(params: CreateContactParams): Promise<Contact>;
34
+ /** Crée jusqu'à 500 contacts dans un groupe. */
35
+ createBatch(params: CreateContactBatchParams, options?: RequestOptions): Promise<ContactBatchResult>;
36
+ get(id: string): Promise<Contact>;
37
+ list(query?: ContactQuery): Promise<Page<Contact>>;
38
+ all(query?: ContactQuery): AsyncGenerator<Contact, void, undefined>;
39
+ update(id: string, params: UpdateContactParams): Promise<Contact>;
40
+ /** Suppression définitive. Ce n'est pas un désabonnement : pour cela, `consent: 'out'`. */
41
+ delete(id: string): Promise<void>;
42
+ }
43
+ export declare class ContactGroups {
44
+ #private;
45
+ constructor(http: Requester);
46
+ create(params: CreateContactGroupParams): Promise<ContactGroup>;
47
+ get(id: string): Promise<ContactGroup>;
48
+ list(query?: PageQuery): Promise<Page<ContactGroup>>;
49
+ all(query?: PageQuery): AsyncGenerator<ContactGroup, void, undefined>;
50
+ update(id: string, params: UpdateContactGroupParams): Promise<ContactGroup>;
51
+ /** Refusé en `409` tant que le groupe contient des contacts. */
52
+ delete(id: string): Promise<void>;
53
+ }
54
+ export declare class Account {
55
+ #private;
56
+ constructor(http: Requester);
57
+ balance(): Promise<Balance[]>;
58
+ credits(query?: CreditQuery): Promise<Page<CreditMovement>>;
59
+ allCredits(query?: CreditQuery): AsyncGenerator<CreditMovement, void, undefined>;
60
+ }
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Account = exports.ContactGroups = exports.Contacts = exports.OtpResource = exports.Messages = exports.Email = exports.Sms = void 0;
4
+ function segment(id) {
5
+ // `..` changerait la route visée, et un identifiant vide viserait la collection.
6
+ if (id === '' || id === '.' || id === '..')
7
+ throw new TypeError('Identifiant de ressource invalide.');
8
+ return encodeURIComponent(id);
9
+ }
10
+ /** Parcourt toutes les pages, en demandant la suivante seulement quand il le faut. */
11
+ async function* paginate(http, path, query) {
12
+ let cursor = query.cursor;
13
+ for (;;) {
14
+ const page = await http.request('GET', path, { query: { ...query, cursor } });
15
+ yield* page.data ?? [];
16
+ cursor = page.next_cursor;
17
+ if (page.has_more !== true || cursor === null || cursor === undefined)
18
+ return;
19
+ }
20
+ }
21
+ class Sms {
22
+ #http;
23
+ constructor(http) { this.#http = http; }
24
+ send(params, options) {
25
+ return this.#http.request('POST', '/v2/sms/send', { body: params, options });
26
+ }
27
+ /** Jusqu'à 500 lignes. Lisez toujours `errors` : un retour normal ne garantit pas que toutes soient parties. */
28
+ sendBatch(params, options) {
29
+ return this.#http.request('POST', '/v2/sms/batch', { body: params, options });
30
+ }
31
+ }
32
+ exports.Sms = Sms;
33
+ class Email {
34
+ #http;
35
+ constructor(http) { this.#http = http; }
36
+ send(params, options) {
37
+ return this.#http.request('POST', '/v2/email/send', { body: params, options });
38
+ }
39
+ }
40
+ exports.Email = Email;
41
+ class Messages {
42
+ #http;
43
+ constructor(http) { this.#http = http; }
44
+ /** Envoi avec le canal en paramètre. WhatsApp et la voix répondent aujourd'hui `501`. */
45
+ send(params, options) {
46
+ return this.#http.request('POST', '/v2/messages', { body: params, options });
47
+ }
48
+ get(id) {
49
+ return this.#http.request('GET', `/v2/messages/${segment(id)}`);
50
+ }
51
+ list(query = {}) {
52
+ return this.#http.request('GET', '/v2/messages', { query });
53
+ }
54
+ all(query = {}) {
55
+ return paginate(this.#http, '/v2/messages', query);
56
+ }
57
+ }
58
+ exports.Messages = Messages;
59
+ class OtpResource {
60
+ #http;
61
+ constructor(http) { this.#http = http; }
62
+ request(params, options) {
63
+ return this.#http.request('POST', '/v2/otp', { body: { channel: 'sms', ...params }, options });
64
+ }
65
+ verify(id, code) {
66
+ return this.#http.request('POST', '/v2/otp/verify', { body: { id, code } });
67
+ }
68
+ }
69
+ exports.OtpResource = OtpResource;
70
+ class Contacts {
71
+ #http;
72
+ constructor(http) { this.#http = http; }
73
+ create(params) {
74
+ return this.#http.request('POST', '/v2/contacts', { body: params });
75
+ }
76
+ /** Crée jusqu'à 500 contacts dans un groupe. */
77
+ createBatch(params, options) {
78
+ return this.#http.request('POST', '/v2/contacts/batch', { body: params, options });
79
+ }
80
+ get(id) {
81
+ return this.#http.request('GET', `/v2/contacts/${segment(id)}`);
82
+ }
83
+ list(query = {}) {
84
+ return this.#http.request('GET', '/v2/contacts', { query });
85
+ }
86
+ all(query = {}) {
87
+ return paginate(this.#http, '/v2/contacts', query);
88
+ }
89
+ update(id, params) {
90
+ return this.#http.request('PATCH', `/v2/contacts/${segment(id)}`, { body: params });
91
+ }
92
+ /** Suppression définitive. Ce n'est pas un désabonnement : pour cela, `consent: 'out'`. */
93
+ async delete(id) {
94
+ await this.#http.request('DELETE', `/v2/contacts/${segment(id)}`);
95
+ }
96
+ }
97
+ exports.Contacts = Contacts;
98
+ class ContactGroups {
99
+ #http;
100
+ constructor(http) { this.#http = http; }
101
+ create(params) {
102
+ return this.#http.request('POST', '/v2/contact-groups', { body: params });
103
+ }
104
+ get(id) {
105
+ return this.#http.request('GET', `/v2/contact-groups/${segment(id)}`);
106
+ }
107
+ list(query = {}) {
108
+ return this.#http.request('GET', '/v2/contact-groups', { query });
109
+ }
110
+ all(query = {}) {
111
+ return paginate(this.#http, '/v2/contact-groups', query);
112
+ }
113
+ update(id, params) {
114
+ return this.#http.request('PATCH', `/v2/contact-groups/${segment(id)}`, { body: params });
115
+ }
116
+ /** Refusé en `409` tant que le groupe contient des contacts. */
117
+ async delete(id) {
118
+ await this.#http.request('DELETE', `/v2/contact-groups/${segment(id)}`);
119
+ }
120
+ }
121
+ exports.ContactGroups = ContactGroups;
122
+ class Account {
123
+ #http;
124
+ constructor(http) { this.#http = http; }
125
+ async balance() {
126
+ const { balances } = await this.#http.request('GET', '/v2/balance');
127
+ return balances ?? [];
128
+ }
129
+ credits(query = {}) {
130
+ return this.#http.request('GET', '/v2/credits', { query });
131
+ }
132
+ allCredits(query = {}) {
133
+ return paginate(this.#http, '/v2/credits', query);
134
+ }
135
+ }
136
+ exports.Account = Account;
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Les réponses gardent les noms de champs de l'API. La signature ouverte de chaque
3
+ * ressource rend disponible un champ ajouté par l'API sans mise à jour du SDK.
4
+ */
5
+ export interface OpenRecord {
6
+ [field: string]: unknown;
7
+ }
8
+ export type Channel = 'sms' | 'email' | 'whatsapp' | 'voice';
9
+ export type Consent = 'in' | 'out' | (string & {});
10
+ export interface Page<T> extends OpenRecord {
11
+ data: T[];
12
+ has_more: boolean;
13
+ next_cursor: string | null;
14
+ }
15
+ export interface PageQuery {
16
+ limit?: number;
17
+ cursor?: string;
18
+ }
19
+ export interface MessageError extends OpenRecord {
20
+ code: string;
21
+ message: string;
22
+ provider_code: string | null;
23
+ }
24
+ export interface MessageRefund extends OpenRecord {
25
+ amount: number;
26
+ currency: string;
27
+ refunded_at: string;
28
+ }
29
+ export interface FallbackOutcome extends OpenRecord {
30
+ will_run: boolean;
31
+ reason: string | null;
32
+ message: string;
33
+ requested: Channel[];
34
+ }
35
+ export interface Message extends OpenRecord {
36
+ id: string;
37
+ channel: Channel;
38
+ status: string;
39
+ to: string;
40
+ from: string;
41
+ units: number;
42
+ price: number | null;
43
+ currency: string;
44
+ refund: MessageRefund | null;
45
+ client_reference: string | null;
46
+ fallback_of: string | null;
47
+ fallback?: FallbackOutcome | null;
48
+ error: MessageError | null;
49
+ created_at: string;
50
+ scheduled_at: string | null;
51
+ sent_at: string | null;
52
+ delivered_at: string | null;
53
+ }
54
+ interface SendCommon extends OpenRecord {
55
+ to: string;
56
+ fallback?: unknown[];
57
+ callback_url?: string;
58
+ scheduled_at?: string;
59
+ client_reference?: string;
60
+ }
61
+ export interface SendSmsParams extends SendCommon {
62
+ /** Sender ID approuvé : obligatoire, sans repli. */
63
+ from: string;
64
+ content: string | OpenRecord;
65
+ }
66
+ export interface EmailContent extends OpenRecord {
67
+ subject: string;
68
+ text?: string;
69
+ html?: string;
70
+ }
71
+ export interface SendEmailParams extends SendCommon {
72
+ from?: string;
73
+ content: EmailContent;
74
+ }
75
+ export interface SendMessageParams extends SendCommon {
76
+ channel: Channel;
77
+ from?: string;
78
+ content: unknown;
79
+ }
80
+ export interface SmsBatchLine extends OpenRecord {
81
+ to: string;
82
+ content?: string | OpenRecord;
83
+ from?: string;
84
+ client_reference?: string;
85
+ scheduled_at?: string;
86
+ callback_url?: string;
87
+ }
88
+ export interface SendSmsBatchParams extends OpenRecord {
89
+ /** De 1 à 500 lignes. */
90
+ messages: SmsBatchLine[];
91
+ from?: string;
92
+ content?: string | OpenRecord;
93
+ scheduled_at?: string;
94
+ callback_url?: string;
95
+ }
96
+ export interface BatchLineError extends OpenRecord {
97
+ index: number;
98
+ code: string;
99
+ message: string;
100
+ param?: string;
101
+ to?: string;
102
+ }
103
+ export interface SmsBatchResult extends OpenRecord {
104
+ total: number;
105
+ accepted: number;
106
+ rejected: number;
107
+ data: (Message & {
108
+ index: number;
109
+ })[];
110
+ /** Une entrée par ligne refusée : le reste du lot est bien parti. */
111
+ errors: BatchLineError[];
112
+ }
113
+ export interface MessageQuery extends PageQuery {
114
+ channel?: Channel;
115
+ status?: string;
116
+ [filter: string]: unknown;
117
+ }
118
+ export interface RequestOtpParams extends OpenRecord {
119
+ to: string;
120
+ /** `sms` par défaut. */
121
+ channel?: Channel;
122
+ from?: string;
123
+ length?: number;
124
+ ttl_seconds?: number;
125
+ template?: string;
126
+ client_reference?: string;
127
+ }
128
+ export interface Otp extends OpenRecord {
129
+ id: string;
130
+ status: string;
131
+ attempts_remaining: number;
132
+ }
133
+ export interface ContactFields extends OpenRecord {
134
+ email?: string;
135
+ whatsapp?: boolean;
136
+ consent?: Consent;
137
+ fields?: string[];
138
+ }
139
+ export interface CreateContactParams extends ContactFields {
140
+ group_id: string;
141
+ phone_number: string;
142
+ }
143
+ export interface UpdateContactParams extends OpenRecord {
144
+ group_id?: string;
145
+ phone_number?: string;
146
+ email?: string | null;
147
+ whatsapp?: boolean;
148
+ consent?: Consent;
149
+ fields?: string[];
150
+ }
151
+ export interface CreateContactBatchParams extends OpenRecord {
152
+ group_id: string;
153
+ /** De 1 à 500 lignes. */
154
+ contacts: (ContactFields & {
155
+ phone_number: string;
156
+ })[];
157
+ on_duplicate?: string;
158
+ }
159
+ export interface Contact extends OpenRecord {
160
+ id: string;
161
+ group_id: string;
162
+ phone_number: string;
163
+ consent: Consent;
164
+ }
165
+ export interface ContactBatchResult extends OpenRecord {
166
+ created: number;
167
+ invalid: number;
168
+ }
169
+ export interface ContactQuery extends PageQuery {
170
+ group_id?: string;
171
+ consent?: Consent;
172
+ search?: string;
173
+ }
174
+ export interface CreateContactGroupParams extends OpenRecord {
175
+ name: string;
176
+ fields?: string[];
177
+ }
178
+ export interface UpdateContactGroupParams extends OpenRecord {
179
+ name?: string;
180
+ fields?: string[];
181
+ }
182
+ export interface ContactGroup extends OpenRecord {
183
+ id: string;
184
+ name: string;
185
+ contacts_count: number;
186
+ fields: string[];
187
+ }
188
+ export interface Balance extends OpenRecord {
189
+ channel: Channel;
190
+ amount: number;
191
+ currency: string;
192
+ }
193
+ export interface CreditMovement extends OpenRecord {
194
+ id: string;
195
+ type: 'credit' | 'debit' | 'refund';
196
+ channel: Channel;
197
+ amount: number;
198
+ currency: string;
199
+ }
200
+ export interface CreditQuery extends PageQuery {
201
+ type?: 'credit' | 'debit' | 'refund';
202
+ [filter: string]: unknown;
203
+ }
204
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ /** Vérification des rappels reçus sur votre serveur. */
2
+ export declare const Webhook: {
3
+ /**
4
+ * Vrai si le rappel vient bien de la plateforme.
5
+ *
6
+ * @param rawBody le corps BRUT, avant tout décodage JSON
7
+ * @param signature l'en-tête `X-Fastermessage-Signature`
8
+ * @param secret le secret généré dans « Intégration & API »
9
+ */
10
+ isGenuine(rawBody: string | Uint8Array, signature: string | null | undefined, secret: string): boolean;
11
+ };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Webhook = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ /** Vérification des rappels reçus sur votre serveur. */
6
+ exports.Webhook = {
7
+ /**
8
+ * Vrai si le rappel vient bien de la plateforme.
9
+ *
10
+ * @param rawBody le corps BRUT, avant tout décodage JSON
11
+ * @param signature l'en-tête `X-Fastermessage-Signature`
12
+ * @param secret le secret généré dans « Intégration & API »
13
+ */
14
+ isGenuine(rawBody, signature, secret) {
15
+ if (typeof signature !== 'string' || !secret)
16
+ return false;
17
+ const expected = Buffer.from(`sha256=${(0, node_crypto_1.createHmac)('sha256', secret).update(rawBody).digest('hex')}`);
18
+ const received = Buffer.from(signature.trim());
19
+ return expected.length === received.length && (0, node_crypto_1.timingSafeEqual)(expected, received);
20
+ },
21
+ };
@@ -0,0 +1,34 @@
1
+ import { Account, ContactGroups, Contacts, Email, Messages, OtpResource, Sms } from './resources.js';
2
+ export declare const DEFAULT_BASE_URL = "https://api.fastermessage.com";
3
+ export interface FasterMessageOptions {
4
+ /** Identifiant d'API, compte débité. */
5
+ username: string;
6
+ /** Mot de passe d'API. */
7
+ password: string;
8
+ /** Clé `fm_live_…` (réel) ou `fm_test_…` (simulé). */
9
+ apiKey: string;
10
+ /** Le domaine d'API de votre marque, le cas échéant. */
11
+ baseUrl?: string;
12
+ /** Délai de chaque tentative, en millisecondes. 30 000 par défaut. */
13
+ timeout?: number;
14
+ /** Nombre de reprises après la première tentative. 2 par défaut. */
15
+ maxRetries?: number;
16
+ /** Remplace `fetch`, par exemple pour passer par un proxy ou pour vos tests. */
17
+ fetch?: typeof globalThis.fetch;
18
+ /** Remplace l'attente entre deux reprises, surtout utile dans vos tests. */
19
+ sleep?: (milliseconds: number) => Promise<void>;
20
+ }
21
+ /** Point d'entrée du SDK. Côté serveur seulement : il porte vos identifiants. */
22
+ export declare class FasterMessage {
23
+ #private;
24
+ readonly sms: Sms;
25
+ readonly email: Email;
26
+ readonly messages: Messages;
27
+ readonly otp: OtpResource;
28
+ readonly contacts: Contacts;
29
+ readonly contactGroups: ContactGroups;
30
+ readonly account: Account;
31
+ constructor(options: FasterMessageOptions);
32
+ /** Vrai avec une clé de test : messages et OTP simulés, mais contacts et soldes réels. */
33
+ get testMode(): boolean;
34
+ }
@@ -0,0 +1,68 @@
1
+ import { Requester } from './http.js';
2
+ import { Account, ContactGroups, Contacts, Email, Messages, OtpResource, Sms } from './resources.js';
3
+ export const DEFAULT_BASE_URL = 'https://api.fastermessage.com';
4
+ const LOCAL_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
5
+ /** Les identifiants ne partent qu'en https, sauf vers la machine locale. */
6
+ function checkedBaseUrl(value) {
7
+ const message = 'baseUrl doit être une adresse https, sans identifiants (http seulement vers la machine locale).';
8
+ let url;
9
+ try {
10
+ url = new URL(value);
11
+ }
12
+ catch {
13
+ throw new TypeError(message);
14
+ }
15
+ const allowed = url.protocol === 'https:' || (url.protocol === 'http:' && LOCAL_HOSTS.has(url.hostname));
16
+ if (!allowed || !url.hostname || url.username || url.password || url.search || url.hash)
17
+ throw new TypeError(message);
18
+ return `${url.origin}${url.pathname}`.replace(/\/+$/, '');
19
+ }
20
+ /** Point d'entrée du SDK. Côté serveur seulement : il porte vos identifiants. */
21
+ export class FasterMessage {
22
+ sms;
23
+ email;
24
+ messages;
25
+ otp;
26
+ contacts;
27
+ contactGroups;
28
+ account;
29
+ #testMode;
30
+ constructor(options) {
31
+ const { username, password, apiKey } = options ?? {};
32
+ if (!username || !password || !apiKey) {
33
+ throw new TypeError("L'identifiant, le mot de passe et la clé d'API sont tous obligatoires.");
34
+ }
35
+ if ('window' in globalThis && 'document' in globalThis) {
36
+ throw new Error('Le SDK FasterMessage ne s’utilise pas dans un navigateur : vos identifiants y seraient publics.');
37
+ }
38
+ if (!/^[\x21-\x7e]+$/.test(apiKey)) {
39
+ // Le message ne cite jamais la valeur : il finirait dans vos journaux.
40
+ throw new TypeError('La clé d’API contient des caractères invalides : vérifiez son copier-coller.');
41
+ }
42
+ this.#testMode = apiKey.includes('_test_');
43
+ const http = new Requester({
44
+ authorization: `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
45
+ apiKey,
46
+ baseUrl: checkedBaseUrl(options.baseUrl ?? DEFAULT_BASE_URL),
47
+ timeout: options.timeout ?? 30_000,
48
+ maxRetries: Math.max(0, options.maxRetries ?? 2),
49
+ ...(options.fetch ? { fetch: options.fetch } : {}),
50
+ ...(options.sleep ? { sleep: options.sleep } : {}),
51
+ });
52
+ this.sms = new Sms(http);
53
+ this.email = new Email(http);
54
+ this.messages = new Messages(http);
55
+ this.otp = new OtpResource(http);
56
+ this.contacts = new Contacts(http);
57
+ this.contactGroups = new ContactGroups(http);
58
+ this.account = new Account(http);
59
+ }
60
+ /** Vrai avec une clé de test : messages et OTP simulés, mais contacts et soldes réels. */
61
+ get testMode() {
62
+ return this.#testMode;
63
+ }
64
+ /** Évite d'écrire le moindre détail du client dans un journal par `console.log`. */
65
+ [Symbol.for('nodejs.util.inspect.custom')]() {
66
+ return `FasterMessage { testMode: ${this.#testMode} }`;
67
+ }
68
+ }
@@ -0,0 +1,59 @@
1
+ /** Toute erreur levée par le SDK. */
2
+ export declare class FasterMessageError extends Error {
3
+ constructor(message: string, options?: ErrorOptions);
4
+ }
5
+ export interface ApiErrorDetails {
6
+ status: number;
7
+ code: string;
8
+ type?: string;
9
+ param?: string | null;
10
+ requestId?: string | null;
11
+ retryAfter?: number | null;
12
+ }
13
+ /**
14
+ * Refus de l'API. Testez `code`, qui est stable : `message` est un libellé en
15
+ * anglais, susceptible d'être reformulé.
16
+ */
17
+ export declare class ApiError extends FasterMessageError {
18
+ readonly status: number;
19
+ readonly code: string;
20
+ readonly type: string;
21
+ readonly param: string | null;
22
+ readonly requestId: string | null;
23
+ readonly retryAfter: number | null;
24
+ constructor(message: string, details: ApiErrorDetails);
25
+ }
26
+ /** 400 : la requête est à corriger. */
27
+ export declare class InvalidRequestError extends ApiError {
28
+ }
29
+ /** 401 : identifiant, mot de passe ou clé refusés. */
30
+ export declare class AuthenticationError extends ApiError {
31
+ }
32
+ /** 402 : solde insuffisant, le compte débité est à recharger. */
33
+ export declare class InsufficientBalanceError extends ApiError {
34
+ }
35
+ /** 403 : opération interdite à ce compte. */
36
+ export declare class PermissionError extends ApiError {
37
+ }
38
+ /** 404 : ressource introuvable. */
39
+ export declare class NotFoundError extends ApiError {
40
+ }
41
+ /** 409 : conflit, par exemple un groupe non vide ou une clé d'idempotence réutilisée. */
42
+ export declare class ConflictError extends ApiError {
43
+ }
44
+ /** 429 : débit dépassé, voir `retryAfter`. */
45
+ export declare class RateLimitError extends ApiError {
46
+ }
47
+ /** 501 : fonction déclarée au contrat mais pas encore servie. */
48
+ export declare class NotImplementedError extends ApiError {
49
+ }
50
+ /** 5xx : panne côté API. */
51
+ export declare class ServerError extends ApiError {
52
+ }
53
+ /**
54
+ * Coupure réseau ou délai dépassé. L'appel a pu aboutir : rejouez avec
55
+ * `idempotencyKey`, jamais avec une nouvelle clé.
56
+ */
57
+ export declare class ConnectionError extends FasterMessageError {
58
+ idempotencyKey: string | null;
59
+ }
@@ -0,0 +1,62 @@
1
+ /** Toute erreur levée par le SDK. */
2
+ export class FasterMessageError extends Error {
3
+ constructor(message, options) {
4
+ super(message, options);
5
+ this.name = new.target.name;
6
+ }
7
+ }
8
+ /**
9
+ * Refus de l'API. Testez `code`, qui est stable : `message` est un libellé en
10
+ * anglais, susceptible d'être reformulé.
11
+ */
12
+ export class ApiError extends FasterMessageError {
13
+ status;
14
+ code;
15
+ type;
16
+ param;
17
+ requestId;
18
+ retryAfter;
19
+ constructor(message, details) {
20
+ super(message);
21
+ this.status = details.status;
22
+ this.code = details.code;
23
+ this.type = details.type ?? '';
24
+ this.param = details.param ?? null;
25
+ this.requestId = details.requestId ?? null;
26
+ this.retryAfter = details.retryAfter ?? null;
27
+ }
28
+ }
29
+ /** 400 : la requête est à corriger. */
30
+ export class InvalidRequestError extends ApiError {
31
+ }
32
+ /** 401 : identifiant, mot de passe ou clé refusés. */
33
+ export class AuthenticationError extends ApiError {
34
+ }
35
+ /** 402 : solde insuffisant, le compte débité est à recharger. */
36
+ export class InsufficientBalanceError extends ApiError {
37
+ }
38
+ /** 403 : opération interdite à ce compte. */
39
+ export class PermissionError extends ApiError {
40
+ }
41
+ /** 404 : ressource introuvable. */
42
+ export class NotFoundError extends ApiError {
43
+ }
44
+ /** 409 : conflit, par exemple un groupe non vide ou une clé d'idempotence réutilisée. */
45
+ export class ConflictError extends ApiError {
46
+ }
47
+ /** 429 : débit dépassé, voir `retryAfter`. */
48
+ export class RateLimitError extends ApiError {
49
+ }
50
+ /** 501 : fonction déclarée au contrat mais pas encore servie. */
51
+ export class NotImplementedError extends ApiError {
52
+ }
53
+ /** 5xx : panne côté API. */
54
+ export class ServerError extends ApiError {
55
+ }
56
+ /**
57
+ * Coupure réseau ou délai dépassé. L'appel a pu aboutir : rejouez avec
58
+ * `idempotencyKey`, jamais avec une nouvelle clé.
59
+ */
60
+ export class ConnectionError extends FasterMessageError {
61
+ idempotencyKey = null;
62
+ }