@xenterprises/fastify-xsignwell 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +60 -0
- package/README.md +137 -302
- package/index.d.ts +164 -0
- package/package.json +2 -2
- package/src/apiRequest.js +49 -0
- package/src/services/bulkSend.js +67 -94
- package/src/services/documents.js +118 -105
- package/src/services/templates.js +64 -95
- package/src/services/webhooks.js +49 -83
- package/src/xSignwell.js +20 -27
- package/.gitlab-ci.yml +0 -45
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenterprises/fastify-xsignwell",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Fastify plugin for SignWell document signing API integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/xSignwell.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"api"
|
|
22
22
|
],
|
|
23
23
|
"author": "X Enterprises",
|
|
24
|
-
"license": "
|
|
24
|
+
"license": "UNLICENSED",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"fastify-plugin": "^5.0.1"
|
|
27
27
|
},
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared API request helper for SignWell services.
|
|
3
|
+
*
|
|
4
|
+
* @param {import('fastify').FastifyInstance} fastify - Fastify instance (for logging)
|
|
5
|
+
* @param {Object} config - Plugin configuration
|
|
6
|
+
* @param {string} endpoint - API endpoint path
|
|
7
|
+
* @param {Object} [options] - Fetch options
|
|
8
|
+
* @returns {Promise<Object>} Parsed API response
|
|
9
|
+
*/
|
|
10
|
+
export async function apiRequest(fastify, config, endpoint, options = {}) {
|
|
11
|
+
const url = `${config.baseUrl}${endpoint}`;
|
|
12
|
+
const headers = {
|
|
13
|
+
"X-Api-Key": config.apiKey,
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
...options.headers,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
let response;
|
|
19
|
+
try {
|
|
20
|
+
response = await fetch(url, { ...options, headers });
|
|
21
|
+
} catch (err) {
|
|
22
|
+
throw new Error(`[xSignwell] Network error calling ${endpoint}: ${err.message}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
const errorText = await response.text();
|
|
27
|
+
let errorData;
|
|
28
|
+
try {
|
|
29
|
+
errorData = JSON.parse(errorText);
|
|
30
|
+
} catch {
|
|
31
|
+
errorData = { message: errorText };
|
|
32
|
+
}
|
|
33
|
+
fastify.log.error(
|
|
34
|
+
{ endpoint, status: response.status, error: errorData },
|
|
35
|
+
"[xSignwell] API error"
|
|
36
|
+
);
|
|
37
|
+
const err = new Error(
|
|
38
|
+
`[xSignwell] ${errorData.message || `API error: ${response.status}`}`
|
|
39
|
+
);
|
|
40
|
+
err.statusCode = response.status;
|
|
41
|
+
err.signwellError = errorData;
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const text = await response.text();
|
|
46
|
+
if (!text) return { success: true };
|
|
47
|
+
|
|
48
|
+
return JSON.parse(text);
|
|
49
|
+
}
|
package/src/services/bulkSend.js
CHANGED
|
@@ -6,100 +6,67 @@
|
|
|
6
6
|
* @see https://developers.signwell.com/reference/get_api-v1-bulk-sends-id
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { apiRequest } from "../apiRequest.js";
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param {import('fastify').FastifyInstance} fastify - Fastify instance
|
|
13
|
-
* @param {Object} config - Plugin configuration
|
|
12
|
+
* @param {import('fastify').FastifyInstance} fastify
|
|
13
|
+
* @param {Object} config
|
|
14
14
|
*/
|
|
15
15
|
export async function setupBulkSend(fastify, config) {
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Make an API request to SignWell
|
|
20
|
-
* @param {string} endpoint - API endpoint
|
|
21
|
-
* @param {Object} options - Fetch options
|
|
22
|
-
* @returns {Promise<Object>} API response
|
|
23
|
-
*/
|
|
24
|
-
async function apiRequest(endpoint, options = {}) {
|
|
25
|
-
const url = `${baseUrl}${endpoint}`;
|
|
26
|
-
const headers = {
|
|
27
|
-
"X-Api-Key": apiKey,
|
|
28
|
-
"Content-Type": "application/json",
|
|
29
|
-
...options.headers,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const response = await fetch(url, {
|
|
33
|
-
...options,
|
|
34
|
-
headers,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
if (!response.ok) {
|
|
38
|
-
const errorText = await response.text();
|
|
39
|
-
let errorData;
|
|
40
|
-
try {
|
|
41
|
-
errorData = JSON.parse(errorText);
|
|
42
|
-
} catch {
|
|
43
|
-
errorData = { message: errorText };
|
|
44
|
-
}
|
|
45
|
-
fastify.log.error({ endpoint, status: response.status, error: errorData }, "SignWell API error");
|
|
46
|
-
throw new Error(errorData.message || `SignWell API error: ${response.status}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const text = await response.text();
|
|
50
|
-
if (!text) return { success: true };
|
|
16
|
+
const { testMode } = config;
|
|
51
17
|
|
|
52
|
-
|
|
18
|
+
function req(endpoint, options) {
|
|
19
|
+
return apiRequest(fastify, config, endpoint, options);
|
|
53
20
|
}
|
|
54
21
|
|
|
55
22
|
/**
|
|
56
23
|
* Get a bulk send by ID
|
|
57
|
-
* @param {string} bulkSendId
|
|
58
|
-
* @returns {Promise<Object>}
|
|
24
|
+
* @param {string} bulkSendId
|
|
25
|
+
* @returns {Promise<Object>}
|
|
59
26
|
*/
|
|
60
27
|
async function get(bulkSendId) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
28
|
+
if (!bulkSendId || typeof bulkSendId !== "string") {
|
|
29
|
+
throw new Error("[xSignwell] bulkSend.get: bulkSendId (string) is required");
|
|
30
|
+
}
|
|
31
|
+
return req(`/bulk_sends/${bulkSendId}`, { method: "GET" });
|
|
64
32
|
}
|
|
65
33
|
|
|
66
34
|
/**
|
|
67
35
|
* List all bulk sends
|
|
68
|
-
* @param {Object} [params]
|
|
69
|
-
* @param {number} [params.page]
|
|
70
|
-
* @param {number} [params.limit]
|
|
71
|
-
* @returns {Promise<Object>}
|
|
36
|
+
* @param {Object} [params]
|
|
37
|
+
* @param {number} [params.page]
|
|
38
|
+
* @param {number} [params.limit]
|
|
39
|
+
* @returns {Promise<Object>}
|
|
72
40
|
*/
|
|
73
41
|
async function list(params = {}) {
|
|
74
|
-
const
|
|
75
|
-
if (params.page)
|
|
76
|
-
if (params.limit)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const endpoint = `/bulk_sends${queryString ? `?${queryString}` : ""}`;
|
|
80
|
-
|
|
81
|
-
return apiRequest(endpoint, {
|
|
82
|
-
method: "GET",
|
|
83
|
-
});
|
|
42
|
+
const qp = new URLSearchParams();
|
|
43
|
+
if (params.page) qp.set("page", params.page);
|
|
44
|
+
if (params.limit) qp.set("limit", params.limit);
|
|
45
|
+
const qs = qp.toString();
|
|
46
|
+
return req(`/bulk_sends${qs ? `?${qs}` : ""}`, { method: "GET" });
|
|
84
47
|
}
|
|
85
48
|
|
|
86
49
|
/**
|
|
87
50
|
* Create a bulk send
|
|
88
|
-
* @param {Object} params
|
|
89
|
-
* @param {string} params.templateId - Template ID
|
|
90
|
-
* @param {Array<Object>} params.recipients -
|
|
51
|
+
* @param {Object} params
|
|
52
|
+
* @param {string} params.templateId - Template ID
|
|
53
|
+
* @param {Array<Object>} params.recipients - Recipient data rows
|
|
91
54
|
* @param {string} [params.subject] - Email subject
|
|
92
55
|
* @param {string} [params.message] - Email message
|
|
93
|
-
* @returns {Promise<Object>}
|
|
56
|
+
* @returns {Promise<Object>}
|
|
94
57
|
*/
|
|
95
58
|
async function create(params) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
if (!params || typeof params !== "object") {
|
|
60
|
+
throw new Error("[xSignwell] bulkSend.create: params object is required");
|
|
61
|
+
}
|
|
62
|
+
if (!params.templateId || typeof params.templateId !== "string") {
|
|
63
|
+
throw new Error("[xSignwell] bulkSend.create: templateId (string) is required");
|
|
64
|
+
}
|
|
65
|
+
if (!Array.isArray(params.recipients) || params.recipients.length === 0) {
|
|
66
|
+
throw new Error("[xSignwell] bulkSend.create: recipients (non-empty array) is required");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const { templateId, recipients, subject, message, ...rest } = params;
|
|
103
70
|
|
|
104
71
|
const body = {
|
|
105
72
|
document_template_id: templateId,
|
|
@@ -111,31 +78,40 @@ export async function setupBulkSend(fastify, config) {
|
|
|
111
78
|
if (subject) body.subject = subject;
|
|
112
79
|
if (message) body.message = message;
|
|
113
80
|
|
|
114
|
-
return
|
|
81
|
+
return req("/bulk_sends", {
|
|
115
82
|
method: "POST",
|
|
116
83
|
body: JSON.stringify(body),
|
|
117
84
|
});
|
|
118
85
|
}
|
|
119
86
|
|
|
120
87
|
/**
|
|
121
|
-
* Get CSV template for bulk send
|
|
122
|
-
* @param {string} templateId
|
|
123
|
-
* @returns {Promise<Object>}
|
|
88
|
+
* Get CSV template for a bulk send
|
|
89
|
+
* @param {string} templateId
|
|
90
|
+
* @returns {Promise<Object>}
|
|
124
91
|
*/
|
|
125
92
|
async function getCsvTemplate(templateId) {
|
|
126
|
-
|
|
93
|
+
if (!templateId || typeof templateId !== "string") {
|
|
94
|
+
throw new Error("[xSignwell] bulkSend.getCsvTemplate: templateId (string) is required");
|
|
95
|
+
}
|
|
96
|
+
return req(`/bulk_sends/csv_template?document_template_id=${templateId}`, {
|
|
127
97
|
method: "GET",
|
|
128
98
|
});
|
|
129
99
|
}
|
|
130
100
|
|
|
131
101
|
/**
|
|
132
102
|
* Validate CSV for bulk send
|
|
133
|
-
* @param {string} templateId
|
|
134
|
-
* @param {string} csvContent
|
|
135
|
-
* @returns {Promise<Object>}
|
|
103
|
+
* @param {string} templateId
|
|
104
|
+
* @param {string} csvContent
|
|
105
|
+
* @returns {Promise<Object>}
|
|
136
106
|
*/
|
|
137
107
|
async function validateCsv(templateId, csvContent) {
|
|
138
|
-
|
|
108
|
+
if (!templateId || typeof templateId !== "string") {
|
|
109
|
+
throw new Error("[xSignwell] bulkSend.validateCsv: templateId (string) is required");
|
|
110
|
+
}
|
|
111
|
+
if (!csvContent || typeof csvContent !== "string") {
|
|
112
|
+
throw new Error("[xSignwell] bulkSend.validateCsv: csvContent (string) is required");
|
|
113
|
+
}
|
|
114
|
+
return req("/bulk_sends/validate_csv", {
|
|
139
115
|
method: "POST",
|
|
140
116
|
body: JSON.stringify({
|
|
141
117
|
document_template_id: templateId,
|
|
@@ -146,26 +122,23 @@ export async function setupBulkSend(fastify, config) {
|
|
|
146
122
|
|
|
147
123
|
/**
|
|
148
124
|
* Get documents from a bulk send
|
|
149
|
-
* @param {string} bulkSendId
|
|
150
|
-
* @param {Object} [params]
|
|
151
|
-
* @
|
|
152
|
-
* @param {number} [params.limit] - Items per page
|
|
153
|
-
* @returns {Promise<Object>} List of documents
|
|
125
|
+
* @param {string} bulkSendId
|
|
126
|
+
* @param {Object} [params]
|
|
127
|
+
* @returns {Promise<Object>}
|
|
154
128
|
*/
|
|
155
129
|
async function getDocuments(bulkSendId, params = {}) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return
|
|
130
|
+
if (!bulkSendId || typeof bulkSendId !== "string") {
|
|
131
|
+
throw new Error("[xSignwell] bulkSend.getDocuments: bulkSendId (string) is required");
|
|
132
|
+
}
|
|
133
|
+
const qp = new URLSearchParams();
|
|
134
|
+
if (params.page) qp.set("page", params.page);
|
|
135
|
+
if (params.limit) qp.set("limit", params.limit);
|
|
136
|
+
const qs = qp.toString();
|
|
137
|
+
return req(`/bulk_sends/${bulkSendId}/documents${qs ? `?${qs}` : ""}`, {
|
|
164
138
|
method: "GET",
|
|
165
139
|
});
|
|
166
140
|
}
|
|
167
141
|
|
|
168
|
-
// Add bulk send service to xsignwell namespace
|
|
169
142
|
fastify.xsignwell.bulkSend = {
|
|
170
143
|
get,
|
|
171
144
|
list,
|
|
@@ -175,5 +148,5 @@ export async function setupBulkSend(fastify, config) {
|
|
|
175
148
|
getDocuments,
|
|
176
149
|
};
|
|
177
150
|
|
|
178
|
-
|
|
151
|
+
fastify.log.info("[xSignwell] Bulk Send service initialized");
|
|
179
152
|
}
|
|
@@ -6,76 +6,49 @@
|
|
|
6
6
|
* @see https://developers.signwell.com/reference/post_api-v1-documents
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { apiRequest } from "../apiRequest.js";
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param {import('fastify').FastifyInstance} fastify - Fastify instance
|
|
13
|
-
* @param {Object} config - Plugin configuration
|
|
12
|
+
* @param {import('fastify').FastifyInstance} fastify
|
|
13
|
+
* @param {Object} config
|
|
14
14
|
*/
|
|
15
15
|
export async function setupDocuments(fastify, config) {
|
|
16
|
-
const {
|
|
16
|
+
const { testMode } = config;
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* @param {string} endpoint - API endpoint
|
|
21
|
-
* @param {Object} options - Fetch options
|
|
22
|
-
* @returns {Promise<Object>} API response
|
|
23
|
-
*/
|
|
24
|
-
async function apiRequest(endpoint, options = {}) {
|
|
25
|
-
const url = `${baseUrl}${endpoint}`;
|
|
26
|
-
const headers = {
|
|
27
|
-
"X-Api-Key": apiKey,
|
|
28
|
-
"Content-Type": "application/json",
|
|
29
|
-
...options.headers,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const response = await fetch(url, {
|
|
33
|
-
...options,
|
|
34
|
-
headers,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
if (!response.ok) {
|
|
38
|
-
const errorText = await response.text();
|
|
39
|
-
let errorData;
|
|
40
|
-
try {
|
|
41
|
-
errorData = JSON.parse(errorText);
|
|
42
|
-
} catch {
|
|
43
|
-
errorData = { message: errorText };
|
|
44
|
-
}
|
|
45
|
-
fastify.log.error({ endpoint, status: response.status, error: errorData }, "SignWell API error");
|
|
46
|
-
throw new Error(errorData.message || `SignWell API error: ${response.status}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Handle empty responses (like DELETE)
|
|
50
|
-
const text = await response.text();
|
|
51
|
-
if (!text) return { success: true };
|
|
52
|
-
|
|
53
|
-
return JSON.parse(text);
|
|
18
|
+
function req(endpoint, options) {
|
|
19
|
+
return apiRequest(fastify, config, endpoint, options);
|
|
54
20
|
}
|
|
55
21
|
|
|
56
22
|
/**
|
|
57
23
|
* Create a new document for signing
|
|
58
|
-
* @param {Object} params
|
|
24
|
+
* @param {Object} params
|
|
59
25
|
* @param {string} params.name - Document name
|
|
60
|
-
* @param {Array<Object>} params.recipients -
|
|
61
|
-
* @param {Array<Object>} [params.files] - Files
|
|
62
|
-
* @param {boolean} [params.draft] - Create as draft
|
|
63
|
-
* @param {boolean} [params.testMode] - Use test mode
|
|
26
|
+
* @param {Array<Object>} params.recipients - Recipients list
|
|
27
|
+
* @param {Array<Object>} [params.files] - Files (base64 or URL)
|
|
28
|
+
* @param {boolean} [params.draft] - Create as draft
|
|
64
29
|
* @param {string} [params.subject] - Email subject
|
|
65
30
|
* @param {string} [params.message] - Email message
|
|
66
31
|
* @param {Object} [params.metadata] - Custom metadata
|
|
67
|
-
* @returns {Promise<Object>}
|
|
32
|
+
* @returns {Promise<Object>}
|
|
68
33
|
*/
|
|
69
34
|
async function create(params) {
|
|
35
|
+
if (!params || typeof params !== "object") {
|
|
36
|
+
throw new Error("[xSignwell] documents.create: params object is required");
|
|
37
|
+
}
|
|
38
|
+
if (!params.name || typeof params.name !== "string") {
|
|
39
|
+
throw new Error("[xSignwell] documents.create: name (string) is required");
|
|
40
|
+
}
|
|
41
|
+
if (!Array.isArray(params.recipients) || params.recipients.length === 0) {
|
|
42
|
+
throw new Error("[xSignwell] documents.create: recipients (non-empty array) is required");
|
|
43
|
+
}
|
|
44
|
+
for (const r of params.recipients) {
|
|
45
|
+
if (!r.email) {
|
|
46
|
+
throw new Error("[xSignwell] documents.create: each recipient must have an email");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
70
50
|
const {
|
|
71
|
-
name,
|
|
72
|
-
recipients,
|
|
73
|
-
files,
|
|
74
|
-
draft = false,
|
|
75
|
-
subject,
|
|
76
|
-
message,
|
|
77
|
-
metadata,
|
|
78
|
-
...rest
|
|
51
|
+
name, recipients, files, draft = false, subject, message, metadata, ...rest
|
|
79
52
|
} = params;
|
|
80
53
|
|
|
81
54
|
const body = {
|
|
@@ -104,7 +77,7 @@ export async function setupDocuments(fastify, config) {
|
|
|
104
77
|
if (message) body.message = message;
|
|
105
78
|
if (metadata) body.metadata = metadata;
|
|
106
79
|
|
|
107
|
-
return
|
|
80
|
+
return req("/documents", {
|
|
108
81
|
method: "POST",
|
|
109
82
|
body: JSON.stringify(body),
|
|
110
83
|
});
|
|
@@ -112,25 +85,23 @@ export async function setupDocuments(fastify, config) {
|
|
|
112
85
|
|
|
113
86
|
/**
|
|
114
87
|
* Create a document from a template
|
|
115
|
-
* @param {string} templateId
|
|
116
|
-
* @param {Object} params
|
|
117
|
-
* @
|
|
118
|
-
* @param {Object} [params.fields] - Field values to pre-fill
|
|
119
|
-
* @param {boolean} [params.draft] - Create as draft
|
|
120
|
-
* @param {string} [params.subject] - Email subject
|
|
121
|
-
* @param {string} [params.message] - Email message
|
|
122
|
-
* @param {Object} [params.metadata] - Custom metadata
|
|
123
|
-
* @returns {Promise<Object>} Created document
|
|
88
|
+
* @param {string} templateId
|
|
89
|
+
* @param {Object} params
|
|
90
|
+
* @returns {Promise<Object>}
|
|
124
91
|
*/
|
|
125
92
|
async function createFromTemplate(templateId, params) {
|
|
93
|
+
if (!templateId || typeof templateId !== "string") {
|
|
94
|
+
throw new Error("[xSignwell] documents.createFromTemplate: templateId (string) is required");
|
|
95
|
+
}
|
|
96
|
+
if (!params || typeof params !== "object") {
|
|
97
|
+
throw new Error("[xSignwell] documents.createFromTemplate: params object is required");
|
|
98
|
+
}
|
|
99
|
+
if (!Array.isArray(params.recipients) || params.recipients.length === 0) {
|
|
100
|
+
throw new Error("[xSignwell] documents.createFromTemplate: recipients (non-empty array) is required");
|
|
101
|
+
}
|
|
102
|
+
|
|
126
103
|
const {
|
|
127
|
-
recipients,
|
|
128
|
-
fields,
|
|
129
|
-
draft = false,
|
|
130
|
-
subject,
|
|
131
|
-
message,
|
|
132
|
-
metadata,
|
|
133
|
-
...rest
|
|
104
|
+
recipients, fields, draft = false, subject, message, metadata, ...rest
|
|
134
105
|
} = params;
|
|
135
106
|
|
|
136
107
|
const body = {
|
|
@@ -151,7 +122,7 @@ export async function setupDocuments(fastify, config) {
|
|
|
151
122
|
if (message) body.message = message;
|
|
152
123
|
if (metadata) body.metadata = metadata;
|
|
153
124
|
|
|
154
|
-
return
|
|
125
|
+
return req(`/document_templates/${templateId}/documents`, {
|
|
155
126
|
method: "POST",
|
|
156
127
|
body: JSON.stringify(body),
|
|
157
128
|
});
|
|
@@ -159,23 +130,42 @@ export async function setupDocuments(fastify, config) {
|
|
|
159
130
|
|
|
160
131
|
/**
|
|
161
132
|
* Get a document by ID
|
|
162
|
-
* @param {string} documentId
|
|
163
|
-
* @returns {Promise<Object>}
|
|
133
|
+
* @param {string} documentId
|
|
134
|
+
* @returns {Promise<Object>}
|
|
164
135
|
*/
|
|
165
136
|
async function get(documentId) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
137
|
+
if (!documentId || typeof documentId !== "string") {
|
|
138
|
+
throw new Error("[xSignwell] documents.get: documentId (string) is required");
|
|
139
|
+
}
|
|
140
|
+
return req(`/documents/${documentId}`, { method: "GET" });
|
|
169
141
|
}
|
|
170
142
|
|
|
171
143
|
/**
|
|
172
|
-
*
|
|
173
|
-
* @param {
|
|
174
|
-
* @param {
|
|
175
|
-
* @
|
|
144
|
+
* List documents
|
|
145
|
+
* @param {Object} [params]
|
|
146
|
+
* @param {number} [params.page]
|
|
147
|
+
* @param {number} [params.limit]
|
|
148
|
+
* @returns {Promise<Object>}
|
|
149
|
+
*/
|
|
150
|
+
async function list(params = {}) {
|
|
151
|
+
const qp = new URLSearchParams();
|
|
152
|
+
if (params.page) qp.set("page", params.page);
|
|
153
|
+
if (params.limit) qp.set("limit", params.limit);
|
|
154
|
+
const qs = qp.toString();
|
|
155
|
+
return req(`/documents${qs ? `?${qs}` : ""}`, { method: "GET" });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Send a document
|
|
160
|
+
* @param {string} documentId
|
|
161
|
+
* @param {Object} [params]
|
|
162
|
+
* @returns {Promise<Object>}
|
|
176
163
|
*/
|
|
177
164
|
async function send(documentId, params = {}) {
|
|
178
|
-
|
|
165
|
+
if (!documentId || typeof documentId !== "string") {
|
|
166
|
+
throw new Error("[xSignwell] documents.send: documentId (string) is required");
|
|
167
|
+
}
|
|
168
|
+
return req(`/documents/${documentId}/send`, {
|
|
179
169
|
method: "POST",
|
|
180
170
|
body: JSON.stringify(params),
|
|
181
171
|
});
|
|
@@ -183,49 +173,59 @@ export async function setupDocuments(fastify, config) {
|
|
|
183
173
|
|
|
184
174
|
/**
|
|
185
175
|
* Send a reminder to recipients who haven't signed
|
|
186
|
-
* @param {string} documentId
|
|
187
|
-
* @returns {Promise<Object>}
|
|
176
|
+
* @param {string} documentId
|
|
177
|
+
* @returns {Promise<Object>}
|
|
188
178
|
*/
|
|
189
179
|
async function remind(documentId) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
180
|
+
if (!documentId || typeof documentId !== "string") {
|
|
181
|
+
throw new Error("[xSignwell] documents.remind: documentId (string) is required");
|
|
182
|
+
}
|
|
183
|
+
return req(`/documents/${documentId}/remind`, { method: "POST" });
|
|
193
184
|
}
|
|
194
185
|
|
|
195
186
|
/**
|
|
196
187
|
* Delete a document
|
|
197
|
-
* @param {string} documentId
|
|
198
|
-
* @returns {Promise<Object>}
|
|
188
|
+
* @param {string} documentId
|
|
189
|
+
* @returns {Promise<Object>}
|
|
199
190
|
*/
|
|
200
191
|
async function remove(documentId) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
192
|
+
if (!documentId || typeof documentId !== "string") {
|
|
193
|
+
throw new Error("[xSignwell] documents.remove: documentId (string) is required");
|
|
194
|
+
}
|
|
195
|
+
return req(`/documents/${documentId}`, { method: "DELETE" });
|
|
204
196
|
}
|
|
205
197
|
|
|
206
198
|
/**
|
|
207
199
|
* Download the completed PDF
|
|
208
|
-
* @param {string} documentId
|
|
209
|
-
* @returns {Promise<Object>}
|
|
200
|
+
* @param {string} documentId
|
|
201
|
+
* @returns {Promise<Object>}
|
|
210
202
|
*/
|
|
211
203
|
async function getCompletedPdf(documentId) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
204
|
+
if (!documentId || typeof documentId !== "string") {
|
|
205
|
+
throw new Error("[xSignwell] documents.getCompletedPdf: documentId (string) is required");
|
|
206
|
+
}
|
|
207
|
+
return req(`/documents/${documentId}/completed_pdf`, { method: "GET" });
|
|
215
208
|
}
|
|
216
209
|
|
|
217
210
|
/**
|
|
218
211
|
* Get signing URL for embedded signing
|
|
219
|
-
* @param {string} documentId
|
|
220
|
-
* @param {string} recipientId
|
|
221
|
-
* @returns {Promise<Object>}
|
|
212
|
+
* @param {string} documentId
|
|
213
|
+
* @param {string} recipientId
|
|
214
|
+
* @returns {Promise<Object>}
|
|
222
215
|
*/
|
|
223
216
|
async function getEmbeddedSigningUrl(documentId, recipientId) {
|
|
217
|
+
if (!documentId || typeof documentId !== "string") {
|
|
218
|
+
throw new Error("[xSignwell] documents.getEmbeddedSigningUrl: documentId (string) is required");
|
|
219
|
+
}
|
|
220
|
+
if (!recipientId || typeof recipientId !== "string") {
|
|
221
|
+
throw new Error("[xSignwell] documents.getEmbeddedSigningUrl: recipientId (string) is required");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
224
|
const document = await get(documentId);
|
|
225
225
|
const recipient = document.recipients?.find((r) => r.id === recipientId);
|
|
226
226
|
|
|
227
227
|
if (!recipient) {
|
|
228
|
-
throw new Error(`Recipient ${recipientId} not found in document`);
|
|
228
|
+
throw new Error(`[xSignwell] Recipient ${recipientId} not found in document ${documentId}`);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
return {
|
|
@@ -234,18 +234,31 @@ export async function setupDocuments(fastify, config) {
|
|
|
234
234
|
};
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Get audit trail for a completed document
|
|
239
|
+
* @param {string} documentId
|
|
240
|
+
* @returns {Promise<Object>}
|
|
241
|
+
*/
|
|
242
|
+
async function getAuditTrail(documentId) {
|
|
243
|
+
if (!documentId || typeof documentId !== "string") {
|
|
244
|
+
throw new Error("[xSignwell] documents.getAuditTrail: documentId (string) is required");
|
|
245
|
+
}
|
|
246
|
+
return req(`/documents/${documentId}/audit_trail`, { method: "GET" });
|
|
247
|
+
}
|
|
248
|
+
|
|
238
249
|
fastify.xsignwell.documents = {
|
|
239
250
|
create,
|
|
240
251
|
createFromTemplate,
|
|
241
252
|
get,
|
|
253
|
+
list,
|
|
242
254
|
send,
|
|
243
255
|
remind,
|
|
244
256
|
remove,
|
|
245
|
-
delete: remove,
|
|
257
|
+
delete: remove,
|
|
246
258
|
getCompletedPdf,
|
|
247
259
|
getEmbeddedSigningUrl,
|
|
260
|
+
getAuditTrail,
|
|
248
261
|
};
|
|
249
262
|
|
|
250
|
-
|
|
263
|
+
fastify.log.info("[xSignwell] Documents service initialized");
|
|
251
264
|
}
|