@bubblelab/bubble-core 0.1.267 → 0.1.269
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bubble-bundle.d.ts +127 -127
- package/dist/bubbles/service-bubble/agi-inc.d.ts +20 -20
- package/dist/bubbles/service-bubble/ai-agent.d.ts +74 -74
- package/dist/bubbles/service-bubble/airtable.d.ts +76 -76
- package/dist/bubbles/service-bubble/apify/actors/app-rankings-scraper.d.ts +6 -6
- package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts +2 -2
- package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts +8 -8
- package/dist/bubbles/service-bubble/apify/actors/linkedin-jobs-scraper.d.ts +2 -2
- package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts +22 -22
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-detail.d.ts +38 -38
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts +52 -52
- package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.d.ts +6 -6
- package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.d.ts +12 -12
- package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.d.ts +12 -12
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts +132 -132
- package/dist/bubbles/service-bubble/apify/apify.d.ts +18 -18
- package/dist/bubbles/service-bubble/asana/asana.d.ts +1 -1
- package/dist/bubbles/service-bubble/asana/asana.schema.d.ts +1 -1
- package/dist/bubbles/service-bubble/ashby/ashby.d.ts +16 -16
- package/dist/bubbles/service-bubble/ashby/ashby.schema.d.ts +22 -22
- package/dist/bubbles/service-bubble/assembled/assembled.d.ts +6 -6
- package/dist/bubbles/service-bubble/assembled/assembled.schema.d.ts +6 -6
- package/dist/bubbles/service-bubble/attio/attio.d.ts +6 -6
- package/dist/bubbles/service-bubble/attio/attio.schema.d.ts +6 -6
- package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts +1 -1
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +1 -1
- package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts +4 -4
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts +8 -8
- package/dist/bubbles/service-bubble/discord/discord.d.ts +12 -12
- package/dist/bubbles/service-bubble/discord/discord.schema.d.ts +12 -12
- package/dist/bubbles/service-bubble/firecrawl.d.ts +330 -330
- package/dist/bubbles/service-bubble/followupboss.d.ts +4 -4
- package/dist/bubbles/service-bubble/github.d.ts +60 -60
- package/dist/bubbles/service-bubble/gmail.d.ts +164 -164
- package/dist/bubbles/service-bubble/google-calendar.d.ts +6 -6
- package/dist/bubbles/service-bubble/google-drive.d.ts +4 -4
- package/dist/bubbles/service-bubble/http.d.ts +6 -6
- package/dist/bubbles/service-bubble/hubspot/hubspot.d.ts +2 -2
- package/dist/bubbles/service-bubble/hubspot/hubspot.schema.d.ts +2 -2
- package/dist/bubbles/service-bubble/insforge-db.d.ts +8 -8
- package/dist/bubbles/service-bubble/jira/jira.d.ts +30 -30
- package/dist/bubbles/service-bubble/jira/jira.schema.d.ts +36 -36
- package/dist/bubbles/service-bubble/notion/notion.d.ts +168 -168
- package/dist/bubbles/service-bubble/notion/property-schemas.d.ts +16 -16
- package/dist/bubbles/service-bubble/postgresql.d.ts +8 -8
- package/dist/bubbles/service-bubble/posthog/posthog.d.ts +10 -10
- package/dist/bubbles/service-bubble/posthog/posthog.schema.d.ts +14 -14
- package/dist/bubbles/service-bubble/resend.d.ts +4 -4
- package/dist/bubbles/service-bubble/slack/slack.d.ts +388 -388
- package/dist/bubbles/service-bubble/snowflake/snowflake.d.ts +4 -4
- package/dist/bubbles/service-bubble/snowflake/snowflake.schema.d.ts +4 -4
- package/dist/bubbles/service-bubble/stripe/stripe.d.ts +24 -24
- package/dist/bubbles/service-bubble/stripe/stripe.schema.d.ts +28 -28
- package/dist/bubbles/service-bubble/xero/xero.d.ts +2 -2
- package/dist/bubbles/service-bubble/xero/xero.schema.d.ts +2 -2
- package/dist/bubbles/service-bubble/zendesk/zendesk.d.ts +20 -20
- package/dist/bubbles/service-bubble/zendesk/zendesk.schema.d.ts +20 -20
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.d.ts +6 -6
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +8 -8
- package/dist/bubbles/tool-bubble/app-rankings-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/chart-js-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +20 -20
- package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +384 -384
- package/dist/bubbles/tool-bubble/people-search-tool.d.ts +44 -44
- package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +10 -10
- package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/sql-query-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/tiktok-tool.d.ts +60 -60
- package/dist/bubbles/tool-bubble/twitter-tool.d.ts +134 -134
- package/dist/bubbles/tool-bubble/yc-scraper-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/youtube-tool.d.ts +20 -20
- package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +12 -12
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +8 -8
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +2 -2
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +34 -34
- package/dist/bubbles.json +1 -1
- package/package.json +2 -2
- package/dist/bubble-trigger/index.d.ts +0 -2
- package/dist/bubble-trigger/index.d.ts.map +0 -1
- package/dist/bubble-trigger/index.js +0 -2
- package/dist/bubble-trigger/index.js.map +0 -1
- package/dist/bubble-trigger/types.d.ts +0 -87
- package/dist/bubble-trigger/types.d.ts.map +0 -1
- package/dist/bubble-trigger/types.js +0 -14
- package/dist/bubble-trigger/types.js.map +0 -1
- package/dist/bubbles/service-bubble/docusign/docusign.d.ts +0 -1101
- package/dist/bubbles/service-bubble/docusign/docusign.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/docusign/docusign.js +0 -730
- package/dist/bubbles/service-bubble/docusign/docusign.js.map +0 -1
- package/dist/bubbles/service-bubble/docusign/docusign.schema.d.ts +0 -1035
- package/dist/bubbles/service-bubble/docusign/docusign.schema.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/docusign/docusign.schema.js +0 -304
- package/dist/bubbles/service-bubble/docusign/docusign.schema.js.map +0 -1
- package/dist/bubbles/service-bubble/docusign/index.d.ts +0 -4
- package/dist/bubbles/service-bubble/docusign/index.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/docusign/index.js +0 -3
- package/dist/bubbles/service-bubble/docusign/index.js.map +0 -1
- package/dist/bubbles/service-bubble/google-sheets.d.ts +0 -1811
- package/dist/bubbles/service-bubble/google-sheets.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/google-sheets.js +0 -904
- package/dist/bubbles/service-bubble/google-sheets.js.map +0 -1
- package/dist/bubbles/service-bubble/looker/index.d.ts +0 -3
- package/dist/bubbles/service-bubble/looker/index.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/looker/index.js +0 -3
- package/dist/bubbles/service-bubble/looker/index.js.map +0 -1
- package/dist/bubbles/service-bubble/looker/looker.d.ts +0 -768
- package/dist/bubbles/service-bubble/looker/looker.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/looker/looker.js +0 -319
- package/dist/bubbles/service-bubble/looker/looker.js.map +0 -1
- package/dist/bubbles/service-bubble/looker/looker.schema.d.ts +0 -735
- package/dist/bubbles/service-bubble/looker/looker.schema.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/looker/looker.schema.js +0 -264
- package/dist/bubbles/service-bubble/looker/looker.schema.js.map +0 -1
- package/dist/bubbles/service-bubble/pylon/index.d.ts +0 -3
- package/dist/bubbles/service-bubble/pylon/index.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/pylon/index.js +0 -3
- package/dist/bubbles/service-bubble/pylon/index.js.map +0 -1
- package/dist/bubbles/service-bubble/pylon/pylon.d.ts +0 -435
- package/dist/bubbles/service-bubble/pylon/pylon.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/pylon/pylon.js +0 -375
- package/dist/bubbles/service-bubble/pylon/pylon.js.map +0 -1
- package/dist/bubbles/service-bubble/pylon/pylon.schema.d.ts +0 -408
- package/dist/bubbles/service-bubble/pylon/pylon.schema.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/pylon/pylon.schema.js +0 -249
- package/dist/bubbles/service-bubble/pylon/pylon.schema.js.map +0 -1
- package/dist/bubbles/service-bubble/slack.d.ts +0 -5869
- package/dist/bubbles/service-bubble/slack.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/slack.js +0 -1536
- package/dist/bubbles/service-bubble/slack.js.map +0 -1
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.d.ts +0 -3
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.d.ts.map +0 -1
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.js +0 -3
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/index.js.map +0 -1
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts +0 -160
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts.map +0 -1
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.js +0 -706
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.js.map +0 -1
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts +0 -93
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts.map +0 -1
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.js +0 -50
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.js.map +0 -1
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.d.ts +0 -114
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.d.ts.map +0 -1
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js +0 -777
- package/dist/bubbles/workflow-bubble/bubbleflow-generator.workflow.js.map +0 -1
- package/dist/types/ai-models.d.ts +0 -4
- package/dist/types/ai-models.d.ts.map +0 -1
- package/dist/types/ai-models.js +0 -16
- package/dist/types/ai-models.js.map +0 -1
- package/dist/utils/param-helper.d.ts +0 -2
- package/dist/utils/param-helper.d.ts.map +0 -1
- package/dist/utils/param-helper.js +0 -5
- package/dist/utils/param-helper.js.map +0 -1
|
@@ -1,730 +0,0 @@
|
|
|
1
|
-
import { ServiceBubble } from '../../../types/service-bubble-class.js';
|
|
2
|
-
import { CredentialType, decodeCredentialPayload, } from '@bubblelab/shared-schemas';
|
|
3
|
-
import { DocuSignParamsSchema, DocuSignResultSchema, } from './docusign.schema.js';
|
|
4
|
-
/**
|
|
5
|
-
* DocuSign Service Bubble
|
|
6
|
-
*
|
|
7
|
-
* eSignature integration for managing document signing workflows.
|
|
8
|
-
*
|
|
9
|
-
* Features:
|
|
10
|
-
* - Create and send envelopes with documents and signers
|
|
11
|
-
* - Create envelopes from pre-built templates
|
|
12
|
-
* - Track envelope and recipient signing status
|
|
13
|
-
* - Configure automatic reminders and expiration
|
|
14
|
-
* - Download signed documents
|
|
15
|
-
* - Void and resend envelopes
|
|
16
|
-
*
|
|
17
|
-
* Use cases:
|
|
18
|
-
* - Automate agreement lifecycle (send, track, remind)
|
|
19
|
-
* - Savings account agreement workflows
|
|
20
|
-
* - Contract management and tracking
|
|
21
|
-
* - Bulk envelope status monitoring
|
|
22
|
-
*/
|
|
23
|
-
export class DocuSignBubble extends ServiceBubble {
|
|
24
|
-
static type = 'service';
|
|
25
|
-
static service = 'docusign';
|
|
26
|
-
static authType = 'oauth';
|
|
27
|
-
static bubbleName = 'docusign';
|
|
28
|
-
static schema = DocuSignParamsSchema;
|
|
29
|
-
static resultSchema = DocuSignResultSchema;
|
|
30
|
-
static shortDescription = 'DocuSign eSignature integration for document signing workflows';
|
|
31
|
-
static longDescription = `
|
|
32
|
-
DocuSign eSignature integration for managing document signing workflows.
|
|
33
|
-
|
|
34
|
-
Features:
|
|
35
|
-
- Create and send envelopes with documents and signers
|
|
36
|
-
- Create envelopes from pre-built templates with role mapping
|
|
37
|
-
- Track envelope and recipient signing status
|
|
38
|
-
- Configure automatic reminders and envelope expiration
|
|
39
|
-
- Download signed/completed documents
|
|
40
|
-
- Void in-progress envelopes and resend notifications
|
|
41
|
-
- List and search envelopes and templates
|
|
42
|
-
|
|
43
|
-
Use cases:
|
|
44
|
-
- Automate agreement lifecycle (generate, send, track, remind, escalate)
|
|
45
|
-
- Savings account agreement workflows
|
|
46
|
-
- Contract management and compliance tracking
|
|
47
|
-
- Bulk envelope status monitoring for CS agents
|
|
48
|
-
|
|
49
|
-
Security Features:
|
|
50
|
-
- OAuth 2.0 authentication with DocuSign
|
|
51
|
-
- Scoped access permissions
|
|
52
|
-
- Secure document handling
|
|
53
|
-
`;
|
|
54
|
-
static alias = 'docusign';
|
|
55
|
-
/**
|
|
56
|
-
* DocuSign credential format:
|
|
57
|
-
* Base64-encoded JSON: { accessToken, accountId, baseUri }
|
|
58
|
-
* The accountId identifies which DocuSign account to access.
|
|
59
|
-
* The baseUri is the region-specific API base URL.
|
|
60
|
-
*/
|
|
61
|
-
parseCredentials() {
|
|
62
|
-
const { credentials } = this.params;
|
|
63
|
-
if (!credentials || typeof credentials !== 'object') {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
const docusignCredRaw = credentials[CredentialType.DOCUSIGN_CRED];
|
|
67
|
-
if (!docusignCredRaw) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
try {
|
|
71
|
-
const parsed = decodeCredentialPayload(docusignCredRaw);
|
|
72
|
-
if (parsed.accessToken && parsed.accountId) {
|
|
73
|
-
return {
|
|
74
|
-
accessToken: parsed.accessToken,
|
|
75
|
-
accountId: parsed.accountId,
|
|
76
|
-
baseUri: parsed.baseUri
|
|
77
|
-
? `${parsed.baseUri}/restapi`
|
|
78
|
-
: 'https://demo.docusign.net/restapi',
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
// If decoding fails, treat the raw value as an access token
|
|
84
|
-
// In this case, we can't make API calls without accountId
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
constructor(params = {
|
|
89
|
-
operation: 'list_envelopes',
|
|
90
|
-
}, context) {
|
|
91
|
-
super(params, context);
|
|
92
|
-
}
|
|
93
|
-
async testCredential() {
|
|
94
|
-
const creds = this.parseCredentials();
|
|
95
|
-
if (!creds) {
|
|
96
|
-
throw new Error('DocuSign credentials are required');
|
|
97
|
-
}
|
|
98
|
-
// Test by calling userinfo endpoint
|
|
99
|
-
const response = await fetch('https://account-d.docusign.com/oauth/userinfo', {
|
|
100
|
-
headers: { Authorization: `Bearer ${creds.accessToken}` },
|
|
101
|
-
});
|
|
102
|
-
if (!response.ok) {
|
|
103
|
-
const text = await response.text();
|
|
104
|
-
throw new Error(`DocuSign token validation failed (${response.status}): ${text}`);
|
|
105
|
-
}
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
async makeDocuSignRequest(endpoint, method = 'GET', body) {
|
|
109
|
-
const creds = this.parseCredentials();
|
|
110
|
-
if (!creds) {
|
|
111
|
-
throw new Error('Invalid DocuSign credentials. Expected base64-encoded JSON with { accessToken, accountId, baseUri }.');
|
|
112
|
-
}
|
|
113
|
-
const url = `${creds.baseUri}/v2.1/accounts/${creds.accountId}${endpoint}`;
|
|
114
|
-
const headers = {
|
|
115
|
-
Authorization: `Bearer ${creds.accessToken}`,
|
|
116
|
-
'Content-Type': 'application/json',
|
|
117
|
-
};
|
|
118
|
-
const response = await fetch(url, {
|
|
119
|
-
method,
|
|
120
|
-
headers,
|
|
121
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
122
|
-
});
|
|
123
|
-
if (!response.ok) {
|
|
124
|
-
const errorText = await response.text();
|
|
125
|
-
let errorMessage;
|
|
126
|
-
try {
|
|
127
|
-
const errorJson = JSON.parse(errorText);
|
|
128
|
-
errorMessage = errorJson.message || errorJson.errorCode || errorText;
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
errorMessage = errorText;
|
|
132
|
-
}
|
|
133
|
-
throw new Error(`DocuSign API error (${response.status}): ${errorMessage}`);
|
|
134
|
-
}
|
|
135
|
-
// Some endpoints return no content (204)
|
|
136
|
-
if (response.status === 204) {
|
|
137
|
-
return {};
|
|
138
|
-
}
|
|
139
|
-
const contentType = response.headers.get('content-type') || '';
|
|
140
|
-
if (contentType.includes('application/json')) {
|
|
141
|
-
return response.json();
|
|
142
|
-
}
|
|
143
|
-
// For binary responses (document downloads)
|
|
144
|
-
const buffer = await response.arrayBuffer();
|
|
145
|
-
return Buffer.from(buffer).toString('base64');
|
|
146
|
-
}
|
|
147
|
-
async performAction(context) {
|
|
148
|
-
void context;
|
|
149
|
-
const { operation } = this.params;
|
|
150
|
-
try {
|
|
151
|
-
const result = await (async () => {
|
|
152
|
-
const parsedParams = this.params;
|
|
153
|
-
switch (operation) {
|
|
154
|
-
case 'create_envelope':
|
|
155
|
-
return await this.createEnvelope(parsedParams);
|
|
156
|
-
case 'create_envelope_from_template':
|
|
157
|
-
return await this.createEnvelopeFromTemplate(parsedParams);
|
|
158
|
-
case 'get_envelope':
|
|
159
|
-
return await this.getEnvelope(parsedParams);
|
|
160
|
-
case 'list_envelopes':
|
|
161
|
-
return await this.listEnvelopes(parsedParams);
|
|
162
|
-
case 'get_recipients':
|
|
163
|
-
return await this.getRecipients(parsedParams);
|
|
164
|
-
case 'list_templates':
|
|
165
|
-
return await this.listTemplates(parsedParams);
|
|
166
|
-
case 'download_document':
|
|
167
|
-
return await this.downloadDocument(parsedParams);
|
|
168
|
-
case 'void_envelope':
|
|
169
|
-
return await this.voidEnvelope(parsedParams);
|
|
170
|
-
case 'resend_envelope':
|
|
171
|
-
return await this.resendEnvelope(parsedParams);
|
|
172
|
-
case 'bulk_send_from_template':
|
|
173
|
-
return await this.bulkSendFromTemplate(parsedParams);
|
|
174
|
-
case 'get_signing_url':
|
|
175
|
-
return await this.getSigningUrl(parsedParams);
|
|
176
|
-
case 'correct_recipient':
|
|
177
|
-
return await this.correctRecipient(parsedParams);
|
|
178
|
-
default:
|
|
179
|
-
throw new Error(`Unsupported operation: ${operation}`);
|
|
180
|
-
}
|
|
181
|
-
})();
|
|
182
|
-
return result;
|
|
183
|
-
}
|
|
184
|
-
catch (error) {
|
|
185
|
-
return {
|
|
186
|
-
operation,
|
|
187
|
-
success: false,
|
|
188
|
-
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
buildNotificationObject(params) {
|
|
193
|
-
const hasReminders = params.reminder_enabled !== undefined;
|
|
194
|
-
const hasExpiration = params.expire_enabled !== undefined;
|
|
195
|
-
if (!hasReminders && !hasExpiration)
|
|
196
|
-
return undefined;
|
|
197
|
-
const notification = { useAccountDefaults: 'false' };
|
|
198
|
-
if (hasReminders) {
|
|
199
|
-
notification.reminders = {
|
|
200
|
-
reminderEnabled: String(params.reminder_enabled),
|
|
201
|
-
reminderDelay: params.reminder_delay || '3',
|
|
202
|
-
reminderFrequency: params.reminder_frequency || '5',
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
if (hasExpiration) {
|
|
206
|
-
notification.expirations = {
|
|
207
|
-
expireEnabled: String(params.expire_enabled),
|
|
208
|
-
expireAfter: params.expire_after || '30',
|
|
209
|
-
expireWarn: params.expire_warn || '3',
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
return notification;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Check if base64 content is a valid PDF (starts with %PDF).
|
|
216
|
-
* If not, wrap the decoded text in a minimal valid PDF.
|
|
217
|
-
*/
|
|
218
|
-
ensurePdfContent(base64Content, _fileName) {
|
|
219
|
-
// Check if it's already a PDF
|
|
220
|
-
try {
|
|
221
|
-
const decoded = Buffer.from(base64Content, 'base64').toString('utf-8');
|
|
222
|
-
if (decoded.startsWith('%PDF')) {
|
|
223
|
-
return { base64: base64Content, extension: 'pdf' };
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
// If decoding fails, assume it's binary PDF data
|
|
228
|
-
return { base64: base64Content, extension: 'pdf' };
|
|
229
|
-
}
|
|
230
|
-
// It's plain text — wrap in a minimal PDF with proper layout
|
|
231
|
-
const text = Buffer.from(base64Content, 'base64').toString('utf-8');
|
|
232
|
-
const pdf = this.textToMinimalPdf(text);
|
|
233
|
-
return {
|
|
234
|
-
base64: Buffer.from(pdf).toString('base64'),
|
|
235
|
-
extension: 'pdf',
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Convert plain text to a minimal valid PDF with proper formatting.
|
|
240
|
-
* Uses Helvetica 10pt, 72pt margins, 14pt line spacing, with word wrapping.
|
|
241
|
-
*/
|
|
242
|
-
textToMinimalPdf(text) {
|
|
243
|
-
const PAGE_WIDTH = 612; // US Letter
|
|
244
|
-
const PAGE_HEIGHT = 792;
|
|
245
|
-
const MARGIN = 72; // 1 inch
|
|
246
|
-
const FONT_SIZE = 10;
|
|
247
|
-
const LINE_HEIGHT = 14;
|
|
248
|
-
const CHARS_PER_LINE = 85; // Approximate for Helvetica 10pt at this width
|
|
249
|
-
const TOP_Y = PAGE_HEIGHT - MARGIN;
|
|
250
|
-
const LINES_PER_PAGE = Math.floor((PAGE_HEIGHT - 2 * MARGIN) / LINE_HEIGHT);
|
|
251
|
-
// Escape PDF special chars
|
|
252
|
-
const escape = (s) => s.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
|
|
253
|
-
// Word-wrap and split into lines
|
|
254
|
-
const rawLines = text.split('\n');
|
|
255
|
-
const wrappedLines = [];
|
|
256
|
-
for (const rawLine of rawLines) {
|
|
257
|
-
if (rawLine.length === 0) {
|
|
258
|
-
wrappedLines.push('');
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
const words = rawLine.split(' ');
|
|
262
|
-
let current = '';
|
|
263
|
-
for (const word of words) {
|
|
264
|
-
if (current.length + word.length + 1 > CHARS_PER_LINE) {
|
|
265
|
-
wrappedLines.push(current);
|
|
266
|
-
current = word;
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
current = current ? current + ' ' + word : word;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (current)
|
|
273
|
-
wrappedLines.push(current);
|
|
274
|
-
}
|
|
275
|
-
// Split into pages
|
|
276
|
-
const pages = [];
|
|
277
|
-
for (let i = 0; i < wrappedLines.length; i += LINES_PER_PAGE) {
|
|
278
|
-
pages.push(wrappedLines.slice(i, i + LINES_PER_PAGE));
|
|
279
|
-
}
|
|
280
|
-
if (pages.length === 0)
|
|
281
|
-
pages.push(['']);
|
|
282
|
-
// Build PDF objects
|
|
283
|
-
const objects = [];
|
|
284
|
-
let objNum = 1;
|
|
285
|
-
// Catalog
|
|
286
|
-
const catalogNum = objNum++;
|
|
287
|
-
objects.push(`${catalogNum} 0 obj\n<< /Type /Catalog /Pages ${catalogNum + 1} 0 R >>\nendobj`);
|
|
288
|
-
// Pages
|
|
289
|
-
const pagesNum = objNum++;
|
|
290
|
-
const pageObjNums = [];
|
|
291
|
-
for (let i = 0; i < pages.length; i++) {
|
|
292
|
-
pageObjNums.push(pagesNum + 1 + i * 2); // page obj numbers
|
|
293
|
-
}
|
|
294
|
-
objects.push(`${pagesNum} 0 obj\n<< /Type /Pages /Kids [${pageObjNums.map(n => `${n} 0 R`).join(' ')}] /Count ${pages.length} >>\nendobj`);
|
|
295
|
-
// Font object number (will be assigned after pages)
|
|
296
|
-
const fontObjNum = pagesNum + 1 + pages.length * 2;
|
|
297
|
-
// Page + Content objects for each page
|
|
298
|
-
for (let p = 0; p < pages.length; p++) {
|
|
299
|
-
const pageNum = objNum++;
|
|
300
|
-
const contentNum = objNum++;
|
|
301
|
-
const lineCommands = pages[p]
|
|
302
|
-
.map((line, i) => {
|
|
303
|
-
const pos = i === 0 ? `${MARGIN} ${TOP_Y} Td` : `0 -${LINE_HEIGHT} Td`;
|
|
304
|
-
return `${pos}\n(${escape(line)}) Tj`;
|
|
305
|
-
})
|
|
306
|
-
.join('\n');
|
|
307
|
-
const stream = `BT\n/F1 ${FONT_SIZE} Tf\n${lineCommands}\nET`;
|
|
308
|
-
objects.push(`${pageNum} 0 obj\n<< /Type /Page /Parent ${pagesNum} 0 R /MediaBox [0 0 ${PAGE_WIDTH} ${PAGE_HEIGHT}] /Contents ${contentNum} 0 R /Resources << /Font << /F1 ${fontObjNum} 0 R >> >> >>\nendobj`);
|
|
309
|
-
objects.push(`${contentNum} 0 obj\n<< /Length ${stream.length} >>\nstream\n${stream}\nendstream\nendobj`);
|
|
310
|
-
}
|
|
311
|
-
// Font
|
|
312
|
-
objNum++;
|
|
313
|
-
objects.push(`${fontObjNum} 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj`);
|
|
314
|
-
// Build the PDF
|
|
315
|
-
const body = objects.join('\n');
|
|
316
|
-
const totalObjs = fontObjNum + 1;
|
|
317
|
-
// Simplified xref — DocuSign is lenient with xref offsets for programmatic PDFs
|
|
318
|
-
let xref = `xref\n0 ${totalObjs}\n0000000000 65535 f \n`;
|
|
319
|
-
let offset = 9; // after %PDF-1.4\n
|
|
320
|
-
for (const obj of objects) {
|
|
321
|
-
xref += `${String(offset).padStart(10, '0')} 00000 n \n`;
|
|
322
|
-
offset += obj.length + 1;
|
|
323
|
-
}
|
|
324
|
-
return `%PDF-1.4\n${body}\n${xref}trailer\n<< /Size ${totalObjs} /Root ${catalogNum} 0 R >>\nstartxref\n${offset}\n%%EOF`;
|
|
325
|
-
}
|
|
326
|
-
async createEnvelope(params) {
|
|
327
|
-
const body = {
|
|
328
|
-
emailSubject: params.email_subject,
|
|
329
|
-
status: params.status,
|
|
330
|
-
documents: params.documents.map((doc, i) => {
|
|
331
|
-
const isPdfName = (doc.name || '').toLowerCase().endsWith('.pdf');
|
|
332
|
-
// Auto-convert text content to PDF if the file is named .pdf
|
|
333
|
-
if (isPdfName) {
|
|
334
|
-
const { base64, extension } = this.ensurePdfContent(doc.document_base64, doc.name);
|
|
335
|
-
return {
|
|
336
|
-
documentId: doc.document_id || String(i + 1),
|
|
337
|
-
name: doc.name,
|
|
338
|
-
fileExtension: extension,
|
|
339
|
-
documentBase64: base64,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
return {
|
|
343
|
-
documentId: doc.document_id || String(i + 1),
|
|
344
|
-
name: doc.name,
|
|
345
|
-
fileExtension: doc.file_extension,
|
|
346
|
-
documentBase64: doc.document_base64,
|
|
347
|
-
};
|
|
348
|
-
}),
|
|
349
|
-
recipients: {
|
|
350
|
-
signers: params.signers.map((s, i) => {
|
|
351
|
-
const signer = {
|
|
352
|
-
email: s.email,
|
|
353
|
-
name: s.name,
|
|
354
|
-
recipientId: s.recipient_id || String(i + 1),
|
|
355
|
-
routingOrder: s.routing_order,
|
|
356
|
-
};
|
|
357
|
-
if (s.tabs) {
|
|
358
|
-
signer.tabs = {};
|
|
359
|
-
if (s.tabs.sign_here?.length) {
|
|
360
|
-
signer.tabs.signHereTabs = s.tabs.sign_here.map(t => ({
|
|
361
|
-
documentId: t.document_id,
|
|
362
|
-
pageNumber: t.page_number,
|
|
363
|
-
xPosition: t.x_position,
|
|
364
|
-
yPosition: t.y_position,
|
|
365
|
-
}));
|
|
366
|
-
}
|
|
367
|
-
if (s.tabs.date_signed?.length) {
|
|
368
|
-
signer.tabs.dateSignedTabs = s.tabs.date_signed.map(t => ({
|
|
369
|
-
documentId: t.document_id,
|
|
370
|
-
pageNumber: t.page_number,
|
|
371
|
-
xPosition: t.x_position,
|
|
372
|
-
yPosition: t.y_position,
|
|
373
|
-
}));
|
|
374
|
-
}
|
|
375
|
-
if (s.tabs.text?.length) {
|
|
376
|
-
signer.tabs.textTabs = s.tabs.text.map(t => ({
|
|
377
|
-
documentId: t.document_id,
|
|
378
|
-
pageNumber: t.page_number,
|
|
379
|
-
xPosition: t.x_position,
|
|
380
|
-
yPosition: t.y_position,
|
|
381
|
-
tabLabel: t.tab_label,
|
|
382
|
-
value: t.value,
|
|
383
|
-
required: t.required,
|
|
384
|
-
}));
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
return signer;
|
|
388
|
-
}),
|
|
389
|
-
},
|
|
390
|
-
};
|
|
391
|
-
if (params.cc_recipients?.length) {
|
|
392
|
-
body.recipients.carbonCopies = params.cc_recipients.map((cc, i) => ({
|
|
393
|
-
email: cc.email,
|
|
394
|
-
name: cc.name,
|
|
395
|
-
recipientId: cc.recipient_id || String(params.signers.length + i + 1),
|
|
396
|
-
routingOrder: cc.routing_order,
|
|
397
|
-
}));
|
|
398
|
-
}
|
|
399
|
-
if (params.email_body) {
|
|
400
|
-
body.emailBlurb = params.email_body;
|
|
401
|
-
}
|
|
402
|
-
const notification = this.buildNotificationObject(params);
|
|
403
|
-
if (notification) {
|
|
404
|
-
body.notification = notification;
|
|
405
|
-
}
|
|
406
|
-
const response = await this.makeDocuSignRequest('/envelopes', 'POST', body);
|
|
407
|
-
return {
|
|
408
|
-
operation: 'create_envelope',
|
|
409
|
-
success: true,
|
|
410
|
-
envelope_id: response.envelopeId,
|
|
411
|
-
status: response.status,
|
|
412
|
-
status_date_time: response.statusDateTime,
|
|
413
|
-
uri: response.uri,
|
|
414
|
-
error: '',
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
async createEnvelopeFromTemplate(params) {
|
|
418
|
-
const body = {
|
|
419
|
-
templateId: params.template_id,
|
|
420
|
-
status: params.status,
|
|
421
|
-
templateRoles: params.signers.map((s, i) => {
|
|
422
|
-
const role = {
|
|
423
|
-
email: s.email,
|
|
424
|
-
name: s.name,
|
|
425
|
-
roleName: s.role_name,
|
|
426
|
-
recipientId: s.recipient_id || String(i + 1),
|
|
427
|
-
};
|
|
428
|
-
// Pre-fill template fields if provided
|
|
429
|
-
if (params.template_data) {
|
|
430
|
-
role.tabs = {
|
|
431
|
-
textTabs: Object.entries(params.template_data).map(([label, value]) => ({
|
|
432
|
-
tabLabel: label,
|
|
433
|
-
value,
|
|
434
|
-
})),
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
return role;
|
|
438
|
-
}),
|
|
439
|
-
};
|
|
440
|
-
if (params.cc_recipients?.length) {
|
|
441
|
-
body.templateRoles.push(...params.cc_recipients.map((cc, i) => ({
|
|
442
|
-
email: cc.email,
|
|
443
|
-
name: cc.name,
|
|
444
|
-
roleName: cc.role_name,
|
|
445
|
-
recipientId: cc.recipient_id || String(params.signers.length + i + 1),
|
|
446
|
-
})));
|
|
447
|
-
}
|
|
448
|
-
if (params.email_subject)
|
|
449
|
-
body.emailSubject = params.email_subject;
|
|
450
|
-
if (params.email_body)
|
|
451
|
-
body.emailBlurb = params.email_body;
|
|
452
|
-
const notification = this.buildNotificationObject(params);
|
|
453
|
-
if (notification)
|
|
454
|
-
body.notification = notification;
|
|
455
|
-
const response = await this.makeDocuSignRequest('/envelopes', 'POST', body);
|
|
456
|
-
return {
|
|
457
|
-
operation: 'create_envelope_from_template',
|
|
458
|
-
success: true,
|
|
459
|
-
envelope_id: response.envelopeId,
|
|
460
|
-
status: response.status,
|
|
461
|
-
status_date_time: response.statusDateTime,
|
|
462
|
-
uri: response.uri,
|
|
463
|
-
error: '',
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
async getEnvelope(params) {
|
|
467
|
-
const response = await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}`);
|
|
468
|
-
return {
|
|
469
|
-
operation: 'get_envelope',
|
|
470
|
-
success: true,
|
|
471
|
-
envelope_id: response.envelopeId,
|
|
472
|
-
status: response.status,
|
|
473
|
-
email_subject: response.emailSubject,
|
|
474
|
-
sent_date_time: response.sentDateTime,
|
|
475
|
-
completed_date_time: response.completedDateTime,
|
|
476
|
-
declined_date_time: response.declinedDateTime,
|
|
477
|
-
voided_date_time: response.voidedDateTime,
|
|
478
|
-
status_changed_date_time: response.statusChangedDateTime,
|
|
479
|
-
error: '',
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
async listEnvelopes(params) {
|
|
483
|
-
const queryParams = new URLSearchParams();
|
|
484
|
-
// Default from_date to 30 days ago if not provided
|
|
485
|
-
const fromDate = params.from_date || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
|
486
|
-
queryParams.set('from_date', fromDate);
|
|
487
|
-
if (params.to_date)
|
|
488
|
-
queryParams.set('to_date', params.to_date);
|
|
489
|
-
if (params.status)
|
|
490
|
-
queryParams.set('status', params.status);
|
|
491
|
-
if (params.search_text)
|
|
492
|
-
queryParams.set('search_text', params.search_text);
|
|
493
|
-
if (params.count)
|
|
494
|
-
queryParams.set('count', params.count);
|
|
495
|
-
if (params.start_position)
|
|
496
|
-
queryParams.set('start_position', params.start_position);
|
|
497
|
-
if (params.order_by)
|
|
498
|
-
queryParams.set('order_by', params.order_by);
|
|
499
|
-
if (params.order)
|
|
500
|
-
queryParams.set('order', params.order);
|
|
501
|
-
const response = await this.makeDocuSignRequest(`/envelopes?${queryParams.toString()}`);
|
|
502
|
-
const envelopes = (response.envelopes || []).map((env) => ({
|
|
503
|
-
envelope_id: env.envelopeId,
|
|
504
|
-
status: env.status,
|
|
505
|
-
email_subject: env.emailSubject,
|
|
506
|
-
sent_date_time: env.sentDateTime,
|
|
507
|
-
completed_date_time: env.completedDateTime,
|
|
508
|
-
status_changed_date_time: env.statusChangedDateTime,
|
|
509
|
-
}));
|
|
510
|
-
return {
|
|
511
|
-
operation: 'list_envelopes',
|
|
512
|
-
success: true,
|
|
513
|
-
envelopes,
|
|
514
|
-
result_set_size: response.resultSetSize,
|
|
515
|
-
total_set_size: response.totalSetSize,
|
|
516
|
-
next_uri: response.nextUri,
|
|
517
|
-
error: '',
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
async getRecipients(params) {
|
|
521
|
-
const response = await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}/recipients`);
|
|
522
|
-
const signers = (response.signers || []).map((s) => ({
|
|
523
|
-
email: s.email,
|
|
524
|
-
name: s.name,
|
|
525
|
-
status: s.status,
|
|
526
|
-
signed_date_time: s.signedDateTime,
|
|
527
|
-
delivered_date_time: s.deliveredDateTime,
|
|
528
|
-
declined_date_time: s.declinedDateTime,
|
|
529
|
-
decline_reason: s.declinedReason,
|
|
530
|
-
recipient_id: s.recipientId,
|
|
531
|
-
routing_order: s.routingOrder,
|
|
532
|
-
}));
|
|
533
|
-
const ccRecipients = (response.carbonCopies || []).map((cc) => ({
|
|
534
|
-
email: cc.email,
|
|
535
|
-
name: cc.name,
|
|
536
|
-
status: cc.status,
|
|
537
|
-
recipient_id: cc.recipientId,
|
|
538
|
-
}));
|
|
539
|
-
return {
|
|
540
|
-
operation: 'get_recipients',
|
|
541
|
-
success: true,
|
|
542
|
-
signers,
|
|
543
|
-
cc_recipients: ccRecipients,
|
|
544
|
-
error: '',
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
async listTemplates(params) {
|
|
548
|
-
const queryParams = new URLSearchParams();
|
|
549
|
-
if (params.search_text)
|
|
550
|
-
queryParams.set('search_text', params.search_text);
|
|
551
|
-
if (params.count)
|
|
552
|
-
queryParams.set('count', params.count);
|
|
553
|
-
const query = queryParams.toString();
|
|
554
|
-
const response = await this.makeDocuSignRequest(`/templates${query ? '?' + query : ''}`);
|
|
555
|
-
const templates = (response.envelopeTemplates || []).map((t) => ({
|
|
556
|
-
template_id: t.templateId,
|
|
557
|
-
name: t.name,
|
|
558
|
-
description: t.description,
|
|
559
|
-
created: t.created,
|
|
560
|
-
last_modified: t.lastModified,
|
|
561
|
-
}));
|
|
562
|
-
return {
|
|
563
|
-
operation: 'list_templates',
|
|
564
|
-
success: true,
|
|
565
|
-
templates,
|
|
566
|
-
result_set_size: response.resultSetSize,
|
|
567
|
-
total_set_size: response.totalSetSize,
|
|
568
|
-
error: '',
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
|
-
async downloadDocument(params) {
|
|
572
|
-
const documentBase64 = await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}/documents/${params.document_id}`);
|
|
573
|
-
return {
|
|
574
|
-
operation: 'download_document',
|
|
575
|
-
success: true,
|
|
576
|
-
document_base64: documentBase64,
|
|
577
|
-
document_name: `envelope_${params.envelope_id}_doc_${params.document_id}.pdf`,
|
|
578
|
-
error: '',
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
async voidEnvelope(params) {
|
|
582
|
-
await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}`, 'PUT', {
|
|
583
|
-
status: 'voided',
|
|
584
|
-
voidedReason: params.void_reason,
|
|
585
|
-
});
|
|
586
|
-
return {
|
|
587
|
-
operation: 'void_envelope',
|
|
588
|
-
success: true,
|
|
589
|
-
envelope_id: params.envelope_id,
|
|
590
|
-
error: '',
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
async resendEnvelope(params) {
|
|
594
|
-
// First get current recipients, then PUT them back with resend flag
|
|
595
|
-
const recipients = await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}/recipients`);
|
|
596
|
-
// Build the recipients payload with only signers who haven't completed
|
|
597
|
-
const signers = (recipients.signers || [])
|
|
598
|
-
.filter((s) => s.status !== 'completed')
|
|
599
|
-
.map((s) => ({
|
|
600
|
-
email: s.email,
|
|
601
|
-
name: s.name,
|
|
602
|
-
recipientId: s.recipientId,
|
|
603
|
-
}));
|
|
604
|
-
if (signers.length === 0) {
|
|
605
|
-
return {
|
|
606
|
-
operation: 'resend_envelope',
|
|
607
|
-
success: true,
|
|
608
|
-
envelope_id: params.envelope_id,
|
|
609
|
-
error: 'All recipients have already completed signing.',
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}/recipients?resend_envelope=true`, 'PUT', { signers });
|
|
613
|
-
return {
|
|
614
|
-
operation: 'resend_envelope',
|
|
615
|
-
success: true,
|
|
616
|
-
envelope_id: params.envelope_id,
|
|
617
|
-
error: '',
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
|
-
async bulkSendFromTemplate(params) {
|
|
621
|
-
if (!params.recipients || params.recipients.length === 0) {
|
|
622
|
-
return {
|
|
623
|
-
operation: 'bulk_send_from_template',
|
|
624
|
-
success: false,
|
|
625
|
-
results: [],
|
|
626
|
-
total_sent: 0,
|
|
627
|
-
total_failed: 0,
|
|
628
|
-
error: 'Recipients array is empty. At least one recipient is required.',
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
const results = [];
|
|
632
|
-
let totalSent = 0;
|
|
633
|
-
let totalFailed = 0;
|
|
634
|
-
for (const recipient of params.recipients) {
|
|
635
|
-
try {
|
|
636
|
-
const body = {
|
|
637
|
-
templateId: params.template_id,
|
|
638
|
-
status: 'sent',
|
|
639
|
-
templateRoles: [
|
|
640
|
-
{
|
|
641
|
-
email: recipient.email,
|
|
642
|
-
name: recipient.name,
|
|
643
|
-
roleName: recipient.role_name,
|
|
644
|
-
},
|
|
645
|
-
],
|
|
646
|
-
};
|
|
647
|
-
if (params.email_subject)
|
|
648
|
-
body.emailSubject = params.email_subject;
|
|
649
|
-
if (params.email_body)
|
|
650
|
-
body.emailBlurb = params.email_body;
|
|
651
|
-
const response = await this.makeDocuSignRequest('/envelopes', 'POST', body);
|
|
652
|
-
results.push({
|
|
653
|
-
envelope_id: response.envelopeId,
|
|
654
|
-
status: response.status,
|
|
655
|
-
recipient_email: recipient.email,
|
|
656
|
-
});
|
|
657
|
-
totalSent++;
|
|
658
|
-
}
|
|
659
|
-
catch (error) {
|
|
660
|
-
results.push({
|
|
661
|
-
recipient_email: recipient.email,
|
|
662
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
663
|
-
});
|
|
664
|
-
totalFailed++;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return {
|
|
668
|
-
operation: 'bulk_send_from_template',
|
|
669
|
-
success: totalSent > 0,
|
|
670
|
-
results,
|
|
671
|
-
total_sent: totalSent,
|
|
672
|
-
total_failed: totalFailed,
|
|
673
|
-
error: totalFailed > 0 ? `${totalFailed} of ${params.recipients.length} sends failed.` : '',
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
async getSigningUrl(params) {
|
|
677
|
-
const body = {
|
|
678
|
-
returnUrl: params.return_url,
|
|
679
|
-
authenticationMethod: 'none',
|
|
680
|
-
email: params.signer_email,
|
|
681
|
-
userName: params.signer_name,
|
|
682
|
-
};
|
|
683
|
-
const response = await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}/views/recipient`, 'POST', body);
|
|
684
|
-
return {
|
|
685
|
-
operation: 'get_signing_url',
|
|
686
|
-
success: true,
|
|
687
|
-
signing_url: response.url,
|
|
688
|
-
error: '',
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
async correctRecipient(params) {
|
|
692
|
-
// First, get current recipients to find the recipientId for old_email
|
|
693
|
-
const recipients = await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}/recipients`);
|
|
694
|
-
const signers = recipients.signers || [];
|
|
695
|
-
const matchingSigner = signers.find((s) => s.email.toLowerCase() === params.old_email.toLowerCase());
|
|
696
|
-
if (!matchingSigner) {
|
|
697
|
-
return {
|
|
698
|
-
operation: 'correct_recipient',
|
|
699
|
-
success: false,
|
|
700
|
-
envelope_id: params.envelope_id,
|
|
701
|
-
old_email: params.old_email,
|
|
702
|
-
new_email: params.new_email,
|
|
703
|
-
error: `No recipient found with email "${params.old_email}" on envelope ${params.envelope_id}.`,
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
// PUT updated recipient info
|
|
707
|
-
await this.makeDocuSignRequest(`/envelopes/${params.envelope_id}/recipients`, 'PUT', {
|
|
708
|
-
signers: [
|
|
709
|
-
{
|
|
710
|
-
recipientId: matchingSigner.recipientId,
|
|
711
|
-
email: params.new_email,
|
|
712
|
-
name: params.new_name || matchingSigner.name,
|
|
713
|
-
},
|
|
714
|
-
],
|
|
715
|
-
});
|
|
716
|
-
return {
|
|
717
|
-
operation: 'correct_recipient',
|
|
718
|
-
success: true,
|
|
719
|
-
envelope_id: params.envelope_id,
|
|
720
|
-
old_email: params.old_email,
|
|
721
|
-
new_email: params.new_email,
|
|
722
|
-
error: '',
|
|
723
|
-
};
|
|
724
|
-
}
|
|
725
|
-
chooseCredential() {
|
|
726
|
-
const creds = this.parseCredentials();
|
|
727
|
-
return creds?.accessToken;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
//# sourceMappingURL=docusign.js.map
|