@assinafy/sdk 1.4.0 → 1.5.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/README.md +75 -12
- package/dist/index.d.mts +209 -35
- package/dist/index.d.ts +209 -35
- package/dist/index.js +229 -74
- package/dist/index.mjs +228 -74
- package/package.json +11 -8
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
AssinafyClient: () => AssinafyClient,
|
|
36
36
|
AssinafyError: () => AssinafyError,
|
|
37
37
|
AuthenticationResource: () => AuthenticationResource,
|
|
38
|
+
DEFAULT_WEBHOOK_EVENTS: () => DEFAULT_WEBHOOK_EVENTS,
|
|
38
39
|
DocumentResource: () => DocumentResource,
|
|
39
40
|
FieldsResource: () => FieldsResource,
|
|
40
41
|
NetworkError: () => NetworkError,
|
|
@@ -139,9 +140,40 @@ function cleanParams(params) {
|
|
|
139
140
|
return out;
|
|
140
141
|
}
|
|
141
142
|
|
|
142
|
-
// src/
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
// src/support/retry.ts
|
|
144
|
+
function header(headers, name) {
|
|
145
|
+
if (!headers) return void 0;
|
|
146
|
+
const lower = name.toLowerCase();
|
|
147
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
148
|
+
if (key.toLowerCase() === lower && value != null) {
|
|
149
|
+
return Array.isArray(value) ? String(value[0]) : String(value);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
function retryDelayFromHeaders(headers) {
|
|
155
|
+
const retryAfter = header(headers, "retry-after");
|
|
156
|
+
if (retryAfter !== void 0) {
|
|
157
|
+
const seconds = Number(retryAfter);
|
|
158
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
159
|
+
const date = Date.parse(retryAfter);
|
|
160
|
+
if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
|
|
161
|
+
}
|
|
162
|
+
const reset = header(headers, "x-rate-limit-reset");
|
|
163
|
+
if (reset !== void 0) {
|
|
164
|
+
const seconds = Number(reset);
|
|
165
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
166
|
+
}
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
function backoffMs(attempt) {
|
|
170
|
+
return Math.min(1e3 * 2 ** Math.max(0, attempt - 1), 8e3);
|
|
171
|
+
}
|
|
172
|
+
function nextRetryDelayMs(headers, attempt, maxDelayMs = 3e4) {
|
|
173
|
+
const hinted = retryDelayFromHeaders(headers);
|
|
174
|
+
if (hinted !== void 0) return Math.min(hinted, maxDelayMs);
|
|
175
|
+
return Math.min(backoffMs(attempt), maxDelayMs);
|
|
176
|
+
}
|
|
145
177
|
|
|
146
178
|
// src/resources/base.ts
|
|
147
179
|
var BaseResource = class {
|
|
@@ -246,8 +278,49 @@ function toInt(value) {
|
|
|
246
278
|
return Number.isFinite(n) ? n : void 0;
|
|
247
279
|
}
|
|
248
280
|
|
|
249
|
-
// src/resources/
|
|
281
|
+
// src/resources/upload.ts
|
|
282
|
+
var import_node_fs = require("fs");
|
|
283
|
+
var import_node_path = __toESM(require("path"));
|
|
250
284
|
var MAX_UPLOAD_BYTES = 25 * 1024 * 1024;
|
|
285
|
+
async function loadSource(source) {
|
|
286
|
+
if ("buffer" in source) {
|
|
287
|
+
if (!source.fileName) {
|
|
288
|
+
throw new ValidationError("fileName is required when uploading a Buffer");
|
|
289
|
+
}
|
|
290
|
+
return { buffer: source.buffer, fileName: source.fileName };
|
|
291
|
+
}
|
|
292
|
+
if (!source.filePath) {
|
|
293
|
+
throw new ValidationError("filePath is required");
|
|
294
|
+
}
|
|
295
|
+
const buffer = await import_node_fs.promises.readFile(source.filePath);
|
|
296
|
+
return { buffer, fileName: source.fileName ?? import_node_path.default.basename(source.filePath) };
|
|
297
|
+
}
|
|
298
|
+
function validateUpload(buffer, fileName) {
|
|
299
|
+
if (!buffer || buffer.byteLength === 0) {
|
|
300
|
+
throw new ValidationError("File buffer is empty", { fileName });
|
|
301
|
+
}
|
|
302
|
+
if (!fileName.toLowerCase().endsWith(".pdf")) {
|
|
303
|
+
throw new ValidationError("Only PDF files are supported", { fileName });
|
|
304
|
+
}
|
|
305
|
+
if (buffer.byteLength > MAX_UPLOAD_BYTES) {
|
|
306
|
+
throw new ValidationError("File size exceeds maximum allowed (25MB)", {
|
|
307
|
+
fileSize: buffer.byteLength,
|
|
308
|
+
maxSize: MAX_UPLOAD_BYTES
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function buildUploadForm(buffer, fileName, options = {}) {
|
|
313
|
+
const form = new FormData();
|
|
314
|
+
const view = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
315
|
+
form.append("file", new Blob([view], { type: "application/pdf" }), fileName);
|
|
316
|
+
form.append("name", options.name ?? fileName);
|
|
317
|
+
if (options.metadata) {
|
|
318
|
+
form.append("metadata", JSON.stringify(options.metadata));
|
|
319
|
+
}
|
|
320
|
+
return form;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/resources/documents.ts
|
|
251
324
|
var READY_STATUSES = /* @__PURE__ */ new Set([
|
|
252
325
|
"metadata_ready",
|
|
253
326
|
"pending_signature",
|
|
@@ -273,7 +346,9 @@ var DocumentResource = class extends BaseResource {
|
|
|
273
346
|
const { buffer, fileName } = await loadSource(source);
|
|
274
347
|
validateUpload(buffer, fileName);
|
|
275
348
|
const accountId = this.accountId(options.accountId);
|
|
276
|
-
const
|
|
349
|
+
const formOptions = {};
|
|
350
|
+
if (options.metadata !== void 0) formOptions.metadata = options.metadata;
|
|
351
|
+
const form = buildUploadForm(buffer, fileName, formOptions);
|
|
277
352
|
this.logger.info("Uploading document", { fileName, size: buffer.byteLength });
|
|
278
353
|
const document = await this.call(
|
|
279
354
|
"Document upload failed",
|
|
@@ -449,7 +524,12 @@ var DocumentResource = class extends BaseResource {
|
|
|
449
524
|
() => this.http.post(`/accounts/${accId}/templates/${tmplId}/documents`, body)
|
|
450
525
|
);
|
|
451
526
|
}
|
|
452
|
-
/**
|
|
527
|
+
/**
|
|
528
|
+
* Estimate the credit cost of creating a document from a template.
|
|
529
|
+
*
|
|
530
|
+
* @returns an {@link ICostEstimate}: `total_credits`, balances, and a
|
|
531
|
+
* per-line `breakdown` of what the operation would consume.
|
|
532
|
+
*/
|
|
453
533
|
async estimateCostFromTemplate(templateId, signers, accountId) {
|
|
454
534
|
const tmplId = this.requireId(templateId, "Template ID");
|
|
455
535
|
const accId = this.accountId(accountId);
|
|
@@ -518,43 +598,6 @@ var DocumentResource = class extends BaseResource {
|
|
|
518
598
|
return { signed, total, pending, percentage };
|
|
519
599
|
}
|
|
520
600
|
};
|
|
521
|
-
async function loadSource(source) {
|
|
522
|
-
if ("buffer" in source) {
|
|
523
|
-
if (!source.fileName) {
|
|
524
|
-
throw new ValidationError("fileName is required when uploading a Buffer");
|
|
525
|
-
}
|
|
526
|
-
return { buffer: source.buffer, fileName: source.fileName };
|
|
527
|
-
}
|
|
528
|
-
if (!source.filePath) {
|
|
529
|
-
throw new ValidationError("filePath is required");
|
|
530
|
-
}
|
|
531
|
-
const buffer = await import_node_fs.promises.readFile(source.filePath);
|
|
532
|
-
return { buffer, fileName: source.fileName ?? import_node_path.default.basename(source.filePath) };
|
|
533
|
-
}
|
|
534
|
-
function validateUpload(buffer, fileName) {
|
|
535
|
-
if (!buffer || buffer.byteLength === 0) {
|
|
536
|
-
throw new ValidationError("File buffer is empty", { fileName });
|
|
537
|
-
}
|
|
538
|
-
if (!fileName.toLowerCase().endsWith(".pdf")) {
|
|
539
|
-
throw new ValidationError("Only PDF files are supported", { fileName });
|
|
540
|
-
}
|
|
541
|
-
if (buffer.byteLength > MAX_UPLOAD_BYTES) {
|
|
542
|
-
throw new ValidationError("File size exceeds maximum allowed (25MB)", {
|
|
543
|
-
fileSize: buffer.byteLength,
|
|
544
|
-
maxSize: MAX_UPLOAD_BYTES
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
function buildUploadForm(buffer, fileName, metadata) {
|
|
549
|
-
const form = new FormData();
|
|
550
|
-
const view = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
551
|
-
form.append("file", new Blob([view], { type: "application/pdf" }), fileName);
|
|
552
|
-
form.append("name", fileName);
|
|
553
|
-
if (metadata) {
|
|
554
|
-
form.append("metadata", JSON.stringify(metadata));
|
|
555
|
-
}
|
|
556
|
-
return form;
|
|
557
|
-
}
|
|
558
601
|
function sleep(ms) {
|
|
559
602
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
560
603
|
}
|
|
@@ -770,7 +813,15 @@ var AssignmentResource = class extends BaseResource {
|
|
|
770
813
|
() => this.http.post(`/documents/${docId}/assignments`, body)
|
|
771
814
|
);
|
|
772
815
|
}
|
|
773
|
-
/**
|
|
816
|
+
/**
|
|
817
|
+
* Estimate the cost (in credits/documents) of creating the assignment.
|
|
818
|
+
*
|
|
819
|
+
* Signer entries may omit `id` and supply only `verification_method` /
|
|
820
|
+
* `notification_methods` when only the channel mix matters for the estimate.
|
|
821
|
+
*
|
|
822
|
+
* @returns an {@link ICostEstimate} with `total_credits`, balances, and a
|
|
823
|
+
* line-item `breakdown`.
|
|
824
|
+
*/
|
|
774
825
|
async estimateCost(documentId, payload) {
|
|
775
826
|
const docId = this.requireId(documentId, "Document ID");
|
|
776
827
|
return this.call(
|
|
@@ -805,7 +856,11 @@ var AssignmentResource = class extends BaseResource {
|
|
|
805
856
|
() => this.http.put(`/documents/${docId}/assignments/${asgId}/signers/${sid}/resend`)
|
|
806
857
|
);
|
|
807
858
|
}
|
|
808
|
-
/**
|
|
859
|
+
/**
|
|
860
|
+
* Estimate the cost of resending a signer notification.
|
|
861
|
+
*
|
|
862
|
+
* @returns an {@link IResendCostEstimate} (`total`, `breakdown`, balances).
|
|
863
|
+
*/
|
|
809
864
|
async estimateResendCost(documentId, assignmentId, signerId) {
|
|
810
865
|
const docId = this.requireId(documentId, "Document ID");
|
|
811
866
|
const asgId = this.requireId(assignmentId, "Assignment ID");
|
|
@@ -829,26 +884,10 @@ var AssignmentResource = class extends BaseResource {
|
|
|
829
884
|
() => this.http.get(`/documents/${docId}/assignments/${asgId}/whatsapp-notifications`)
|
|
830
885
|
);
|
|
831
886
|
}
|
|
832
|
-
/**
|
|
833
|
-
* Cancel a signature request. This endpoint is not listed in the public
|
|
834
|
-
* Swagger but is exposed by the platform.
|
|
835
|
-
*/
|
|
836
|
-
async cancel(documentId, reason, accountId) {
|
|
837
|
-
const docId = this.requireId(documentId, "Document ID");
|
|
838
|
-
const accId = this.accountId(accountId);
|
|
839
|
-
this.logger.info("Cancelling signature request", { documentId: docId, reason });
|
|
840
|
-
return this.call(
|
|
841
|
-
"Failed to cancel signature request",
|
|
842
|
-
() => this.http.post(
|
|
843
|
-
`/accounts/${accId}/signature-requests/${docId}/cancel`,
|
|
844
|
-
{ document_id: docId, reason }
|
|
845
|
-
)
|
|
846
|
-
);
|
|
847
|
-
}
|
|
848
887
|
};
|
|
849
888
|
|
|
850
889
|
// src/resources/webhooks.ts
|
|
851
|
-
var
|
|
890
|
+
var DEFAULT_WEBHOOK_EVENTS = [
|
|
852
891
|
"document_ready",
|
|
853
892
|
"document_prepared",
|
|
854
893
|
"signer_signed_document",
|
|
@@ -856,7 +895,21 @@ var DEFAULT_EVENTS = [
|
|
|
856
895
|
"document_processing_failed"
|
|
857
896
|
];
|
|
858
897
|
var WebhookResource = class extends BaseResource {
|
|
859
|
-
/**
|
|
898
|
+
/**
|
|
899
|
+
* Register (or replace) the workspace's single webhook subscription
|
|
900
|
+
* (`PUT /accounts/{id}/webhooks/subscriptions`). There is exactly one
|
|
901
|
+
* subscription per workspace, keyed by URL.
|
|
902
|
+
*
|
|
903
|
+
* When `events` is omitted or empty, {@link DEFAULT_WEBHOOK_EVENTS} is used
|
|
904
|
+
* (`document_ready`, `document_prepared`, `signer_signed_document`,
|
|
905
|
+
* `signer_rejected_document`, `document_processing_failed`).
|
|
906
|
+
*
|
|
907
|
+
* @example
|
|
908
|
+
* ```ts
|
|
909
|
+
* await client.webhooks.register({ url: 'https://example.com/hook', email: 'ops@example.com' });
|
|
910
|
+
* // → { url, email, events: [...], is_active: true, updated_at: '2026-…' }
|
|
911
|
+
* ```
|
|
912
|
+
*/
|
|
860
913
|
async register(payload, accountId) {
|
|
861
914
|
if (!payload.url) throw new ValidationError("Webhook URL is required");
|
|
862
915
|
if (!payload.email) throw new ValidationError("Webhook email is required");
|
|
@@ -864,7 +917,7 @@ var WebhookResource = class extends BaseResource {
|
|
|
864
917
|
const body = {
|
|
865
918
|
url: payload.url,
|
|
866
919
|
email: payload.email,
|
|
867
|
-
events: payload.events && payload.events.length > 0 ? payload.events :
|
|
920
|
+
events: payload.events && payload.events.length > 0 ? payload.events : DEFAULT_WEBHOOK_EVENTS,
|
|
868
921
|
is_active: payload.is_active ?? true
|
|
869
922
|
};
|
|
870
923
|
this.logger.info("Registering webhook", { url: payload.url });
|
|
@@ -929,6 +982,46 @@ var WebhookResource = class extends BaseResource {
|
|
|
929
982
|
|
|
930
983
|
// src/resources/templates.ts
|
|
931
984
|
var TemplateResource = class extends BaseResource {
|
|
985
|
+
/**
|
|
986
|
+
* Create a template by uploading a PDF (`POST /accounts/{id}/templates`).
|
|
987
|
+
*
|
|
988
|
+
* The template is created in `Uploaded` status and transitions to `Ready`
|
|
989
|
+
* once the platform finishes processing its pages. Configure roles/fields
|
|
990
|
+
* afterwards in the Assinafy editor.
|
|
991
|
+
*
|
|
992
|
+
* @example
|
|
993
|
+
* ```ts
|
|
994
|
+
* const tmpl = await client.templates.create(
|
|
995
|
+
* { filePath: './nda.pdf' },
|
|
996
|
+
* { name: 'NDA template' },
|
|
997
|
+
* );
|
|
998
|
+
* // → { resource: 'template', id, name, status: 'Uploaded',
|
|
999
|
+
* // roles: [{ id, name: 'TemplateEditor', assignment_type: 'Editor' }],
|
|
1000
|
+
* // pages: [], tags: [], created_at, updated_at }
|
|
1001
|
+
* ```
|
|
1002
|
+
*/
|
|
1003
|
+
async create(source, options = {}) {
|
|
1004
|
+
const { buffer, fileName } = await loadSource(source);
|
|
1005
|
+
validateUpload(buffer, fileName);
|
|
1006
|
+
const id = this.accountId(options.accountId);
|
|
1007
|
+
const formOptions = {};
|
|
1008
|
+
if (options.name !== void 0) formOptions.name = options.name;
|
|
1009
|
+
const form = buildUploadForm(buffer, fileName, formOptions);
|
|
1010
|
+
this.logger.info("Creating template", { fileName, size: buffer.byteLength });
|
|
1011
|
+
const template = await this.call(
|
|
1012
|
+
"Failed to create template",
|
|
1013
|
+
() => this.http.post(`/accounts/${id}/templates`, form, {
|
|
1014
|
+
headers: { "Content-Type": "multipart/form-data" }
|
|
1015
|
+
})
|
|
1016
|
+
);
|
|
1017
|
+
if (!template?.id) {
|
|
1018
|
+
throw new ValidationError("Template upload succeeded but no template ID was returned", {
|
|
1019
|
+
response: template
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
this.logger.info("Template created", { templateId: template.id });
|
|
1023
|
+
return template;
|
|
1024
|
+
}
|
|
932
1025
|
/** List templates for the workspace. */
|
|
933
1026
|
async list(params = {}, accountId) {
|
|
934
1027
|
const id = this.accountId(accountId);
|
|
@@ -938,11 +1031,10 @@ var TemplateResource = class extends BaseResource {
|
|
|
938
1031
|
);
|
|
939
1032
|
}
|
|
940
1033
|
/**
|
|
941
|
-
* Get a template by ID.
|
|
1034
|
+
* Get a template by ID (`GET /accounts/{id}/templates/{template_id}`).
|
|
942
1035
|
*
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
* by the official PHP SDK.
|
|
1036
|
+
* Unlike the list endpoint, the single-template response includes `pages`
|
|
1037
|
+
* (with per-page `download_url`) and `default_document_tags`.
|
|
946
1038
|
*/
|
|
947
1039
|
async get(templateId, accountId) {
|
|
948
1040
|
const id = this.accountId(accountId);
|
|
@@ -953,9 +1045,40 @@ var TemplateResource = class extends BaseResource {
|
|
|
953
1045
|
);
|
|
954
1046
|
}
|
|
955
1047
|
/**
|
|
956
|
-
* `
|
|
957
|
-
*
|
|
958
|
-
*
|
|
1048
|
+
* Update a template's `name` and/or default `message`
|
|
1049
|
+
* (`PUT /accounts/{id}/templates/{template_id}`). Returns the updated template.
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* ```ts
|
|
1053
|
+
* await client.templates.update(templateId, { name: 'NDA v2', message: 'Please sign' });
|
|
1054
|
+
* ```
|
|
1055
|
+
*/
|
|
1056
|
+
async update(templateId, payload, accountId) {
|
|
1057
|
+
const id = this.accountId(accountId);
|
|
1058
|
+
const tmplId = this.requireId(templateId, "Template ID");
|
|
1059
|
+
return this.call(
|
|
1060
|
+
"Failed to update template",
|
|
1061
|
+
() => this.http.put(
|
|
1062
|
+
`/accounts/${id}/templates/${tmplId}`,
|
|
1063
|
+
cleanParams(payload)
|
|
1064
|
+
)
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
/** Delete a template (`DELETE /accounts/{id}/templates/{template_id}`). */
|
|
1068
|
+
async delete(templateId, accountId) {
|
|
1069
|
+
const id = this.accountId(accountId);
|
|
1070
|
+
const tmplId = this.requireId(templateId, "Template ID");
|
|
1071
|
+
return this.callVoid(
|
|
1072
|
+
"Failed to delete template",
|
|
1073
|
+
() => this.http.delete(`/accounts/${id}/templates/${tmplId}`)
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Download a template page as a JPEG
|
|
1078
|
+
* (`GET /accounts/{id}/templates/{template_id}/pages/{page_id}/download`).
|
|
1079
|
+
*
|
|
1080
|
+
* Used by template editors to render page thumbnails on the client. The
|
|
1081
|
+
* matching `download_url` is also returned on each `template.pages[]` entry.
|
|
959
1082
|
*/
|
|
960
1083
|
async downloadPage(templateId, pageId, accountId) {
|
|
961
1084
|
const id = this.accountId(accountId);
|
|
@@ -1323,7 +1446,12 @@ var SignerDocumentsResource = class extends BaseResource {
|
|
|
1323
1446
|
})
|
|
1324
1447
|
);
|
|
1325
1448
|
}
|
|
1326
|
-
/**
|
|
1449
|
+
/**
|
|
1450
|
+
* `GET /sign?signer-access-code=…` — fetch the assignment as the signer sees it.
|
|
1451
|
+
*
|
|
1452
|
+
* @param hasAcceptedTerms maps to the `has_accepted_terms` query param
|
|
1453
|
+
* (server default `false`); pass `true` once the signer has accepted terms.
|
|
1454
|
+
*/
|
|
1327
1455
|
async getAssignment(signerAccessCode, hasAcceptedTerms) {
|
|
1328
1456
|
const code = this.requireId(signerAccessCode, "signer-access-code");
|
|
1329
1457
|
return this.call(
|
|
@@ -1353,8 +1481,8 @@ var SignerDocumentsResource = class extends BaseResource {
|
|
|
1353
1481
|
}
|
|
1354
1482
|
/**
|
|
1355
1483
|
* `PUT /documents/{documentId}/assignments/{assignmentId}/reject?signer-access-code=…`
|
|
1356
|
-
* — signer-side decline. (
|
|
1357
|
-
* workspace
|
|
1484
|
+
* — signer-side decline. (The workspace-side equivalent is to delete the
|
|
1485
|
+
* document via `documents.delete`; there is no workspace "cancel" endpoint.)
|
|
1358
1486
|
*/
|
|
1359
1487
|
async decline(documentId, assignmentId, signerAccessCode, declineReason) {
|
|
1360
1488
|
const did = this.requireId(documentId, "Document ID");
|
|
@@ -1445,6 +1573,10 @@ var AssinafyClient = class _AssinafyClient {
|
|
|
1445
1573
|
timeout: options.timeout ?? 3e4,
|
|
1446
1574
|
headers
|
|
1447
1575
|
});
|
|
1576
|
+
const maxRetries = options.maxRetries ?? 2;
|
|
1577
|
+
if (maxRetries > 0) {
|
|
1578
|
+
installRateLimitRetry(this.axiosInstance, maxRetries, this.logger);
|
|
1579
|
+
}
|
|
1448
1580
|
this.documents = new DocumentResource(this.axiosInstance, this.defaultAccountId, this.logger);
|
|
1449
1581
|
this.signers = new SignerResource(this.axiosInstance, this.defaultAccountId, this.logger);
|
|
1450
1582
|
this.workspaces = new WorkspaceResource(this.axiosInstance, void 0, this.logger);
|
|
@@ -1483,6 +1615,7 @@ var AssinafyClient = class _AssinafyClient {
|
|
|
1483
1615
|
if (baseUrl !== void 0) opts.baseUrl = baseUrl;
|
|
1484
1616
|
if (webhookSecret !== void 0) opts.webhookSecret = webhookSecret;
|
|
1485
1617
|
if (config.timeout !== void 0) opts.timeout = config.timeout;
|
|
1618
|
+
if (config.maxRetries !== void 0) opts.maxRetries = config.maxRetries;
|
|
1486
1619
|
if (config.logger !== void 0) opts.logger = config.logger;
|
|
1487
1620
|
return new _AssinafyClient(opts);
|
|
1488
1621
|
}
|
|
@@ -1542,6 +1675,27 @@ var AssinafyClient = class _AssinafyClient {
|
|
|
1542
1675
|
function normaliseBaseUrl(raw) {
|
|
1543
1676
|
return raw.endsWith("/") ? raw.slice(0, -1) : raw;
|
|
1544
1677
|
}
|
|
1678
|
+
function installRateLimitRetry(http, maxRetries, logger) {
|
|
1679
|
+
http.interceptors.response.use(
|
|
1680
|
+
(response) => response,
|
|
1681
|
+
async (error) => {
|
|
1682
|
+
if (!import_axios2.default.isAxiosError(error) || error.response?.status !== 429 || !error.config) {
|
|
1683
|
+
throw error;
|
|
1684
|
+
}
|
|
1685
|
+
const config = error.config;
|
|
1686
|
+
const attempt = (config._retryCount ?? 0) + 1;
|
|
1687
|
+
if (attempt > maxRetries) throw error;
|
|
1688
|
+
config._retryCount = attempt;
|
|
1689
|
+
const delayMs = nextRetryDelayMs(
|
|
1690
|
+
error.response.headers,
|
|
1691
|
+
attempt
|
|
1692
|
+
);
|
|
1693
|
+
logger.warn("Rate limited (429); retrying after delay", { attempt, maxRetries, delayMs });
|
|
1694
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1695
|
+
return http(config);
|
|
1696
|
+
}
|
|
1697
|
+
);
|
|
1698
|
+
}
|
|
1545
1699
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1546
1700
|
0 && (module.exports = {
|
|
1547
1701
|
ApiError,
|
|
@@ -1549,6 +1703,7 @@ function normaliseBaseUrl(raw) {
|
|
|
1549
1703
|
AssinafyClient,
|
|
1550
1704
|
AssinafyError,
|
|
1551
1705
|
AuthenticationResource,
|
|
1706
|
+
DEFAULT_WEBHOOK_EVENTS,
|
|
1552
1707
|
DocumentResource,
|
|
1553
1708
|
FieldsResource,
|
|
1554
1709
|
NetworkError,
|