@xenterprises/fastify-xsignwell 1.1.0 → 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/test/xSignwell.test.js +0 -539
|
@@ -6,89 +6,51 @@
|
|
|
6
6
|
* @see https://developers.signwell.com/reference/get_api-v1-document-templates-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 setupTemplates(fastify, config) {
|
|
16
|
-
|
|
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 };
|
|
51
|
-
|
|
52
|
-
return JSON.parse(text);
|
|
16
|
+
function req(endpoint, options) {
|
|
17
|
+
return apiRequest(fastify, config, endpoint, options);
|
|
53
18
|
}
|
|
54
19
|
|
|
55
20
|
/**
|
|
56
21
|
* Get a template by ID
|
|
57
|
-
* @param {string} templateId
|
|
58
|
-
* @returns {Promise<Object>}
|
|
22
|
+
* @param {string} templateId
|
|
23
|
+
* @returns {Promise<Object>}
|
|
59
24
|
*/
|
|
60
25
|
async function get(templateId) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
26
|
+
if (!templateId || typeof templateId !== "string") {
|
|
27
|
+
throw new Error("[xSignwell] templates.get: templateId (string) is required");
|
|
28
|
+
}
|
|
29
|
+
return req(`/document_templates/${templateId}`, { method: "GET" });
|
|
64
30
|
}
|
|
65
31
|
|
|
66
32
|
/**
|
|
67
33
|
* Create a new template
|
|
68
|
-
* @param {Object} params
|
|
34
|
+
* @param {Object} params
|
|
69
35
|
* @param {string} params.name - Template name
|
|
70
|
-
* @param {Array<Object>} [params.files] - Files
|
|
36
|
+
* @param {Array<Object>} [params.files] - Files (base64 or URL)
|
|
71
37
|
* @param {Array<Object>} [params.recipients] - Recipient placeholders
|
|
72
38
|
* @param {Array<Object>} [params.fields] - Field definitions
|
|
73
39
|
* @param {string} [params.subject] - Default email subject
|
|
74
40
|
* @param {string} [params.message] - Default email message
|
|
75
|
-
* @returns {Promise<Object>}
|
|
41
|
+
* @returns {Promise<Object>}
|
|
76
42
|
*/
|
|
77
43
|
async function create(params) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const body = {
|
|
89
|
-
name,
|
|
90
|
-
...rest,
|
|
91
|
-
};
|
|
44
|
+
if (!params || typeof params !== "object") {
|
|
45
|
+
throw new Error("[xSignwell] templates.create: params object is required");
|
|
46
|
+
}
|
|
47
|
+
if (!params.name || typeof params.name !== "string") {
|
|
48
|
+
throw new Error("[xSignwell] templates.create: name (string) is required");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { name, files, recipients, fields, subject, message, ...rest } = params;
|
|
52
|
+
|
|
53
|
+
const body = { name, ...rest };
|
|
92
54
|
|
|
93
55
|
if (files) {
|
|
94
56
|
body.files = files.map((f) => ({
|
|
@@ -110,7 +72,7 @@ export async function setupTemplates(fastify, config) {
|
|
|
110
72
|
if (subject) body.subject = subject;
|
|
111
73
|
if (message) body.message = message;
|
|
112
74
|
|
|
113
|
-
return
|
|
75
|
+
return req("/document_templates", {
|
|
114
76
|
method: "POST",
|
|
115
77
|
body: JSON.stringify(body),
|
|
116
78
|
});
|
|
@@ -118,12 +80,18 @@ export async function setupTemplates(fastify, config) {
|
|
|
118
80
|
|
|
119
81
|
/**
|
|
120
82
|
* Update an existing template
|
|
121
|
-
* @param {string} templateId
|
|
122
|
-
* @param {Object} params
|
|
123
|
-
* @returns {Promise<Object>}
|
|
83
|
+
* @param {string} templateId
|
|
84
|
+
* @param {Object} params
|
|
85
|
+
* @returns {Promise<Object>}
|
|
124
86
|
*/
|
|
125
87
|
async function update(templateId, params) {
|
|
126
|
-
|
|
88
|
+
if (!templateId || typeof templateId !== "string") {
|
|
89
|
+
throw new Error("[xSignwell] templates.update: templateId (string) is required");
|
|
90
|
+
}
|
|
91
|
+
if (!params || typeof params !== "object") {
|
|
92
|
+
throw new Error("[xSignwell] templates.update: params object is required");
|
|
93
|
+
}
|
|
94
|
+
return req(`/document_templates/${templateId}`, {
|
|
127
95
|
method: "PUT",
|
|
128
96
|
body: JSON.stringify(params),
|
|
129
97
|
});
|
|
@@ -131,66 +99,67 @@ export async function setupTemplates(fastify, config) {
|
|
|
131
99
|
|
|
132
100
|
/**
|
|
133
101
|
* Delete a template
|
|
134
|
-
* @param {string} templateId
|
|
135
|
-
* @returns {Promise<Object>}
|
|
102
|
+
* @param {string} templateId
|
|
103
|
+
* @returns {Promise<Object>}
|
|
136
104
|
*/
|
|
137
105
|
async function remove(templateId) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
106
|
+
if (!templateId || typeof templateId !== "string") {
|
|
107
|
+
throw new Error("[xSignwell] templates.remove: templateId (string) is required");
|
|
108
|
+
}
|
|
109
|
+
return req(`/document_templates/${templateId}`, { method: "DELETE" });
|
|
141
110
|
}
|
|
142
111
|
|
|
143
112
|
/**
|
|
144
113
|
* List all templates
|
|
145
|
-
* @param {Object} [params]
|
|
146
|
-
* @param {number} [params.page]
|
|
147
|
-
* @param {number} [params.limit]
|
|
148
|
-
* @returns {Promise<Object>}
|
|
114
|
+
* @param {Object} [params]
|
|
115
|
+
* @param {number} [params.page]
|
|
116
|
+
* @param {number} [params.limit]
|
|
117
|
+
* @returns {Promise<Object>}
|
|
149
118
|
*/
|
|
150
119
|
async function list(params = {}) {
|
|
151
|
-
const
|
|
152
|
-
if (params.page)
|
|
153
|
-
if (params.limit)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const endpoint = `/document_templates${queryString ? `?${queryString}` : ""}`;
|
|
157
|
-
|
|
158
|
-
return apiRequest(endpoint, {
|
|
159
|
-
method: "GET",
|
|
160
|
-
});
|
|
120
|
+
const qp = new URLSearchParams();
|
|
121
|
+
if (params.page) qp.set("page", params.page);
|
|
122
|
+
if (params.limit) qp.set("limit", params.limit);
|
|
123
|
+
const qs = qp.toString();
|
|
124
|
+
return req(`/document_templates${qs ? `?${qs}` : ""}`, { method: "GET" });
|
|
161
125
|
}
|
|
162
126
|
|
|
163
127
|
/**
|
|
164
|
-
* Get template fields
|
|
165
|
-
* @param {string} templateId
|
|
166
|
-
* @returns {Promise<Array>}
|
|
128
|
+
* Get template fields
|
|
129
|
+
* @param {string} templateId
|
|
130
|
+
* @returns {Promise<Array>}
|
|
167
131
|
*/
|
|
168
132
|
async function getFields(templateId) {
|
|
133
|
+
if (!templateId || typeof templateId !== "string") {
|
|
134
|
+
throw new Error("[xSignwell] templates.getFields: templateId (string) is required");
|
|
135
|
+
}
|
|
169
136
|
const template = await get(templateId);
|
|
170
137
|
return template.fields || [];
|
|
171
138
|
}
|
|
172
139
|
|
|
173
140
|
/**
|
|
174
141
|
* Get template recipients (placeholders)
|
|
175
|
-
* @param {string} templateId
|
|
176
|
-
* @returns {Promise<Array>}
|
|
142
|
+
* @param {string} templateId
|
|
143
|
+
* @returns {Promise<Array>}
|
|
177
144
|
*/
|
|
178
145
|
async function getRecipients(templateId) {
|
|
146
|
+
if (!templateId || typeof templateId !== "string") {
|
|
147
|
+
throw new Error("[xSignwell] templates.getRecipients: templateId (string) is required");
|
|
148
|
+
}
|
|
179
149
|
const template = await get(templateId);
|
|
180
150
|
return template.recipients || [];
|
|
181
151
|
}
|
|
182
152
|
|
|
183
|
-
// Add templates service to xsignwell namespace
|
|
184
153
|
fastify.xsignwell.templates = {
|
|
185
154
|
get,
|
|
186
155
|
create,
|
|
187
156
|
update,
|
|
188
157
|
remove,
|
|
189
|
-
delete: remove,
|
|
158
|
+
delete: remove,
|
|
190
159
|
list,
|
|
191
160
|
getFields,
|
|
192
161
|
getRecipients,
|
|
193
162
|
};
|
|
194
163
|
|
|
195
|
-
|
|
164
|
+
fastify.log.info("[xSignwell] Templates service initialized");
|
|
196
165
|
}
|
package/src/services/webhooks.js
CHANGED
|
@@ -6,80 +6,46 @@
|
|
|
6
6
|
* @see https://developers.signwell.com/reference/get_api-v1-hooks
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
10
|
+
import { apiRequest } from "../apiRequest.js";
|
|
11
|
+
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param {import('fastify').FastifyInstance} fastify - Fastify instance
|
|
13
|
-
* @param {Object} config - Plugin configuration
|
|
13
|
+
* @param {import('fastify').FastifyInstance} fastify
|
|
14
|
+
* @param {Object} config
|
|
14
15
|
*/
|
|
15
16
|
export async function setupWebhooks(fastify, config) {
|
|
16
|
-
|
|
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 };
|
|
51
|
-
|
|
52
|
-
return JSON.parse(text);
|
|
17
|
+
function req(endpoint, options) {
|
|
18
|
+
return apiRequest(fastify, config, endpoint, options);
|
|
53
19
|
}
|
|
54
20
|
|
|
55
21
|
/**
|
|
56
22
|
* List all webhooks
|
|
57
|
-
* @returns {Promise<Array>}
|
|
23
|
+
* @returns {Promise<Array>}
|
|
58
24
|
*/
|
|
59
25
|
async function list() {
|
|
60
|
-
return
|
|
61
|
-
method: "GET",
|
|
62
|
-
});
|
|
26
|
+
return req("/hooks", { method: "GET" });
|
|
63
27
|
}
|
|
64
28
|
|
|
65
29
|
/**
|
|
66
30
|
* Create a new webhook
|
|
67
|
-
* @param {Object} params
|
|
68
|
-
* @param {string} params.callbackUrl - URL to receive
|
|
31
|
+
* @param {Object} params
|
|
32
|
+
* @param {string} params.callbackUrl - URL to receive events
|
|
69
33
|
* @param {string} [params.event] - Event type to subscribe to
|
|
70
|
-
* @returns {Promise<Object>}
|
|
34
|
+
* @returns {Promise<Object>}
|
|
71
35
|
*/
|
|
72
36
|
async function create(params) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
37
|
+
if (!params || typeof params !== "object") {
|
|
38
|
+
throw new Error("[xSignwell] webhooks.create: params object is required");
|
|
39
|
+
}
|
|
40
|
+
if (!params.callbackUrl || typeof params.callbackUrl !== "string") {
|
|
41
|
+
throw new Error("[xSignwell] webhooks.create: callbackUrl (string) is required");
|
|
42
|
+
}
|
|
79
43
|
|
|
44
|
+
const { callbackUrl, event, ...rest } = params;
|
|
45
|
+
const body = { callback_url: callbackUrl, ...rest };
|
|
80
46
|
if (event) body.event = event;
|
|
81
47
|
|
|
82
|
-
return
|
|
48
|
+
return req("/hooks", {
|
|
83
49
|
method: "POST",
|
|
84
50
|
body: JSON.stringify(body),
|
|
85
51
|
});
|
|
@@ -87,18 +53,17 @@ export async function setupWebhooks(fastify, config) {
|
|
|
87
53
|
|
|
88
54
|
/**
|
|
89
55
|
* Delete a webhook
|
|
90
|
-
* @param {string} webhookId
|
|
91
|
-
* @returns {Promise<Object>}
|
|
56
|
+
* @param {string} webhookId
|
|
57
|
+
* @returns {Promise<Object>}
|
|
92
58
|
*/
|
|
93
59
|
async function remove(webhookId) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
60
|
+
if (!webhookId || typeof webhookId !== "string") {
|
|
61
|
+
throw new Error("[xSignwell] webhooks.remove: webhookId (string) is required");
|
|
62
|
+
}
|
|
63
|
+
return req(`/hooks/${webhookId}`, { method: "DELETE" });
|
|
97
64
|
}
|
|
98
65
|
|
|
99
|
-
/**
|
|
100
|
-
* Webhook event types
|
|
101
|
-
*/
|
|
66
|
+
/** Webhook event type constants */
|
|
102
67
|
const events = {
|
|
103
68
|
DOCUMENT_COMPLETED: "document.completed",
|
|
104
69
|
DOCUMENT_SENT: "document.sent",
|
|
@@ -114,39 +79,41 @@ export async function setupWebhooks(fastify, config) {
|
|
|
114
79
|
};
|
|
115
80
|
|
|
116
81
|
/**
|
|
117
|
-
* Verify webhook signature (
|
|
82
|
+
* Verify webhook signature (HMAC-SHA256)
|
|
118
83
|
* @param {string} payload - Raw request body
|
|
119
84
|
* @param {string} signature - Signature header value
|
|
120
85
|
* @param {string} secret - Webhook secret
|
|
121
|
-
* @returns {boolean}
|
|
86
|
+
* @returns {boolean}
|
|
122
87
|
*/
|
|
123
88
|
function verifySignature(payload, signature, secret) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
89
|
+
if (!payload || typeof payload !== "string") {
|
|
90
|
+
throw new Error("[xSignwell] webhooks.verifySignature: payload (string) is required");
|
|
91
|
+
}
|
|
92
|
+
if (!signature || typeof signature !== "string") {
|
|
93
|
+
throw new Error("[xSignwell] webhooks.verifySignature: signature (string) is required");
|
|
94
|
+
}
|
|
95
|
+
if (!secret || typeof secret !== "string") {
|
|
96
|
+
throw new Error("[xSignwell] webhooks.verifySignature: secret (string) is required");
|
|
97
|
+
}
|
|
127
98
|
|
|
128
99
|
try {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
.createHmac("sha256", secret)
|
|
132
|
-
.update(payload)
|
|
133
|
-
.digest("hex");
|
|
134
|
-
return crypto.timingSafeEqual(
|
|
135
|
-
Buffer.from(signature),
|
|
136
|
-
Buffer.from(expectedSignature)
|
|
137
|
-
);
|
|
100
|
+
const expected = createHmac("sha256", secret).update(payload).digest("hex");
|
|
101
|
+
return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
138
102
|
} catch (error) {
|
|
139
|
-
fastify.log.error({ error }, "
|
|
103
|
+
fastify.log.error({ error: error.message }, "[xSignwell] Signature verification failed");
|
|
140
104
|
return false;
|
|
141
105
|
}
|
|
142
106
|
}
|
|
143
107
|
|
|
144
108
|
/**
|
|
145
109
|
* Parse webhook event payload
|
|
146
|
-
* @param {Object} payload
|
|
147
|
-
* @returns {Object}
|
|
110
|
+
* @param {Object} payload
|
|
111
|
+
* @returns {Object}
|
|
148
112
|
*/
|
|
149
113
|
function parseEvent(payload) {
|
|
114
|
+
if (!payload || typeof payload !== "object") {
|
|
115
|
+
throw new Error("[xSignwell] webhooks.parseEvent: payload (object) is required");
|
|
116
|
+
}
|
|
150
117
|
return {
|
|
151
118
|
event: payload.event || payload.type,
|
|
152
119
|
documentId: payload.document?.id || payload.document_id,
|
|
@@ -157,16 +124,15 @@ export async function setupWebhooks(fastify, config) {
|
|
|
157
124
|
};
|
|
158
125
|
}
|
|
159
126
|
|
|
160
|
-
// Add webhooks service to xsignwell namespace
|
|
161
127
|
fastify.xsignwell.webhooks = {
|
|
162
128
|
list,
|
|
163
129
|
create,
|
|
164
130
|
remove,
|
|
165
|
-
delete: remove,
|
|
131
|
+
delete: remove,
|
|
166
132
|
events,
|
|
167
133
|
verifySignature,
|
|
168
134
|
parseEvent,
|
|
169
135
|
};
|
|
170
136
|
|
|
171
|
-
|
|
137
|
+
fastify.log.info("[xSignwell] Webhooks service initialized");
|
|
172
138
|
}
|
package/src/xSignwell.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* xSignwell - SignWell Document Signing Integration
|
|
3
3
|
*
|
|
4
4
|
* A Fastify plugin for integrating with SignWell's e-signature API.
|
|
5
|
-
* Provides document creation, template management, and webhook handling.
|
|
5
|
+
* Provides document creation, template management, bulk sending, and webhook handling.
|
|
6
6
|
*
|
|
7
7
|
* @see https://developers.signwell.com/reference/getting-started-with-your-api-1
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import fp from "fastify-plugin";
|
|
11
|
+
import { apiRequest } from "./apiRequest.js";
|
|
11
12
|
import { setupDocuments } from "./services/documents.js";
|
|
12
13
|
import { setupTemplates } from "./services/templates.js";
|
|
13
14
|
import { setupWebhooks } from "./services/webhooks.js";
|
|
@@ -24,15 +25,23 @@ import { setupBulkSend } from "./services/bulkSend.js";
|
|
|
24
25
|
* @param {boolean} [options.active] - Enable/disable the plugin (default: true)
|
|
25
26
|
*/
|
|
26
27
|
async function xSignwell(fastify, options) {
|
|
27
|
-
// Check if plugin is disabled
|
|
28
28
|
if (options.active === false) {
|
|
29
|
-
|
|
29
|
+
fastify.log.info("[xSignwell] Plugin disabled");
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
// Validate required
|
|
33
|
+
// Validate required options
|
|
34
34
|
if (!options.apiKey) {
|
|
35
|
-
throw new Error("xSignwell
|
|
35
|
+
throw new Error("[xSignwell] apiKey is required");
|
|
36
|
+
}
|
|
37
|
+
if (typeof options.apiKey !== "string") {
|
|
38
|
+
throw new Error("[xSignwell] apiKey must be a string");
|
|
39
|
+
}
|
|
40
|
+
if (options.baseUrl !== undefined && typeof options.baseUrl !== "string") {
|
|
41
|
+
throw new Error("[xSignwell] baseUrl must be a string");
|
|
42
|
+
}
|
|
43
|
+
if (options.testMode !== undefined && typeof options.testMode !== "boolean") {
|
|
44
|
+
throw new Error("[xSignwell] testMode must be a boolean");
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
const config = {
|
|
@@ -41,10 +50,7 @@ async function xSignwell(fastify, options) {
|
|
|
41
50
|
testMode: options.testMode || false,
|
|
42
51
|
};
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
fastify.decorate("xsignwell", {
|
|
46
|
-
config,
|
|
47
|
-
});
|
|
53
|
+
fastify.decorate("xsignwell", { config });
|
|
48
54
|
|
|
49
55
|
// Setup services
|
|
50
56
|
await setupDocuments(fastify, config);
|
|
@@ -52,31 +58,18 @@ async function xSignwell(fastify, options) {
|
|
|
52
58
|
await setupWebhooks(fastify, config);
|
|
53
59
|
await setupBulkSend(fastify, config);
|
|
54
60
|
|
|
55
|
-
//
|
|
61
|
+
// Account info helper
|
|
56
62
|
fastify.xsignwell.me = async function () {
|
|
57
|
-
|
|
58
|
-
method: "GET",
|
|
59
|
-
headers: {
|
|
60
|
-
"X-Api-Key": config.apiKey,
|
|
61
|
-
"Content-Type": "application/json",
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
if (!response.ok) {
|
|
66
|
-
const error = await response.text();
|
|
67
|
-
fastify.log.error({ error }, "Failed to get SignWell account info");
|
|
68
|
-
throw new Error(`SignWell API error: ${response.status}`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return response.json();
|
|
63
|
+
return apiRequest(fastify, config, "/me", { method: "GET" });
|
|
72
64
|
};
|
|
73
65
|
|
|
74
|
-
|
|
66
|
+
fastify.log.info("[xSignwell] Document Signing Enabled");
|
|
75
67
|
if (config.testMode) {
|
|
76
|
-
|
|
68
|
+
fastify.log.info("[xSignwell] Running in TEST MODE");
|
|
77
69
|
}
|
|
78
70
|
}
|
|
79
71
|
|
|
80
72
|
export default fp(xSignwell, {
|
|
81
73
|
name: "xSignwell",
|
|
74
|
+
fastify: ">=5.0.0",
|
|
82
75
|
});
|
package/.gitlab-ci.yml
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# ============================================================================
|
|
2
|
-
# GitLab CI/CD Pipeline - xSignwell
|
|
3
|
-
# ============================================================================
|
|
4
|
-
# Runs tests on merge requests and commits to main/master
|
|
5
|
-
|
|
6
|
-
stages:
|
|
7
|
-
- test
|
|
8
|
-
|
|
9
|
-
variables:
|
|
10
|
-
NODE_ENV: test
|
|
11
|
-
|
|
12
|
-
# ============================================================================
|
|
13
|
-
# Shared Configuration
|
|
14
|
-
# ============================================================================
|
|
15
|
-
.shared_rules: &shared_rules
|
|
16
|
-
rules:
|
|
17
|
-
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
18
|
-
- if: '$CI_COMMIT_BRANCH == "main"'
|
|
19
|
-
- if: '$CI_COMMIT_BRANCH == "master"'
|
|
20
|
-
- if: '$CI_COMMIT_TAG'
|
|
21
|
-
|
|
22
|
-
# ============================================================================
|
|
23
|
-
# STAGE: TEST
|
|
24
|
-
# ============================================================================
|
|
25
|
-
test:
|
|
26
|
-
stage: test
|
|
27
|
-
image: node:20-alpine
|
|
28
|
-
<<: *shared_rules
|
|
29
|
-
|
|
30
|
-
cache:
|
|
31
|
-
key: ${CI_COMMIT_REF_SLUG}
|
|
32
|
-
paths:
|
|
33
|
-
- node_modules/
|
|
34
|
-
|
|
35
|
-
before_script:
|
|
36
|
-
- npm ci
|
|
37
|
-
|
|
38
|
-
script:
|
|
39
|
-
- echo "Running xSignwell tests..."
|
|
40
|
-
- npm test
|
|
41
|
-
- npm audit --audit-level=high || true
|
|
42
|
-
|
|
43
|
-
retry:
|
|
44
|
-
max: 2
|
|
45
|
-
when: runner_system_failure
|