@dereekb/zoho 13.0.6 → 13.0.7
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/index.cjs.js +2164 -231
- package/index.esm.js +2143 -232
- package/nestjs/LICENSE +21 -0
- package/nestjs/README.md +11 -0
- package/nestjs/docs/configuration.md +165 -0
- package/nestjs/docs/crm-getting-started.md +296 -0
- package/nestjs/index.cjs.js +653 -5
- package/nestjs/index.esm.js +647 -7
- package/nestjs/package.json +3 -3
- package/nestjs/src/lib/crm/crm.api.d.ts +46 -0
- package/nestjs/src/lib/crm/crm.config.d.ts +16 -1
- package/nestjs/src/lib/crm/crm.module.d.ts +77 -8
- package/nestjs/src/lib/index.d.ts +2 -0
- package/nestjs/src/lib/recruit/recruit.api.d.ts +50 -0
- package/nestjs/src/lib/recruit/recruit.config.d.ts +16 -1
- package/nestjs/src/lib/recruit/recruit.module.d.ts +77 -8
- package/nestjs/src/lib/sign/index.d.ts +3 -0
- package/nestjs/src/lib/sign/sign.api.d.ts +54 -0
- package/nestjs/src/lib/sign/sign.config.d.ts +10 -0
- package/nestjs/src/lib/sign/sign.module.d.ts +94 -0
- package/package.json +2 -2
- package/src/lib/accounts/accounts.api.d.ts +149 -3
- package/src/lib/accounts/accounts.factory.d.ts +73 -6
- package/src/lib/crm/crm.api.d.ts +599 -62
- package/src/lib/crm/crm.api.notes.d.ts +46 -3
- package/src/lib/crm/crm.api.tags.d.ts +65 -2
- package/src/lib/crm/crm.config.d.ts +30 -0
- package/src/lib/crm/crm.criteria.d.ts +60 -3
- package/src/lib/crm/crm.error.api.d.ts +42 -0
- package/src/lib/crm/crm.factory.d.ts +39 -3
- package/src/lib/crm/crm.notes.d.ts +36 -0
- package/src/lib/crm/crm.tags.d.ts +3 -0
- package/src/lib/index.d.ts +1 -0
- package/src/lib/recruit/recruit.api.candidates.d.ts +44 -3
- package/src/lib/recruit/recruit.api.d.ts +719 -57
- package/src/lib/recruit/recruit.api.notes.d.ts +140 -0
- package/src/lib/recruit/recruit.api.tags.d.ts +122 -14
- package/src/lib/recruit/recruit.config.d.ts +30 -0
- package/src/lib/recruit/recruit.criteria.d.ts +55 -3
- package/src/lib/recruit/recruit.error.api.d.ts +39 -0
- package/src/lib/recruit/recruit.factory.d.ts +39 -3
- package/src/lib/recruit/recruit.notes.d.ts +21 -0
- package/src/lib/recruit/recruit.tags.d.ts +3 -0
- package/src/lib/shared/criteria.d.ts +95 -11
- package/src/lib/shared/criteria.util.d.ts +19 -4
- package/src/lib/sign/index.d.ts +6 -0
- package/src/lib/sign/sign.api.d.ts +397 -0
- package/src/lib/sign/sign.api.page.d.ts +109 -0
- package/src/lib/sign/sign.config.d.ts +24 -0
- package/src/lib/sign/sign.d.ts +225 -0
- package/src/lib/sign/sign.error.api.d.ts +7 -0
- package/src/lib/sign/sign.factory.d.ts +58 -0
- package/src/lib/zoho.api.page.d.ts +41 -10
- package/src/lib/zoho.config.d.ts +24 -9
- package/src/lib/zoho.limit.d.ts +41 -9
- package/src/lib/zoho.type.d.ts +24 -8
package/index.esm.js
CHANGED
|
@@ -3,7 +3,10 @@ import { fetchPageFactory, FetchResponseError, makeUrlSearchParams, parseFetchFi
|
|
|
3
3
|
import { BaseError } from 'make-error';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Creates an empty {@link ZohoPageResult} with no data and `more_records: false`.
|
|
7
|
+
* Useful as a fallback when the API returns `null` instead of an empty result.
|
|
8
|
+
*
|
|
9
|
+
* @returns An empty page result with default pagination info
|
|
7
10
|
*/
|
|
8
11
|
function emptyZohoPageResult() {
|
|
9
12
|
return {
|
|
@@ -17,11 +20,26 @@ function emptyZohoPageResult() {
|
|
|
17
20
|
};
|
|
18
21
|
}
|
|
19
22
|
/**
|
|
20
|
-
* Creates a
|
|
23
|
+
* Creates a page factory that wraps a Zoho fetch function with automatic pagination.
|
|
21
24
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* The factory reads `info.more_records` from each response to determine if additional
|
|
26
|
+
* pages exist, and automatically increments the `page` parameter for subsequent requests.
|
|
27
|
+
*
|
|
28
|
+
* @param fetch - The Zoho fetch function to paginate over
|
|
29
|
+
* @param defaults - Optional default configuration for the page factory
|
|
30
|
+
* @returns A page factory that produces iterable page fetchers
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const pageFactory = zohoFetchPageFactory(zohoCrmSearchRecords(context));
|
|
35
|
+
*
|
|
36
|
+
* const fetchPage = pageFactory({ module: 'Contacts', word: 'Smith', per_page: 10 });
|
|
37
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
38
|
+
*
|
|
39
|
+
* if (firstPage.result.info.more_records) {
|
|
40
|
+
* const secondPage = await firstPage.fetchNext();
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
25
43
|
*/
|
|
26
44
|
function zohoFetchPageFactory(fetch, defaults) {
|
|
27
45
|
return fetchPageFactory({
|
|
@@ -38,7 +56,13 @@ function zohoFetchPageFactory(fetch, defaults) {
|
|
|
38
56
|
});
|
|
39
57
|
}
|
|
40
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Service identifier used to distinguish Zoho Recruit from other Zoho services when managing access tokens and API routing.
|
|
61
|
+
*/
|
|
41
62
|
const ZOHO_RECRUIT_SERVICE_NAME = 'recruit';
|
|
63
|
+
/**
|
|
64
|
+
* Resolves an environment key or passthrough URL to the full Zoho Recruit API URL.
|
|
65
|
+
*/
|
|
42
66
|
function zohoRecruitConfigApiUrl(input) {
|
|
43
67
|
switch (input) {
|
|
44
68
|
case 'sandbox':
|
|
@@ -86,9 +110,33 @@ const ZOHO_RECRUIT_RECORD_ATTACHMENT_METADATA_ATTACH_TYPE_RESUME = 'Resume';
|
|
|
86
110
|
*/
|
|
87
111
|
const MAX_ZOHO_SEARCH_MODULE_RECORDS_CRITERIA = 10;
|
|
88
112
|
/**
|
|
89
|
-
*
|
|
113
|
+
* Compiles a {@link ZohoSearchRecordsCriteriaTreeElement} into a URL-ready criteria string.
|
|
114
|
+
*
|
|
115
|
+
* Accepts any supported input shape: a raw criteria string (passed through),
|
|
116
|
+
* an array of {@link ZohoSearchRecordsCriteriaEntry} (AND-joined), or a full
|
|
117
|
+
* {@link ZohoSearchRecordsCriteriaTree} with nested AND/OR groups. Returns
|
|
118
|
+
* `undefined` when the input is nullish or empty.
|
|
90
119
|
*
|
|
91
|
-
*
|
|
120
|
+
* @param input - Criteria tree element, entry array, or raw criteria string
|
|
121
|
+
* @returns Compiled criteria string, or `undefined` if input is empty
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* // From an entry array (AND-joined):
|
|
126
|
+
* const criteria = zohoSearchRecordsCriteriaString([
|
|
127
|
+
* { field: 'Last_Name', filter: 'equals', value: 'Smith' },
|
|
128
|
+
* { field: 'Email', filter: 'contains', value: 'example.com' }
|
|
129
|
+
* ]);
|
|
130
|
+
* // => '((Last_Name:equals:Smith)and(Email:contains:example.com))'
|
|
131
|
+
*
|
|
132
|
+
* // From a tree with OR:
|
|
133
|
+
* const orCriteria = zohoSearchRecordsCriteriaString({
|
|
134
|
+
* or: [
|
|
135
|
+
* [{ field: 'Status', filter: 'equals', value: 'Active' }],
|
|
136
|
+
* [{ field: 'Status', filter: 'equals', value: 'Pending' }]
|
|
137
|
+
* ]
|
|
138
|
+
* });
|
|
139
|
+
* ```
|
|
92
140
|
*/
|
|
93
141
|
function zohoSearchRecordsCriteriaString(input) {
|
|
94
142
|
let result;
|
|
@@ -111,6 +159,14 @@ function zohoSearchRecordsCriteriaString(input) {
|
|
|
111
159
|
}
|
|
112
160
|
return result;
|
|
113
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Compiles a {@link ZohoSearchRecordsCriteriaTree} into a criteria string by
|
|
164
|
+
* recursively resolving nested AND/OR groups. When both `and` and `or` are
|
|
165
|
+
* present at the same level, the OR group is merged into the AND group.
|
|
166
|
+
*
|
|
167
|
+
* @param tree - Criteria tree containing `and` and/or `or` branches
|
|
168
|
+
* @returns Compiled criteria string, or `undefined` if the tree is empty
|
|
169
|
+
*/
|
|
114
170
|
function zohoSearchRecordsCriteriaStringForTree(tree) {
|
|
115
171
|
function convertToString(value) {
|
|
116
172
|
let result;
|
|
@@ -144,7 +200,9 @@ function zohoSearchRecordsCriteriaStringForTree(tree) {
|
|
|
144
200
|
return result;
|
|
145
201
|
}
|
|
146
202
|
/**
|
|
147
|
-
*
|
|
203
|
+
* Escapes parentheses and commas in a field value for use in a {@link ZohoSearchRecordsCriteriaString}.
|
|
204
|
+
*
|
|
205
|
+
* Characters `(`, `)`, and `,` are escaped with a double-backslash prefix as required by the Zoho API.
|
|
148
206
|
*/
|
|
149
207
|
const escapeZohoFieldValueForCriteriaString = escapeStringCharactersFunction({
|
|
150
208
|
/**
|
|
@@ -154,10 +212,22 @@ const escapeZohoFieldValueForCriteriaString = escapeStringCharactersFunction({
|
|
|
154
212
|
escapeCharacter: (char) => `\\\\${char}`
|
|
155
213
|
});
|
|
156
214
|
/**
|
|
157
|
-
* Converts
|
|
215
|
+
* Converts a single {@link ZohoSearchRecordsCriteriaEntry} into a parenthesized criteria string.
|
|
158
216
|
*
|
|
159
|
-
* @
|
|
160
|
-
*
|
|
217
|
+
* Automatically escapes parentheses and commas in the value via {@link escapeZohoFieldValueForCriteriaString}.
|
|
218
|
+
*
|
|
219
|
+
* @param entry - The criteria entry to convert
|
|
220
|
+
* @returns Criteria string in the format `(field:filter:escapedValue)`
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const str = zohoSearchRecordsCriteriaEntryToCriteriaString({
|
|
225
|
+
* field: 'Last_Name',
|
|
226
|
+
* filter: 'equals',
|
|
227
|
+
* value: 'Smith'
|
|
228
|
+
* });
|
|
229
|
+
* // => '(Last_Name:equals:Smith)'
|
|
230
|
+
* ```
|
|
161
231
|
*/
|
|
162
232
|
function zohoSearchRecordsCriteriaEntryToCriteriaString(entry) {
|
|
163
233
|
const escapedValue = escapeZohoFieldValueForCriteriaString(entry.value);
|
|
@@ -165,15 +235,35 @@ function zohoSearchRecordsCriteriaEntryToCriteriaString(entry) {
|
|
|
165
235
|
}
|
|
166
236
|
|
|
167
237
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* https://www.zoho.com/recruit/developer-guide/apiv2/search-records.html
|
|
238
|
+
* Maximum number of criteria allowed per Recruit search query (10).
|
|
171
239
|
*
|
|
172
240
|
* "You can search for a maximum of 10 criteria (with the same or different column) with equals and starts_with conditions."
|
|
241
|
+
*
|
|
242
|
+
* Re-exports {@link MAX_ZOHO_SEARCH_MODULE_RECORDS_CRITERIA}.
|
|
243
|
+
*
|
|
244
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/search-records.html
|
|
173
245
|
*/
|
|
174
246
|
const MAX_ZOHO_RECRUIT_SEARCH_MODULE_RECORDS_CRITERIA = MAX_ZOHO_SEARCH_MODULE_RECORDS_CRITERIA;
|
|
247
|
+
/**
|
|
248
|
+
* Recruit-specific re-export of {@link zohoSearchRecordsCriteriaString}.
|
|
249
|
+
*
|
|
250
|
+
* Compiles a criteria tree element (entry array, nested tree, or raw string) into a
|
|
251
|
+
* URL-ready criteria string. Returns `undefined` when the input is nullish or empty.
|
|
252
|
+
*/
|
|
175
253
|
const zohoRecruitSearchRecordsCriteriaString = zohoSearchRecordsCriteriaString;
|
|
254
|
+
/**
|
|
255
|
+
* Recruit-specific re-export of {@link zohoSearchRecordsCriteriaStringForTree}.
|
|
256
|
+
*
|
|
257
|
+
* Compiles a {@link ZohoRecruitSearchRecordsCriteriaTree} into a criteria string by
|
|
258
|
+
* recursively resolving nested AND/OR groups.
|
|
259
|
+
*/
|
|
176
260
|
const zohoRecruitSearchRecordsCriteriaStringForTree = zohoSearchRecordsCriteriaStringForTree;
|
|
261
|
+
/**
|
|
262
|
+
* Recruit-specific re-export of {@link zohoSearchRecordsCriteriaEntryToCriteriaString}.
|
|
263
|
+
*
|
|
264
|
+
* Converts a single criteria entry into a parenthesized criteria string
|
|
265
|
+
* in the format `(field:filter:escapedValue)`.
|
|
266
|
+
*/
|
|
177
267
|
const zohoRecruitSearchRecordsCriteriaEntryToCriteriaString = zohoSearchRecordsCriteriaEntryToCriteriaString;
|
|
178
268
|
|
|
179
269
|
/**
|
|
@@ -480,19 +570,37 @@ class ZohoRecruitRecordNoContentError extends BaseError {
|
|
|
480
570
|
this.recordId = recordId;
|
|
481
571
|
}
|
|
482
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Base error for Zoho Recruit record CRUD operations, carrying structured error details from the API response.
|
|
575
|
+
*/
|
|
483
576
|
class ZohoRecruitRecordCrudError extends ZohoServerError {
|
|
484
577
|
}
|
|
578
|
+
/**
|
|
579
|
+
* Thrown when a required field is missing from the record data submitted to Zoho Recruit.
|
|
580
|
+
*/
|
|
485
581
|
class ZohoRecruitRecordCrudMandatoryFieldNotFoundError extends ZohoRecruitRecordCrudError {
|
|
486
582
|
}
|
|
583
|
+
/**
|
|
584
|
+
* Thrown when a record cannot be created or updated because it would produce duplicate data in Zoho Recruit.
|
|
585
|
+
*/
|
|
487
586
|
class ZohoRecruitRecordCrudDuplicateDataError extends ZohoRecruitRecordCrudError {
|
|
488
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* Thrown when the Zoho Recruit API rejects record data as invalid. Provides per-field error details via {@link invalidFieldDetails}.
|
|
590
|
+
*/
|
|
489
591
|
class ZohoRecruitRecordCrudInvalidDataError extends ZohoRecruitRecordCrudError {
|
|
490
592
|
get invalidFieldDetails() {
|
|
491
593
|
return this.error.details;
|
|
492
594
|
}
|
|
493
595
|
}
|
|
596
|
+
/**
|
|
597
|
+
* Thrown when the 'id' field in the submitted data does not match any existing Zoho Recruit record.
|
|
598
|
+
*/
|
|
494
599
|
class ZohoRecruitRecordCrudNoMatchingRecordError extends ZohoRecruitRecordCrudInvalidDataError {
|
|
495
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* Creates a typed CRUD error subclass based on the error code returned by the Zoho Recruit API, enabling callers to catch specific failure modes.
|
|
603
|
+
*/
|
|
496
604
|
function zohoRecruitRecordCrudError(error) {
|
|
497
605
|
let result;
|
|
498
606
|
switch (error.code) {
|
|
@@ -517,6 +625,9 @@ function zohoRecruitRecordCrudError(error) {
|
|
|
517
625
|
}
|
|
518
626
|
return result;
|
|
519
627
|
}
|
|
628
|
+
/**
|
|
629
|
+
* Returns an assertion function that throws {@link ZohoRecruitRecordNoContentError} when the data array result is empty or null, indicating the requested record does not exist.
|
|
630
|
+
*/
|
|
520
631
|
function assertZohoRecruitRecordDataArrayResultHasContent(moduleName, recordId) {
|
|
521
632
|
return (x) => {
|
|
522
633
|
if (x == null || !x.data?.length) {
|
|
@@ -527,7 +638,13 @@ function assertZohoRecruitRecordDataArrayResultHasContent(moduleName, recordId)
|
|
|
527
638
|
}
|
|
528
639
|
};
|
|
529
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* Logs Zoho Recruit server errors to the console, prefixed with the 'ZohoRecruit' service label.
|
|
643
|
+
*/
|
|
530
644
|
const logZohoRecruitErrorToConsole = logZohoServerErrorFunction('ZohoRecruit');
|
|
645
|
+
/**
|
|
646
|
+
* Parses the JSON body of a failed Zoho Recruit fetch response into a structured error, returning undefined if the body cannot be parsed.
|
|
647
|
+
*/
|
|
531
648
|
async function parseZohoRecruitError(responseError) {
|
|
532
649
|
const data = await responseError.response.json().catch((x) => undefined);
|
|
533
650
|
let result;
|
|
@@ -536,6 +653,9 @@ async function parseZohoRecruitError(responseError) {
|
|
|
536
653
|
}
|
|
537
654
|
return result;
|
|
538
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* Converts raw Zoho Recruit error response data into a parsed error, delegating to Recruit-specific handlers for known error codes and falling back to the shared Zoho parser.
|
|
658
|
+
*/
|
|
539
659
|
function parseZohoRecruitServerErrorResponseData(errorResponseData, responseError) {
|
|
540
660
|
let result;
|
|
541
661
|
const error = tryFindZohoServerErrorData(errorResponseData, responseError);
|
|
@@ -550,7 +670,13 @@ function parseZohoRecruitServerErrorResponseData(errorResponseData, responseErro
|
|
|
550
670
|
}
|
|
551
671
|
return result;
|
|
552
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Intercepts Zoho Recruit API responses that return HTTP 200 but contain an error payload, re-throwing them as proper errors so callers are not silently misled by a success status.
|
|
675
|
+
*/
|
|
553
676
|
const interceptZohoRecruit200StatusWithErrorResponse = interceptZohoErrorResponseFactory(parseZohoRecruitServerErrorResponseData);
|
|
677
|
+
/**
|
|
678
|
+
* Wraps a fetch client to automatically parse Zoho Recruit error responses, log them, and invoke a custom handler (e.g., for token refresh on authentication failures).
|
|
679
|
+
*/
|
|
554
680
|
const handleZohoRecruitErrorFetch = handleZohoErrorFetchFactory(parseZohoRecruitError, logZohoRecruitErrorToConsole);
|
|
555
681
|
// MARK: Compat
|
|
556
682
|
/**
|
|
@@ -566,9 +692,10 @@ const assertRecordDataArrayResultHasContent = assertZohoRecruitRecordDataArrayRe
|
|
|
566
692
|
*/
|
|
567
693
|
const ZOHO_RECRUIT_CRUD_FUNCTION_MAX_RECORDS_LIMIT = 100;
|
|
568
694
|
/**
|
|
569
|
-
*
|
|
695
|
+
* Shared implementation for the Insert, Upsert, and Update endpoints, which all share the same request/response structure.
|
|
570
696
|
*
|
|
571
|
-
*
|
|
697
|
+
* When a single record is provided, the function returns the change details directly or throws on error.
|
|
698
|
+
* When multiple records are provided, it returns a paired success/error result.
|
|
572
699
|
*/
|
|
573
700
|
function updateRecordLikeFunction$1(context, fetchUrlPrefix, fetchMethod) {
|
|
574
701
|
return (({ data, module }) => context.fetchJson(`/v2/${module}${fetchUrlPrefix}`, zohoRecruitApiFetchJsonInput(fetchMethod, { data: asArray(data) })).then((x) => {
|
|
@@ -589,45 +716,145 @@ function updateRecordLikeFunction$1(context, fetchUrlPrefix, fetchMethod) {
|
|
|
589
716
|
}));
|
|
590
717
|
}
|
|
591
718
|
/**
|
|
592
|
-
*
|
|
719
|
+
* Creates a {@link ZohoRecruitInsertRecordFunction} bound to the given context.
|
|
593
720
|
*
|
|
594
|
-
*
|
|
721
|
+
* Inserts one or more records into a Recruit module. When a single record is
|
|
722
|
+
* provided, returns the {@link ZohoRecruitChangeObjectDetails} directly or
|
|
723
|
+
* throws on error. When multiple records are provided, returns a
|
|
724
|
+
* {@link ZohoRecruitUpdateRecordResult} with paired success/error arrays.
|
|
595
725
|
*
|
|
596
|
-
* @
|
|
597
|
-
*
|
|
726
|
+
* Maximum of {@link ZOHO_RECRUIT_CRUD_FUNCTION_MAX_RECORDS_LIMIT} records per call.
|
|
727
|
+
*
|
|
728
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
729
|
+
* @returns Function that inserts records into the specified module
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```typescript
|
|
733
|
+
* const insertRecord = zohoRecruitInsertRecord(context);
|
|
734
|
+
*
|
|
735
|
+
* // Single record — returns details directly or throws on error:
|
|
736
|
+
* const details = await insertRecord({
|
|
737
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
738
|
+
* data: { First_Name: 'Jane', Last_Name: 'Doe', Email: 'jane@example.com' }
|
|
739
|
+
* });
|
|
740
|
+
*
|
|
741
|
+
* // Multiple records — returns paired success/error arrays:
|
|
742
|
+
* const result = await insertRecord({
|
|
743
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
744
|
+
* data: [
|
|
745
|
+
* { First_Name: 'Jane', Last_Name: 'Doe', Email: 'jane@example.com' },
|
|
746
|
+
* { First_Name: 'John', Last_Name: 'Doe', Email: 'john@example.com' }
|
|
747
|
+
* ]
|
|
748
|
+
* });
|
|
749
|
+
* ```
|
|
750
|
+
*
|
|
751
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/insert-records.html
|
|
598
752
|
*/
|
|
599
753
|
function zohoRecruitInsertRecord(context) {
|
|
600
754
|
return updateRecordLikeFunction$1(context, '', 'POST');
|
|
601
755
|
}
|
|
602
756
|
/**
|
|
603
|
-
*
|
|
757
|
+
* Creates a {@link ZohoRecruitUpsertRecordFunction} bound to the given context.
|
|
604
758
|
*
|
|
605
|
-
*
|
|
759
|
+
* Inserts or updates one or more records in a Recruit module based on whether
|
|
760
|
+
* each record includes an `id`. Uses the `/upsert` endpoint. Single-record
|
|
761
|
+
* calls return details directly or throw; multi-record calls return paired
|
|
762
|
+
* success/error arrays.
|
|
606
763
|
*
|
|
607
|
-
* @
|
|
608
|
-
*
|
|
764
|
+
* Maximum of {@link ZOHO_RECRUIT_CRUD_FUNCTION_MAX_RECORDS_LIMIT} records per call.
|
|
765
|
+
*
|
|
766
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
767
|
+
* @returns Function that upserts records in the specified module
|
|
768
|
+
*
|
|
769
|
+
* @example
|
|
770
|
+
* ```typescript
|
|
771
|
+
* const upsertRecord = zohoRecruitUpsertRecord(context);
|
|
772
|
+
*
|
|
773
|
+
* // Create (no id) — returns details directly:
|
|
774
|
+
* const created = await upsertRecord({
|
|
775
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
776
|
+
* data: { Email: 'new@example.com', Last_Name: 'New' }
|
|
777
|
+
* });
|
|
778
|
+
*
|
|
779
|
+
* // Update (with id) — returns details directly:
|
|
780
|
+
* const updated = await upsertRecord({
|
|
781
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
782
|
+
* data: { id: existingId, First_Name: 'Updated' }
|
|
783
|
+
* });
|
|
784
|
+
*
|
|
785
|
+
* // Mixed create and update — returns paired arrays:
|
|
786
|
+
* const result = await upsertRecord({
|
|
787
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
788
|
+
* data: [
|
|
789
|
+
* { Email: 'create@example.com', Last_Name: 'Create' },
|
|
790
|
+
* { id: existingId, First_Name: 'Update' }
|
|
791
|
+
* ]
|
|
792
|
+
* });
|
|
793
|
+
* ```
|
|
794
|
+
*
|
|
795
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/upsert-records.html
|
|
609
796
|
*/
|
|
610
797
|
function zohoRecruitUpsertRecord(context) {
|
|
611
798
|
return updateRecordLikeFunction$1(context, '/upsert', 'POST');
|
|
612
799
|
}
|
|
613
800
|
/**
|
|
614
|
-
*
|
|
801
|
+
* Creates a {@link ZohoRecruitUpdateRecordFunction} bound to the given context.
|
|
615
802
|
*
|
|
616
|
-
*
|
|
803
|
+
* Updates one or more existing records in a Recruit module. Each record must
|
|
804
|
+
* include an `id` field. Single-record calls return details directly or throw;
|
|
805
|
+
* multi-record calls return paired success/error arrays.
|
|
617
806
|
*
|
|
618
|
-
* @
|
|
619
|
-
*
|
|
807
|
+
* Maximum of {@link ZOHO_RECRUIT_CRUD_FUNCTION_MAX_RECORDS_LIMIT} records per call.
|
|
808
|
+
*
|
|
809
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
810
|
+
* @returns Function that updates records in the specified module
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* ```typescript
|
|
814
|
+
* const updateRecord = zohoRecruitUpdateRecord(context);
|
|
815
|
+
*
|
|
816
|
+
* // Single record — returns details directly:
|
|
817
|
+
* const details = await updateRecord({
|
|
818
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
819
|
+
* data: { id: recordId, First_Name: 'Updated Name' }
|
|
820
|
+
* });
|
|
821
|
+
*
|
|
822
|
+
* // Multiple records — returns paired arrays:
|
|
823
|
+
* const result = await updateRecord({
|
|
824
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
825
|
+
* data: [
|
|
826
|
+
* { id: recordId1, First_Name: 'Updated 1' },
|
|
827
|
+
* { id: recordId2, First_Name: 'Updated 2' }
|
|
828
|
+
* ]
|
|
829
|
+
* });
|
|
830
|
+
* ```
|
|
831
|
+
*
|
|
832
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/update-records.html
|
|
620
833
|
*/
|
|
621
834
|
function zohoRecruitUpdateRecord(context) {
|
|
622
835
|
return updateRecordLikeFunction$1(context, '', 'PUT');
|
|
623
836
|
}
|
|
624
837
|
/**
|
|
625
|
-
*
|
|
838
|
+
* Creates a {@link ZohoRecruitDeleteRecordFunction} bound to the given context.
|
|
626
839
|
*
|
|
627
|
-
*
|
|
840
|
+
* Deletes one or more records from a Recruit module by their IDs. Supports
|
|
841
|
+
* an optional `wf_trigger` flag to execute workflow rules on deletion. Returns
|
|
842
|
+
* a response with separated success and error entries.
|
|
628
843
|
*
|
|
629
|
-
* @param context
|
|
630
|
-
* @returns
|
|
844
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
845
|
+
* @returns Function that deletes records from the specified module
|
|
846
|
+
*
|
|
847
|
+
* @example
|
|
848
|
+
* ```typescript
|
|
849
|
+
* const deleteRecord = zohoRecruitDeleteRecord(context);
|
|
850
|
+
*
|
|
851
|
+
* const result = await deleteRecord({
|
|
852
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
853
|
+
* ids: candidateId
|
|
854
|
+
* });
|
|
855
|
+
* ```
|
|
856
|
+
*
|
|
857
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/delete-records.html
|
|
631
858
|
*/
|
|
632
859
|
function zohoRecruitDeleteRecord(context) {
|
|
633
860
|
return ({ ids, module, wf_trigger }) => {
|
|
@@ -635,12 +862,26 @@ function zohoRecruitDeleteRecord(context) {
|
|
|
635
862
|
};
|
|
636
863
|
}
|
|
637
864
|
/**
|
|
638
|
-
*
|
|
865
|
+
* Creates a {@link ZohoRecruitGetRecordByIdFunction} bound to the given context.
|
|
639
866
|
*
|
|
640
|
-
*
|
|
867
|
+
* Retrieves a single record from a Recruit module by its ID. The response is
|
|
868
|
+
* unwrapped from the standard data array, returning the record directly.
|
|
869
|
+
* Throws if the record is not found.
|
|
641
870
|
*
|
|
642
|
-
* @param context
|
|
643
|
-
* @returns
|
|
871
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
872
|
+
* @returns Function that retrieves a record by module name and ID
|
|
873
|
+
*
|
|
874
|
+
* @example
|
|
875
|
+
* ```typescript
|
|
876
|
+
* const getRecordById = zohoRecruitGetRecordById(context);
|
|
877
|
+
*
|
|
878
|
+
* const record = await getRecordById({
|
|
879
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
880
|
+
* id: candidateId
|
|
881
|
+
* });
|
|
882
|
+
* ```
|
|
883
|
+
*
|
|
884
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-records.html
|
|
644
885
|
*/
|
|
645
886
|
function zohoRecruitGetRecordById(context) {
|
|
646
887
|
return (input) => context
|
|
@@ -649,23 +890,61 @@ function zohoRecruitGetRecordById(context) {
|
|
|
649
890
|
.then((x) => x.data[0]);
|
|
650
891
|
}
|
|
651
892
|
/**
|
|
652
|
-
*
|
|
893
|
+
* Creates a {@link ZohoRecruitGetRecordsFunction} bound to the given context.
|
|
653
894
|
*
|
|
654
|
-
*
|
|
895
|
+
* Retrieves a paginated list of records from a Recruit module. Supports field
|
|
896
|
+
* selection, sorting, custom view filtering, territory filtering, and
|
|
897
|
+
* conversion/approval status filters via {@link ZohoRecruitGetRecordsInput}.
|
|
655
898
|
*
|
|
656
|
-
* @param context
|
|
657
|
-
* @returns
|
|
899
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
900
|
+
* @returns Function that retrieves paginated records from a module
|
|
901
|
+
*
|
|
902
|
+
* @example
|
|
903
|
+
* ```typescript
|
|
904
|
+
* const getRecords = zohoRecruitGetRecords(context);
|
|
905
|
+
*
|
|
906
|
+
* const page = await getRecords({
|
|
907
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
908
|
+
* per_page: 10
|
|
909
|
+
* });
|
|
910
|
+
* ```
|
|
911
|
+
*
|
|
912
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-records.html
|
|
658
913
|
*/
|
|
659
914
|
function zohoRecruitGetRecords(context) {
|
|
660
915
|
return ((input) => context.fetchJson(`/v2/${input.module}?${zohoRecruitUrlSearchParamsMinusModule(input).toString()}`, zohoRecruitApiFetchJsonInput('GET')));
|
|
661
916
|
}
|
|
662
917
|
/**
|
|
663
|
-
*
|
|
918
|
+
* Creates a {@link ZohoRecruitSearchRecordsFunction} bound to the given context.
|
|
664
919
|
*
|
|
665
|
-
*
|
|
920
|
+
* Searches records in a Recruit module using one of: criteria tree (compiled
|
|
921
|
+
* via {@link zohoRecruitSearchRecordsCriteriaString}), email, phone, or keyword.
|
|
922
|
+
* At least one search parameter must be provided. Returns a paginated result,
|
|
923
|
+
* defaulting to an empty data array when no matches are found.
|
|
666
924
|
*
|
|
667
|
-
* @param context
|
|
668
|
-
* @returns
|
|
925
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
926
|
+
* @returns Function that searches records in the specified module
|
|
927
|
+
* @throws {Error} If none of `criteria`, `email`, `phone`, or `word` are provided
|
|
928
|
+
*
|
|
929
|
+
* @example
|
|
930
|
+
* ```typescript
|
|
931
|
+
* const searchRecords = zohoRecruitSearchRecords(context);
|
|
932
|
+
*
|
|
933
|
+
* // Search by criteria:
|
|
934
|
+
* const result = await searchRecords({
|
|
935
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
936
|
+
* criteria: [{ field: 'Last_Name', filter: 'starts_with', value: 'Smith' }],
|
|
937
|
+
* per_page: 10
|
|
938
|
+
* });
|
|
939
|
+
*
|
|
940
|
+
* // Search by keyword:
|
|
941
|
+
* const wordResult = await searchRecords({
|
|
942
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
943
|
+
* word: 'engineer'
|
|
944
|
+
* });
|
|
945
|
+
* ```
|
|
946
|
+
*
|
|
947
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/search-records.html
|
|
669
948
|
*/
|
|
670
949
|
function zohoRecruitSearchRecords(context) {
|
|
671
950
|
function searchRecordsUrlSearchParams(input) {
|
|
@@ -683,16 +962,60 @@ function zohoRecruitSearchRecords(context) {
|
|
|
683
962
|
}
|
|
684
963
|
return ((input) => context.fetchJson(`/v2/${input.module}/search?${searchRecordsUrlSearchParams(input).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => x ?? { data: [], info: { more_records: false } }));
|
|
685
964
|
}
|
|
965
|
+
/**
|
|
966
|
+
* Creates a {@link ZohoRecruitSearchRecordsPageFactory} bound to the given context.
|
|
967
|
+
*
|
|
968
|
+
* Returns a page factory that automatically handles Zoho Recruit's pagination,
|
|
969
|
+
* making it easy to iterate through all search results across multiple pages.
|
|
970
|
+
*
|
|
971
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
972
|
+
* @returns Page factory for iterating over search results
|
|
973
|
+
*
|
|
974
|
+
* @example
|
|
975
|
+
* ```typescript
|
|
976
|
+
* const pageFactory = zohoRecruitSearchRecordsPageFactory(context);
|
|
977
|
+
*
|
|
978
|
+
* const fetchPage = pageFactory({
|
|
979
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
980
|
+
* criteria: [{ field: 'Last_Name', filter: 'starts_with', value: 'Smith' }],
|
|
981
|
+
* per_page: 5
|
|
982
|
+
* });
|
|
983
|
+
*
|
|
984
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
985
|
+
* const secondPage = await firstPage.fetchNext();
|
|
986
|
+
* ```
|
|
987
|
+
*/
|
|
686
988
|
function zohoRecruitSearchRecordsPageFactory(context) {
|
|
687
989
|
return zohoFetchPageFactory(zohoRecruitSearchRecords(context));
|
|
688
990
|
}
|
|
689
991
|
/**
|
|
690
|
-
* Creates a ZohoRecruitGetRelatedRecordsFunctionFactory
|
|
992
|
+
* Creates a {@link ZohoRecruitGetRelatedRecordsFunctionFactory} bound to the given context.
|
|
993
|
+
*
|
|
994
|
+
* Returns a factory that produces typed functions for fetching related records
|
|
995
|
+
* (e.g. Notes, Emails, Attachments) of a specific target module. The factory
|
|
996
|
+
* accepts a {@link ZohoRecruitGetRelatedRecordsFunctionConfig} to specify the
|
|
997
|
+
* target module and empty-result behavior. By default, returns an empty page
|
|
998
|
+
* result instead of null when no records are found.
|
|
999
|
+
*
|
|
1000
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1001
|
+
* @returns Factory that creates typed related-records retrieval functions
|
|
691
1002
|
*
|
|
692
|
-
*
|
|
1003
|
+
* @example
|
|
1004
|
+
* ```typescript
|
|
1005
|
+
* const factory = zohoRecruitGetRelatedRecordsFunctionFactory(context);
|
|
693
1006
|
*
|
|
694
|
-
*
|
|
695
|
-
*
|
|
1007
|
+
* // Create a typed function for fetching related Notes:
|
|
1008
|
+
* const getNotesForRecord = factory<ZohoRecruitRecordNote>({
|
|
1009
|
+
* targetModule: ZOHO_RECRUIT_NOTES_MODULE
|
|
1010
|
+
* });
|
|
1011
|
+
*
|
|
1012
|
+
* const notes = await getNotesForRecord({
|
|
1013
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1014
|
+
* id: candidateId
|
|
1015
|
+
* });
|
|
1016
|
+
* ```
|
|
1017
|
+
*
|
|
1018
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-related-records.html
|
|
696
1019
|
*/
|
|
697
1020
|
function zohoRecruitGetRelatedRecordsFunctionFactory(context) {
|
|
698
1021
|
return (config) => {
|
|
@@ -700,15 +1023,126 @@ function zohoRecruitGetRelatedRecordsFunctionFactory(context) {
|
|
|
700
1023
|
return (input) => context.fetchJson(`/v2/${input.module}/${input.id}/${targetModule}?${zohoRecruitUrlSearchParamsMinusIdAndModule(input, input.filter).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => x ?? (returnEmptyRecordsInsteadOfNull !== false ? emptyZohoPageResult() : x));
|
|
701
1024
|
};
|
|
702
1025
|
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Creates a {@link ZohoRecruitGetEmailsForRecordFunction} bound to the given context.
|
|
1028
|
+
*
|
|
1029
|
+
* Retrieves email metadata related to a specific record by targeting the
|
|
1030
|
+
* Emails module via the related records API. Returns a paginated result of
|
|
1031
|
+
* {@link ZohoRecruitRecordEmailMetadata} entries. When no emails exist for the
|
|
1032
|
+
* record, the result contains an empty data array rather than null.
|
|
1033
|
+
*
|
|
1034
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1035
|
+
* @returns Function that retrieves emails for a record
|
|
1036
|
+
*
|
|
1037
|
+
* @example
|
|
1038
|
+
* ```typescript
|
|
1039
|
+
* const getEmailsForRecord = zohoRecruitGetEmailsForRecord(context);
|
|
1040
|
+
*
|
|
1041
|
+
* const result = await getEmailsForRecord({
|
|
1042
|
+
* id: candidateId,
|
|
1043
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE
|
|
1044
|
+
* });
|
|
1045
|
+
* ```
|
|
1046
|
+
*
|
|
1047
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-related-records.html
|
|
1048
|
+
*/
|
|
703
1049
|
function zohoRecruitGetEmailsForRecord(context) {
|
|
704
1050
|
return zohoRecruitGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_RECRUIT_EMAILS_MODULE });
|
|
705
1051
|
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Creates a {@link ZohoRecruitGetEmailsForRecordPageFactory} bound to the given context.
|
|
1054
|
+
*
|
|
1055
|
+
* Returns a page factory for iterating over emails related to a record across
|
|
1056
|
+
* multiple pages. Wraps {@link zohoRecruitGetEmailsForRecord} with automatic
|
|
1057
|
+
* pagination handling via {@link zohoFetchPageFactory}.
|
|
1058
|
+
*
|
|
1059
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1060
|
+
* @returns Page factory for iterating over record emails
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* ```typescript
|
|
1064
|
+
* const pageFactory = zohoRecruitGetEmailsForRecordPageFactory(context);
|
|
1065
|
+
*
|
|
1066
|
+
* const fetchPage = pageFactory({
|
|
1067
|
+
* id: candidateId,
|
|
1068
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1069
|
+
* per_page: 5
|
|
1070
|
+
* });
|
|
1071
|
+
*
|
|
1072
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
1073
|
+
*
|
|
1074
|
+
* if (firstPage.result.info.more_records) {
|
|
1075
|
+
* const secondPage = await firstPage.fetchNext();
|
|
1076
|
+
* }
|
|
1077
|
+
* ```
|
|
1078
|
+
*
|
|
1079
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-related-records.html
|
|
1080
|
+
*/
|
|
706
1081
|
function zohoRecruitGetEmailsForRecordPageFactory(context) {
|
|
707
1082
|
return zohoFetchPageFactory(zohoRecruitGetEmailsForRecord(context));
|
|
708
1083
|
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Creates a {@link ZohoRecruitGetAttachmentsForRecordFunction} bound to the given context.
|
|
1086
|
+
*
|
|
1087
|
+
* Retrieves attachment metadata related to a specific record by targeting the
|
|
1088
|
+
* Attachments module via the related records API. Returns a paginated result of
|
|
1089
|
+
* {@link ZohoRecruitRecordAttachmentMetadata} entries including file names, sizes,
|
|
1090
|
+
* and category information. When no attachments exist for the record, the result
|
|
1091
|
+
* contains an empty data array rather than null.
|
|
1092
|
+
*
|
|
1093
|
+
* Each attachment entry includes a `$type` field that distinguishes between
|
|
1094
|
+
* directly uploaded attachments (`'Attachment'`) and linked attachments.
|
|
1095
|
+
*
|
|
1096
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1097
|
+
* @returns Function that retrieves attachments for a record
|
|
1098
|
+
*
|
|
1099
|
+
* @example
|
|
1100
|
+
* ```typescript
|
|
1101
|
+
* const getAttachmentsForRecord = zohoRecruitGetAttachmentsForRecord(context);
|
|
1102
|
+
*
|
|
1103
|
+
* const result = await getAttachmentsForRecord({
|
|
1104
|
+
* id: candidateId,
|
|
1105
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE
|
|
1106
|
+
* });
|
|
1107
|
+
*
|
|
1108
|
+
* // Filter to only directly uploaded attachments (downloadable):
|
|
1109
|
+
* const downloadable = result.data.filter((x) => x.$type === 'Attachment');
|
|
1110
|
+
* ```
|
|
1111
|
+
*
|
|
1112
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-related-records.html
|
|
1113
|
+
*/
|
|
709
1114
|
function zohoRecruitGetAttachmentsForRecord(context) {
|
|
710
1115
|
return zohoRecruitGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_RECRUIT_ATTACHMENTS_MODULE });
|
|
711
1116
|
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Creates a {@link ZohoRecruitGetAttachmentsForRecordPageFactory} bound to the given context.
|
|
1119
|
+
*
|
|
1120
|
+
* Returns a page factory for iterating over attachments related to a record
|
|
1121
|
+
* across multiple pages. Wraps {@link zohoRecruitGetAttachmentsForRecord} with
|
|
1122
|
+
* automatic pagination handling via {@link zohoFetchPageFactory}.
|
|
1123
|
+
*
|
|
1124
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1125
|
+
* @returns Page factory for iterating over record attachments
|
|
1126
|
+
*
|
|
1127
|
+
* @example
|
|
1128
|
+
* ```typescript
|
|
1129
|
+
* const pageFactory = zohoRecruitGetAttachmentsForRecordPageFactory(context);
|
|
1130
|
+
*
|
|
1131
|
+
* const fetchPage = pageFactory({
|
|
1132
|
+
* id: candidateId,
|
|
1133
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1134
|
+
* per_page: 10
|
|
1135
|
+
* });
|
|
1136
|
+
*
|
|
1137
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
1138
|
+
*
|
|
1139
|
+
* if (firstPage.result.info.more_records) {
|
|
1140
|
+
* const secondPage = await firstPage.fetchNext();
|
|
1141
|
+
* }
|
|
1142
|
+
* ```
|
|
1143
|
+
*
|
|
1144
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-related-records.html
|
|
1145
|
+
*/
|
|
712
1146
|
function zohoRecruitGetAttachmentsForRecordPageFactory(context) {
|
|
713
1147
|
return zohoFetchPageFactory(zohoRecruitGetAttachmentsForRecord(context));
|
|
714
1148
|
}
|
|
@@ -719,88 +1153,121 @@ function zohoRecruitGetAttachmentsForRecordPageFactory(context) {
|
|
|
719
1153
|
*/
|
|
720
1154
|
const ZOHO_RECRUIT_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
721
1155
|
/**
|
|
722
|
-
*
|
|
1156
|
+
* Creates a {@link ZohoRecruitUploadAttachmentForRecordFunction} bound to the given context.
|
|
723
1157
|
*
|
|
724
|
-
*
|
|
1158
|
+
* Uploads an attachment to a specific record. Supports either a direct
|
|
1159
|
+
* {@link File} upload (sent as multipart/form-data) or a URL from which Zoho
|
|
1160
|
+
* will fetch the file. An attachment category must be specified by ID or name.
|
|
1161
|
+
* Maximum file size is {@link ZOHO_RECRUIT_ATTACHMENT_MAX_SIZE} (20MB).
|
|
725
1162
|
*
|
|
726
|
-
* @param context
|
|
727
|
-
* @returns
|
|
1163
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1164
|
+
* @returns Function that uploads an attachment to a record
|
|
1165
|
+
* @throws {Error} If neither `file` nor `attachmentUrl` is provided
|
|
1166
|
+
* @throws {Error} If neither `attachmentCategoryId` nor `attachmentCategoryName` is provided
|
|
1167
|
+
*
|
|
1168
|
+
* @example
|
|
1169
|
+
* ```typescript
|
|
1170
|
+
* const uploadAttachment = zohoRecruitUploadAttachmentForRecord(context);
|
|
1171
|
+
*
|
|
1172
|
+
* // Upload a file directly:
|
|
1173
|
+
* await uploadAttachment({
|
|
1174
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1175
|
+
* id: candidateId,
|
|
1176
|
+
* file: new File(['content'], 'resume.pdf', { type: 'application/pdf' }),
|
|
1177
|
+
* attachmentCategoryName: 'Resume'
|
|
1178
|
+
* });
|
|
1179
|
+
*
|
|
1180
|
+
* // Upload from a URL:
|
|
1181
|
+
* await uploadAttachment({
|
|
1182
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1183
|
+
* id: candidateId,
|
|
1184
|
+
* attachmentUrl: 'https://example.com/document.pdf',
|
|
1185
|
+
* attachmentCategoryName: 'Others'
|
|
1186
|
+
* });
|
|
1187
|
+
* ```
|
|
1188
|
+
*
|
|
1189
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/upload-attachment.html
|
|
728
1190
|
*/
|
|
729
1191
|
function zohoRecruitUploadAttachmentForRecord(context) {
|
|
730
1192
|
return (input) => {
|
|
731
|
-
const { attachmentCategoryId, attachmentCategoryName,
|
|
1193
|
+
const { attachmentCategoryId, attachmentCategoryName, file, attachmentUrl } = input;
|
|
732
1194
|
const urlParams = {
|
|
733
1195
|
attachments_category_id: joinStringsWithCommas(attachmentCategoryId),
|
|
734
|
-
attachments_category: joinStringsWithCommas(attachmentCategoryName)
|
|
735
|
-
attachment_url: input.attachmentUrl
|
|
1196
|
+
attachments_category: joinStringsWithCommas(attachmentCategoryName)
|
|
736
1197
|
};
|
|
737
1198
|
if (!urlParams.attachments_category_id?.length && !urlParams.attachments_category?.length) {
|
|
738
1199
|
throw new Error('attachmentCategoryId or attachmentCategoryName must be provided and not empty.');
|
|
739
1200
|
}
|
|
740
|
-
|
|
741
|
-
|
|
1201
|
+
const url = `/v2/${input.module}/${input.id}/${ZOHO_RECRUIT_ATTACHMENTS_MODULE}?${makeUrlSearchParams(urlParams).toString()}`;
|
|
1202
|
+
if (file != null) {
|
|
1203
|
+
const body = new FormData();
|
|
1204
|
+
body.append('file', file);
|
|
1205
|
+
// Clear the base Content-Type header (empty string removes it via mergeRequestHeaders) so fetch auto-detects multipart/form-data with the correct boundary from the FormData body.
|
|
1206
|
+
return context.fetch(url, { method: 'POST', headers: { 'Content-Type': '' }, body });
|
|
742
1207
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
response = context.fetch(url, { method: 'POST' });
|
|
747
|
-
}
|
|
748
|
-
else if (formData != null) {
|
|
749
|
-
throw new Error('unsupported currently. Use the attachmentUrl parameter instead.');
|
|
750
|
-
// There is something weird going on with sending requests this way and zoho's server is rejecting it.
|
|
751
|
-
/*
|
|
752
|
-
response = context.fetch(url, {
|
|
753
|
-
method: 'POST',
|
|
754
|
-
headers: {
|
|
755
|
-
'Content-Type': 'multipart/form-data',
|
|
756
|
-
'content-length': '210'
|
|
757
|
-
},
|
|
758
|
-
body: formData
|
|
759
|
-
});
|
|
760
|
-
*/
|
|
761
|
-
/*
|
|
762
|
-
const fullUrl = (context.config.apiUrl as string) + url;
|
|
763
|
-
const accessToken = await context.accessTokenStringFactory();
|
|
764
|
-
|
|
765
|
-
response = fetch(fullUrl, {
|
|
766
|
-
headers: {
|
|
767
|
-
Authorization: `Bearer ${accessToken}`
|
|
768
|
-
},
|
|
769
|
-
body: formData,
|
|
770
|
-
method: 'POST'
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
console.log({ response });
|
|
774
|
-
*/
|
|
1208
|
+
else if (attachmentUrl) {
|
|
1209
|
+
const urlWithAttachment = `${url}&${makeUrlSearchParams({ attachment_url: attachmentUrl }).toString()}`;
|
|
1210
|
+
return context.fetch(urlWithAttachment, { method: 'POST' });
|
|
775
1211
|
}
|
|
776
1212
|
else {
|
|
777
|
-
throw new Error('
|
|
1213
|
+
throw new Error('file or attachmentUrl must be provided.');
|
|
778
1214
|
}
|
|
779
|
-
return response;
|
|
780
1215
|
};
|
|
781
1216
|
}
|
|
782
1217
|
/**
|
|
783
|
-
*
|
|
1218
|
+
* Creates a {@link ZohoRecruitDownloadAttachmentForRecordFunction} bound to the given context.
|
|
784
1219
|
*
|
|
785
|
-
*
|
|
1220
|
+
* Downloads a specific attachment from a record. Returns a parsed
|
|
1221
|
+
* {@link FetchFileResponse} containing the file data and metadata extracted
|
|
1222
|
+
* from the response headers.
|
|
786
1223
|
*
|
|
787
|
-
* @param context
|
|
788
|
-
* @returns
|
|
1224
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1225
|
+
* @returns Function that downloads an attachment by record and attachment ID
|
|
1226
|
+
*
|
|
1227
|
+
* @example
|
|
1228
|
+
* ```typescript
|
|
1229
|
+
* const downloadAttachment = zohoRecruitDownloadAttachmentForRecord(context);
|
|
1230
|
+
*
|
|
1231
|
+
* const fileResponse = await downloadAttachment({
|
|
1232
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1233
|
+
* id: candidateId,
|
|
1234
|
+
* attachment_id: attachmentId
|
|
1235
|
+
* });
|
|
1236
|
+
* ```
|
|
1237
|
+
*
|
|
1238
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/download-attachments.html
|
|
789
1239
|
*/
|
|
790
1240
|
function zohoRecruitDownloadAttachmentForRecord(context) {
|
|
791
1241
|
return (input) => context.fetch(`/v2/${input.module}/${input.id}/${ZOHO_RECRUIT_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'GET' }).then(parseFetchFileResponse);
|
|
792
1242
|
}
|
|
793
1243
|
/**
|
|
794
|
-
*
|
|
1244
|
+
* Creates a {@link ZohoRecruitDeleteAttachmentFromRecordFunction} bound to the given context.
|
|
795
1245
|
*
|
|
796
|
-
*
|
|
1246
|
+
* Deletes a specific attachment from a record by its attachment ID.
|
|
1247
|
+
* Returns the raw {@link Response}.
|
|
797
1248
|
*
|
|
798
|
-
* @param context
|
|
799
|
-
* @returns
|
|
1249
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1250
|
+
* @returns Function that deletes an attachment by record and attachment ID
|
|
1251
|
+
*
|
|
1252
|
+
* @example
|
|
1253
|
+
* ```typescript
|
|
1254
|
+
* const deleteAttachment = zohoRecruitDeleteAttachmentFromRecord(context);
|
|
1255
|
+
*
|
|
1256
|
+
* const response = await deleteAttachment({
|
|
1257
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1258
|
+
* id: candidateId,
|
|
1259
|
+
* attachment_id: attachmentId
|
|
1260
|
+
* });
|
|
1261
|
+
* ```
|
|
1262
|
+
*
|
|
1263
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/delete-attachments.html
|
|
800
1264
|
*/
|
|
801
1265
|
function zohoRecruitDeleteAttachmentFromRecord(context) {
|
|
802
1266
|
return (input) => context.fetch(`/v2/${input.module}/${input.id}/${ZOHO_RECRUIT_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'DELETE' });
|
|
803
1267
|
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Thrown when a Zoho Recruit serverless function execution fails, wrapping the error response with the API error code and message.
|
|
1270
|
+
*/
|
|
804
1271
|
class ZohoRecruitExecuteRestApiFunctionError extends BaseError {
|
|
805
1272
|
error;
|
|
806
1273
|
constructor(error) {
|
|
@@ -809,15 +1276,39 @@ class ZohoRecruitExecuteRestApiFunctionError extends BaseError {
|
|
|
809
1276
|
}
|
|
810
1277
|
}
|
|
811
1278
|
/**
|
|
812
|
-
* Creates a
|
|
1279
|
+
* Creates a function that executes Zoho Recruit serverless functions via the REST API.
|
|
1280
|
+
*
|
|
1281
|
+
* Supports both OAuth-based and API-key-based authentication. When using an API key, a custom target URL can be specified for cross-environment calls.
|
|
813
1282
|
*
|
|
814
1283
|
* OAuth Details:
|
|
815
1284
|
* - https://www.zoho.com/crm/developer/docs/functions/serverless-fn-oauth.html#OAuth2
|
|
816
1285
|
* - There is no documentation for ZohoRecruit specifically, but it seems to behave the same way
|
|
817
1286
|
* - You will need the following scopes: ZohoRecruit.functions.execute.READ,ZohoRecruit.functions.execute.CREATE
|
|
818
1287
|
*
|
|
819
|
-
* @param context
|
|
820
|
-
* @returns
|
|
1288
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1289
|
+
* @returns Function that executes serverless functions via the REST API
|
|
1290
|
+
* @throws {ZohoRecruitExecuteRestApiFunctionError} If the function execution fails
|
|
1291
|
+
*
|
|
1292
|
+
* @example
|
|
1293
|
+
* ```typescript
|
|
1294
|
+
* const executeFunction = zohoRecruitExecuteRestApiFunction(context);
|
|
1295
|
+
*
|
|
1296
|
+
* // Execute using OAuth credentials:
|
|
1297
|
+
* const result = await executeFunction({ functionName: 'my_function' });
|
|
1298
|
+
*
|
|
1299
|
+
* // Execute with parameters:
|
|
1300
|
+
* const paramResult = await executeFunction({
|
|
1301
|
+
* functionName: 'process_candidate',
|
|
1302
|
+
* params: { candidate_id: '12345', action: 'approve' }
|
|
1303
|
+
* });
|
|
1304
|
+
*
|
|
1305
|
+
* // Execute using an API key (cross-environment):
|
|
1306
|
+
* const apiResult = await executeFunction({
|
|
1307
|
+
* functionName: 'my_function',
|
|
1308
|
+
* apiKey: 'your-api-key',
|
|
1309
|
+
* apiUrl: 'production'
|
|
1310
|
+
* });
|
|
1311
|
+
* ```
|
|
821
1312
|
*/
|
|
822
1313
|
function zohoRecruitExecuteRestApiFunction(context) {
|
|
823
1314
|
return (input) => {
|
|
@@ -839,9 +1330,15 @@ function zohoRecruitExecuteRestApiFunction(context) {
|
|
|
839
1330
|
};
|
|
840
1331
|
}
|
|
841
1332
|
// MARK: Util
|
|
1333
|
+
/**
|
|
1334
|
+
* Builds URL search params from input objects, omitting the `module` key since it is used in the URL path rather than query string.
|
|
1335
|
+
*/
|
|
842
1336
|
function zohoRecruitUrlSearchParamsMinusModule(...input) {
|
|
843
1337
|
return makeUrlSearchParams(input, { omitKeys: 'module' });
|
|
844
1338
|
}
|
|
1339
|
+
/**
|
|
1340
|
+
* Builds URL search params from input objects, omitting both `id` and `module` keys since they are used in the URL path.
|
|
1341
|
+
*/
|
|
845
1342
|
function zohoRecruitUrlSearchParamsMinusIdAndModule(...input) {
|
|
846
1343
|
return makeUrlSearchParams(input, { omitKeys: ['id', 'module'] });
|
|
847
1344
|
}
|
|
@@ -849,6 +1346,9 @@ function zohoRecruitUrlSearchParamsMinusIdAndModule(...input) {
|
|
|
849
1346
|
* @deprecated use makeUrlSearchParams instead.
|
|
850
1347
|
*/
|
|
851
1348
|
const zohoRecruitUrlSearchParams = makeUrlSearchParams;
|
|
1349
|
+
/**
|
|
1350
|
+
* Constructs a standard {@link FetchJsonInput} for Zoho Recruit API calls with the given HTTP method and optional body.
|
|
1351
|
+
*/
|
|
852
1352
|
function zohoRecruitApiFetchJsonInput(method, body) {
|
|
853
1353
|
const result = {
|
|
854
1354
|
method,
|
|
@@ -856,6 +1356,28 @@ function zohoRecruitApiFetchJsonInput(method, body) {
|
|
|
856
1356
|
};
|
|
857
1357
|
return result;
|
|
858
1358
|
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Separates a change response's entries into success and error arrays based on their status.
|
|
1361
|
+
*
|
|
1362
|
+
* Iterates over the `data` array from a Zoho Recruit change operation response and
|
|
1363
|
+
* partitions entries into `successItems` and `errorItems` based on their `status` field.
|
|
1364
|
+
* The original response is spread into the result, so all original fields remain accessible.
|
|
1365
|
+
*
|
|
1366
|
+
* Used internally by {@link zohoRecruitDeleteRecord} and similar functions to provide
|
|
1367
|
+
* convenient access to separated success/error results.
|
|
1368
|
+
*
|
|
1369
|
+
* @param response - Raw change operation response containing mixed success/error entries
|
|
1370
|
+
* @returns The response augmented with pre-separated `successItems` and `errorItems` arrays
|
|
1371
|
+
*
|
|
1372
|
+
* @example
|
|
1373
|
+
* ```typescript
|
|
1374
|
+
* const rawResponse = await context.fetchJson<ZohoRecruitChangeObjectLikeResponse>(...);
|
|
1375
|
+
* const result = zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs(rawResponse);
|
|
1376
|
+
*
|
|
1377
|
+
* result.successItems; // entries with status === 'success'
|
|
1378
|
+
* result.errorItems; // entries with non-success status
|
|
1379
|
+
* ```
|
|
1380
|
+
*/
|
|
859
1381
|
function zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs(response) {
|
|
860
1382
|
const { data } = response;
|
|
861
1383
|
const successItems = [];
|
|
@@ -875,6 +1397,20 @@ function zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs(response) {
|
|
|
875
1397
|
};
|
|
876
1398
|
return result;
|
|
877
1399
|
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Pairs each input record with its corresponding API result and separates them into success and error arrays by status.
|
|
1402
|
+
*
|
|
1403
|
+
* Iterates over the `input` and `results` arrays in parallel, matching each input record
|
|
1404
|
+
* to its positional result. Entries are classified as success or error based on
|
|
1405
|
+
* the result's `status` field matching {@link ZOHO_SUCCESS_STATUS}.
|
|
1406
|
+
*
|
|
1407
|
+
* Used internally by {@link updateRecordLikeFunction} to pair input data with API outcomes
|
|
1408
|
+
* for insert, update, and upsert operations.
|
|
1409
|
+
*
|
|
1410
|
+
* @param input - Array of input records that were submitted to the API
|
|
1411
|
+
* @param results - Array of per-record results returned by the API, positionally aligned with `input`
|
|
1412
|
+
* @returns Object with `successItems` and `errorItems`, each containing paired `{ input, result }` entries
|
|
1413
|
+
*/
|
|
878
1414
|
function zohoRecruitMultiRecordResult(input, results) {
|
|
879
1415
|
const successItems = [];
|
|
880
1416
|
const errorItems = [];
|
|
@@ -971,10 +1507,9 @@ const executeRestApiFunction = zohoRecruitExecuteRestApiFunction;
|
|
|
971
1507
|
/**
|
|
972
1508
|
* Associates one or more candidates with one or more job openings.
|
|
973
1509
|
*
|
|
974
|
-
*
|
|
1510
|
+
* The result separates "already associated" errors from other errors, allowing callers to treat duplicate associations as non-fatal.
|
|
975
1511
|
*
|
|
976
|
-
*
|
|
977
|
-
* @returns
|
|
1512
|
+
* https://www.zoho.com/recruit/developer-guide/apiv2/associate-candidate.html
|
|
978
1513
|
*/
|
|
979
1514
|
function zohoRecruitAssociateCandidateRecordsWithJobOpenings(context) {
|
|
980
1515
|
return (input) => context.fetchJson(`/v2/${ZOHO_RECRUIT_CANDIDATES_MODULE}/actions/associate`, zohoRecruitApiFetchJsonInput('PUT', { data: asArray(input) })).then((x) => {
|
|
@@ -991,6 +1526,9 @@ function zohoRecruitAssociateCandidateRecordsWithJobOpenings(context) {
|
|
|
991
1526
|
};
|
|
992
1527
|
});
|
|
993
1528
|
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Searches for records associated with a given candidate or job opening. Returns an empty page result when no records are found.
|
|
1531
|
+
*/
|
|
994
1532
|
function zohoRecruitSearchAssociatedRecords(context) {
|
|
995
1533
|
return (input) => {
|
|
996
1534
|
return context.fetchJson(`/v2/${input.module}/${input.id}/associate?${zohoRecruitUrlSearchParamsMinusIdAndModule(input).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => {
|
|
@@ -999,6 +1537,9 @@ function zohoRecruitSearchAssociatedRecords(context) {
|
|
|
999
1537
|
});
|
|
1000
1538
|
};
|
|
1001
1539
|
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Searches for job openings associated with a specific candidate.
|
|
1542
|
+
*/
|
|
1002
1543
|
function zohoRecruitSearchCandidateAssociatedJobOpeningRecords(context) {
|
|
1003
1544
|
const searchAssociatedRecordsFactory = zohoRecruitSearchAssociatedRecords(context);
|
|
1004
1545
|
return (input) => {
|
|
@@ -1008,9 +1549,15 @@ function zohoRecruitSearchCandidateAssociatedJobOpeningRecords(context) {
|
|
|
1008
1549
|
});
|
|
1009
1550
|
};
|
|
1010
1551
|
}
|
|
1552
|
+
/**
|
|
1553
|
+
* Creates a page factory for paginating over job openings associated with a candidate.
|
|
1554
|
+
*/
|
|
1011
1555
|
function zohoRecruitSearchCandidateAssociatedJobOpeningRecordsPageFactory(context) {
|
|
1012
1556
|
return zohoFetchPageFactory(zohoRecruitSearchCandidateAssociatedJobOpeningRecords(context));
|
|
1013
1557
|
}
|
|
1558
|
+
/**
|
|
1559
|
+
* Searches for candidates associated with a specific job opening.
|
|
1560
|
+
*/
|
|
1014
1561
|
function zohoRecruitSearchJobOpeningAssociatedCandidateRecords(context, jobOpeningModuleName = ZOHO_RECRUIT_JOB_OPENINGS_MODULE) {
|
|
1015
1562
|
const searchAssociatedRecordsFactory = zohoRecruitSearchAssociatedRecords(context);
|
|
1016
1563
|
return (input) => {
|
|
@@ -1020,26 +1567,124 @@ function zohoRecruitSearchJobOpeningAssociatedCandidateRecords(context, jobOpeni
|
|
|
1020
1567
|
});
|
|
1021
1568
|
};
|
|
1022
1569
|
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Creates a page factory for paginating over candidates associated with a job opening.
|
|
1572
|
+
*/
|
|
1023
1573
|
function zohoRecruitSearchJobOpeningAssociatedCandidateRecordsPageFactory(context) {
|
|
1024
1574
|
return zohoFetchPageFactory(zohoRecruitSearchJobOpeningAssociatedCandidateRecords(context));
|
|
1025
1575
|
}
|
|
1026
1576
|
|
|
1577
|
+
/**
|
|
1578
|
+
* Creates a {@link ZohoRecruitCreateNotesFunction} bound to the given context.
|
|
1579
|
+
*
|
|
1580
|
+
* Creates one or more notes directly in the Notes module. Each note entry must include
|
|
1581
|
+
* `se_module` and `Parent_Id` to link the note to a record.
|
|
1582
|
+
*
|
|
1583
|
+
* Prefer {@link zohoRecruitCreateNotesForRecord} when creating notes linked to a specific
|
|
1584
|
+
* record, as it handles the module/parent linking automatically.
|
|
1585
|
+
*
|
|
1586
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1587
|
+
* @returns Function that creates notes in the Notes module
|
|
1588
|
+
*
|
|
1589
|
+
* @example
|
|
1590
|
+
* ```typescript
|
|
1591
|
+
* const createNotes = zohoRecruitCreateNotes(context);
|
|
1592
|
+
*
|
|
1593
|
+
* const result = await createNotes({
|
|
1594
|
+
* data: [{
|
|
1595
|
+
* Note_Title: 'Interview Notes',
|
|
1596
|
+
* Note_Content: 'Strong candidate',
|
|
1597
|
+
* se_module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1598
|
+
* Parent_Id: candidateId
|
|
1599
|
+
* }]
|
|
1600
|
+
* });
|
|
1601
|
+
* ```
|
|
1602
|
+
*/
|
|
1027
1603
|
function zohoRecruitCreateNotes(context) {
|
|
1028
1604
|
return (input) => context.fetchJson(`/v2/${ZOHO_RECRUIT_NOTES_MODULE}`, zohoRecruitApiFetchJsonInput('POST', { data: input.data })).then((x) => {
|
|
1029
1605
|
return zohoRecruitMultiRecordResult(asArray(input.data), x.data);
|
|
1030
1606
|
});
|
|
1031
1607
|
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Creates a {@link ZohoRecruitDeleteNotesFunction} bound to the given context.
|
|
1610
|
+
*
|
|
1611
|
+
* Deletes one or more notes by their IDs from the Notes module. Returns a paired
|
|
1612
|
+
* success/error result for each note ID.
|
|
1613
|
+
*
|
|
1614
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1615
|
+
* @returns Function that deletes notes by ID
|
|
1616
|
+
*
|
|
1617
|
+
* @example
|
|
1618
|
+
* ```typescript
|
|
1619
|
+
* const deleteNotes = zohoRecruitDeleteNotes(context);
|
|
1620
|
+
*
|
|
1621
|
+
* const result = await deleteNotes({ ids: [noteId1, noteId2] });
|
|
1622
|
+
* ```
|
|
1623
|
+
*/
|
|
1032
1624
|
function zohoRecruitDeleteNotes(context) {
|
|
1033
1625
|
return (input) => context.fetchJson(`/v2/${ZOHO_RECRUIT_NOTES_MODULE}?${makeUrlSearchParams({ ids: input.ids })}`, zohoRecruitApiFetchJsonInput('DELETE')).then((x) => {
|
|
1034
1626
|
return zohoRecruitMultiRecordResult(asArray(input.ids), x.data);
|
|
1035
1627
|
});
|
|
1036
1628
|
}
|
|
1629
|
+
/**
|
|
1630
|
+
* Creates a {@link ZohoRecruitGetNotesForRecordFunction} bound to the given context.
|
|
1631
|
+
*
|
|
1632
|
+
* Retrieves notes related to a specific record by targeting the Notes module
|
|
1633
|
+
* via the related records API. Returns an empty page result when no notes exist.
|
|
1634
|
+
*
|
|
1635
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1636
|
+
* @returns Function that retrieves notes for a record
|
|
1637
|
+
*
|
|
1638
|
+
* @example
|
|
1639
|
+
* ```typescript
|
|
1640
|
+
* const getNotesForRecord = zohoRecruitGetNotesForRecord(context);
|
|
1641
|
+
*
|
|
1642
|
+
* const result = await getNotesForRecord({
|
|
1643
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1644
|
+
* id: candidateId
|
|
1645
|
+
* });
|
|
1646
|
+
* ```
|
|
1647
|
+
*/
|
|
1037
1648
|
function zohoRecruitGetNotesForRecord(context) {
|
|
1038
1649
|
return zohoRecruitGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_RECRUIT_NOTES_MODULE });
|
|
1039
1650
|
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Creates a {@link ZohoRecruitGetNotesForRecordPageFactory} bound to the given context.
|
|
1653
|
+
*
|
|
1654
|
+
* Returns a page factory for iterating over notes related to a record across
|
|
1655
|
+
* multiple pages. Wraps {@link zohoRecruitGetNotesForRecord} with automatic
|
|
1656
|
+
* pagination handling via {@link zohoFetchPageFactory}.
|
|
1657
|
+
*
|
|
1658
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1659
|
+
* @returns Page factory for iterating over record notes
|
|
1660
|
+
*/
|
|
1040
1661
|
function zohoRecruitGetNotesForRecordPageFactory(context) {
|
|
1041
1662
|
return zohoFetchPageFactory(zohoRecruitGetNotesForRecord(context));
|
|
1042
1663
|
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Creates a {@link ZohoRecruitCreateNotesForRecordFunction} bound to the given context.
|
|
1666
|
+
*
|
|
1667
|
+
* Creates one or more notes linked to a specific record. Automatically sets
|
|
1668
|
+
* `se_module` and `Parent_Id` on each note entry from the request's `module` and `id`,
|
|
1669
|
+
* then delegates to {@link zohoRecruitCreateNotes}.
|
|
1670
|
+
*
|
|
1671
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1672
|
+
* @returns Function that creates notes linked to a specific record
|
|
1673
|
+
*
|
|
1674
|
+
* @example
|
|
1675
|
+
* ```typescript
|
|
1676
|
+
* const createNotesForRecord = zohoRecruitCreateNotesForRecord(context);
|
|
1677
|
+
*
|
|
1678
|
+
* const result = await createNotesForRecord({
|
|
1679
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1680
|
+
* id: candidateId,
|
|
1681
|
+
* notes: {
|
|
1682
|
+
* Note_Title: 'Interview Notes',
|
|
1683
|
+
* Note_Content: 'Strong candidate for the role.'
|
|
1684
|
+
* }
|
|
1685
|
+
* });
|
|
1686
|
+
* ```
|
|
1687
|
+
*/
|
|
1043
1688
|
function zohoRecruitCreateNotesForRecord(context) {
|
|
1044
1689
|
const createNotesInstance = zohoRecruitCreateNotes(context);
|
|
1045
1690
|
return (input) => {
|
|
@@ -1076,6 +1721,30 @@ const getNotesForRecordPageFactory = zohoRecruitGetNotesForRecordPageFactory;
|
|
|
1076
1721
|
*/
|
|
1077
1722
|
const createNotesForRecord = zohoRecruitCreateNotesForRecord;
|
|
1078
1723
|
|
|
1724
|
+
/**
|
|
1725
|
+
* Creates a {@link ZohoRecruitCreateTagsFunction} bound to the given context.
|
|
1726
|
+
*
|
|
1727
|
+
* Creates one or more tags for a module. The result separates duplicate tag errors
|
|
1728
|
+
* (which are often non-fatal) from other errors, making it easy to handle the common
|
|
1729
|
+
* case where a tag already exists.
|
|
1730
|
+
*
|
|
1731
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1732
|
+
* @returns Function that creates tags in the specified module
|
|
1733
|
+
*
|
|
1734
|
+
* @example
|
|
1735
|
+
* ```typescript
|
|
1736
|
+
* const createTags = zohoRecruitCreateTagsForModule(context);
|
|
1737
|
+
*
|
|
1738
|
+
* const result = await createTags({
|
|
1739
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1740
|
+
* tags: [{ name: 'Interviewed' }, { name: 'Priority', color_code: '#FF0000' }]
|
|
1741
|
+
* });
|
|
1742
|
+
*
|
|
1743
|
+
* // Duplicate tags are separated for convenience:
|
|
1744
|
+
* result.duplicateErrorItems; // tags that already existed
|
|
1745
|
+
* result.errorItems; // other (real) errors
|
|
1746
|
+
* ```
|
|
1747
|
+
*/
|
|
1079
1748
|
function zohoRecruitCreateTagsForModule(context) {
|
|
1080
1749
|
return (input) => context.fetchJson(`/v2/settings/tags?${makeUrlSearchParams({ module: input.module })}`, zohoRecruitApiFetchJsonInput('POST', { tags: asArray(input.tags) })).then((x) => {
|
|
1081
1750
|
const result = zohoRecruitMultiRecordResult(asArray(input.tags), x.tags);
|
|
@@ -1091,12 +1760,24 @@ function zohoRecruitCreateTagsForModule(context) {
|
|
|
1091
1760
|
});
|
|
1092
1761
|
}
|
|
1093
1762
|
/**
|
|
1094
|
-
*
|
|
1763
|
+
* Creates a {@link ZohoRecruitGetTagsFunction} bound to the given context.
|
|
1095
1764
|
*
|
|
1096
|
-
*
|
|
1765
|
+
* Returns the list of tags within a module. Normalizes the non-standard API response
|
|
1766
|
+
* that returns data under a `tags` key instead of the standard `data` key.
|
|
1097
1767
|
*
|
|
1098
|
-
* @param context
|
|
1099
|
-
* @returns
|
|
1768
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1769
|
+
* @returns Function that retrieves tags for a module
|
|
1770
|
+
*
|
|
1771
|
+
* @example
|
|
1772
|
+
* ```typescript
|
|
1773
|
+
* const getTags = zohoRecruitGetTagsForModule(context);
|
|
1774
|
+
*
|
|
1775
|
+
* const result = await getTags({
|
|
1776
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE
|
|
1777
|
+
* });
|
|
1778
|
+
* ```
|
|
1779
|
+
*
|
|
1780
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/get-tag-list.html
|
|
1100
1781
|
*/
|
|
1101
1782
|
function zohoRecruitGetTagsForModule(context) {
|
|
1102
1783
|
return (input) => context.fetchJson(`/v2/settings/tags?${makeUrlSearchParams({ module: input.module, my_tags: input.my_tags })}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => {
|
|
@@ -1107,21 +1788,45 @@ function zohoRecruitGetTagsForModule(context) {
|
|
|
1107
1788
|
};
|
|
1108
1789
|
});
|
|
1109
1790
|
}
|
|
1791
|
+
/**
|
|
1792
|
+
* Creates a {@link ZohoRecruitGetTagsForModulePageFactory} bound to the given context.
|
|
1793
|
+
*
|
|
1794
|
+
* Returns a page factory for iterating over tags in a module across multiple pages.
|
|
1795
|
+
* Wraps {@link zohoRecruitGetTagsForModule} with automatic pagination handling.
|
|
1796
|
+
*
|
|
1797
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1798
|
+
* @returns Page factory for iterating over module tags
|
|
1799
|
+
*/
|
|
1110
1800
|
function zohoRecruitGetTagsForModulePageFactory(context) {
|
|
1111
1801
|
return zohoFetchPageFactory(zohoRecruitGetTagsForModule(context));
|
|
1112
1802
|
}
|
|
1113
1803
|
// MARK: Add Tag To Record
|
|
1114
1804
|
/**
|
|
1115
|
-
*
|
|
1805
|
+
* Maximum number of record ids allowed when adding tags, enforced by the Zoho Recruit API.
|
|
1116
1806
|
*/
|
|
1117
1807
|
const ZOHO_RECRUIT_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
1118
1808
|
/**
|
|
1119
|
-
*
|
|
1809
|
+
* Creates a {@link ZohoRecruitAddTagsToRecordsFunction} bound to the given context.
|
|
1120
1810
|
*
|
|
1121
|
-
*
|
|
1811
|
+
* Adds one or more tags to one or more records. Returns a paired success/error result
|
|
1812
|
+
* for each record. Maximum of {@link ZOHO_RECRUIT_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED} (100) record IDs per call.
|
|
1122
1813
|
*
|
|
1123
|
-
* @param context
|
|
1124
|
-
* @returns
|
|
1814
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1815
|
+
* @returns Function that adds tags to records
|
|
1816
|
+
* @throws {Error} If more than 100 record IDs are provided
|
|
1817
|
+
*
|
|
1818
|
+
* @example
|
|
1819
|
+
* ```typescript
|
|
1820
|
+
* const addTags = zohoRecruitAddTagsToRecords(context);
|
|
1821
|
+
*
|
|
1822
|
+
* const result = await addTags({
|
|
1823
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1824
|
+
* tag_names: ['Interviewed', 'Priority'],
|
|
1825
|
+
* ids: [candidateId1, candidateId2]
|
|
1826
|
+
* });
|
|
1827
|
+
* ```
|
|
1828
|
+
*
|
|
1829
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/add-tags.html
|
|
1125
1830
|
*/
|
|
1126
1831
|
function zohoRecruitAddTagsToRecords(context) {
|
|
1127
1832
|
return (input) => {
|
|
@@ -1136,16 +1841,31 @@ function zohoRecruitAddTagsToRecords(context) {
|
|
|
1136
1841
|
}
|
|
1137
1842
|
// MARK: Remove Tag From Record
|
|
1138
1843
|
/**
|
|
1139
|
-
*
|
|
1844
|
+
* Maximum number of record ids allowed when removing tags, enforced by the Zoho Recruit API.
|
|
1140
1845
|
*/
|
|
1141
1846
|
const ZOHO_RECRUIT_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
1142
1847
|
/**
|
|
1143
|
-
*
|
|
1848
|
+
* Creates a {@link ZohoRecruitRemoveTagsFromRecordsFunction} bound to the given context.
|
|
1144
1849
|
*
|
|
1145
|
-
*
|
|
1850
|
+
* Removes one or more tags from one or more records. Returns a paired success/error result
|
|
1851
|
+
* for each record. Maximum of {@link ZOHO_RECRUIT_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED} (100) record IDs per call.
|
|
1146
1852
|
*
|
|
1147
|
-
* @param context
|
|
1148
|
-
* @returns
|
|
1853
|
+
* @param context - Authenticated Zoho Recruit context providing fetch and rate limiting
|
|
1854
|
+
* @returns Function that removes tags from records
|
|
1855
|
+
* @throws {Error} If more than 100 record IDs are provided
|
|
1856
|
+
*
|
|
1857
|
+
* @example
|
|
1858
|
+
* ```typescript
|
|
1859
|
+
* const removeTags = zohoRecruitRemoveTagsFromRecords(context);
|
|
1860
|
+
*
|
|
1861
|
+
* const result = await removeTags({
|
|
1862
|
+
* module: ZOHO_RECRUIT_CANDIDATES_MODULE,
|
|
1863
|
+
* tag_names: 'Interviewed',
|
|
1864
|
+
* ids: candidateId
|
|
1865
|
+
* });
|
|
1866
|
+
* ```
|
|
1867
|
+
*
|
|
1868
|
+
* @see https://www.zoho.com/recruit/developer-guide/apiv2/remove-tags.html
|
|
1149
1869
|
*/
|
|
1150
1870
|
function zohoRecruitRemoveTagsFromRecords(context) {
|
|
1151
1871
|
return (input) => {
|
|
@@ -1248,16 +1968,39 @@ function zohoAccessTokenStringFactory(zohoAccessTokenFactory) {
|
|
|
1248
1968
|
};
|
|
1249
1969
|
}
|
|
1250
1970
|
|
|
1971
|
+
/**
|
|
1972
|
+
* Default handler that logs a warning to the console when the Zoho API rate limit is exceeded.
|
|
1973
|
+
*/
|
|
1251
1974
|
const DEFAULT_ZOHO_RATE_LIMITED_TOO_MANY_REQUETS_LOG_FUNCTION = (headers) => {
|
|
1252
1975
|
console.warn(`zohoRateLimitedFetchHandler(): Too many requests made. The limit is ${headers.limit} requests per reset period. Will be reset at ${headers.resetAt}.`);
|
|
1253
1976
|
};
|
|
1977
|
+
/**
|
|
1978
|
+
* Creates a {@link ZohoRateLimitedFetchHandler} that throttles outgoing requests based on
|
|
1979
|
+
* Zoho's rate limit headers (`X-RATELIMIT-LIMIT`, `X-RATELIMIT-REMAINING`, `X-RATELIMIT-RESET`).
|
|
1980
|
+
*
|
|
1981
|
+
* The handler uses an exponential backoff strategy with the following behavior:
|
|
1982
|
+
* - Rate limiting begins after 10% of the allowed requests have been made (`startLimitAt`)
|
|
1983
|
+
* - Wait times increase exponentially (rate 1.08) as more requests are made, capped at 10 seconds
|
|
1984
|
+
* - On each response, the limiter updates its remaining count and reset time from headers
|
|
1985
|
+
* - When the API returns a different limit than configured, the limiter dynamically adjusts
|
|
1986
|
+
* - On 429 responses, the request is automatically retried after the rate limiter delay
|
|
1987
|
+
* - The limiter is disabled when responses lack rate limit headers (e.g., error responses)
|
|
1988
|
+
*
|
|
1989
|
+
* @param config - Optional configuration for rate limit, reset period, and 429 handling
|
|
1990
|
+
* @returns A rate-limited fetch handler with the underlying rate limiter accessible via `_rateLimiter`
|
|
1991
|
+
*/
|
|
1254
1992
|
function zohoRateLimitedFetchHandler(config) {
|
|
1255
1993
|
const onTooManyRequests = config?.onTooManyRequests !== false ? (config?.onTooManyRequests ?? DEFAULT_ZOHO_RATE_LIMITED_TOO_MANY_REQUETS_LOG_FUNCTION) : undefined;
|
|
1256
1994
|
const defaultLimit = config?.maxRateLimit ?? DEFAULT_ZOHO_API_RATE_LIMIT;
|
|
1257
1995
|
const defaultResetPeriod = config?.resetPeriod ?? DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD;
|
|
1996
|
+
/**
|
|
1997
|
+
* Builds a rate limiter config derived from the given limit.
|
|
1998
|
+
* Called once at initialization with `defaultLimit`, and again dynamically
|
|
1999
|
+
* when the API's `X-RATELIMIT-LIMIT` header reports a different value.
|
|
2000
|
+
*/
|
|
1258
2001
|
function configForLimit(limit, resetAt) {
|
|
1259
2002
|
return {
|
|
1260
|
-
limit
|
|
2003
|
+
limit,
|
|
1261
2004
|
startLimitAt: Math.ceil(limit / 10), // can do 10% of the requests of the limit before rate limiting begins
|
|
1262
2005
|
cooldownRate: 1.2 * (limit / (defaultResetPeriod / MS_IN_SECOND)),
|
|
1263
2006
|
exponentRate: 1.08,
|
|
@@ -1270,6 +2013,10 @@ function zohoRateLimitedFetchHandler(config) {
|
|
|
1270
2013
|
const rateLimiter = resetPeriodPromiseRateLimiter(defaultConfig);
|
|
1271
2014
|
return rateLimitedFetchHandler({
|
|
1272
2015
|
rateLimiter,
|
|
2016
|
+
/**
|
|
2017
|
+
* Inspects each response for Zoho rate limit headers and updates the limiter accordingly.
|
|
2018
|
+
* Returns `true` to signal a retry when a 429 status is received.
|
|
2019
|
+
*/
|
|
1273
2020
|
updateWithResponse: function (response, fetchResponseError) {
|
|
1274
2021
|
const hasLimitHeader = response.headers.has(ZOHO_RATE_LIMIT_REMAINING_HEADER);
|
|
1275
2022
|
let shouldRetry = false;
|
|
@@ -1278,7 +2025,7 @@ function zohoRateLimitedFetchHandler(config) {
|
|
|
1278
2025
|
const headerDetails = zohoRateLimitHeaderDetails(response.headers);
|
|
1279
2026
|
if (headerDetails) {
|
|
1280
2027
|
const { limit, resetAt, remaining } = headerDetails;
|
|
1281
|
-
if (limit !== defaultLimit) {
|
|
2028
|
+
if (limit && limit !== defaultLimit) {
|
|
1282
2029
|
const newConfig = configForLimit(limit, resetAt);
|
|
1283
2030
|
rateLimiter.setConfig(newConfig, false);
|
|
1284
2031
|
}
|
|
@@ -1301,6 +2048,31 @@ function zohoRateLimitedFetchHandler(config) {
|
|
|
1301
2048
|
});
|
|
1302
2049
|
}
|
|
1303
2050
|
|
|
2051
|
+
/**
|
|
2052
|
+
* Creates a {@link ZohoRecruitFactory} from the given configuration.
|
|
2053
|
+
*
|
|
2054
|
+
* The factory pre-initializes shared resources (access token provider, rate limiter)
|
|
2055
|
+
* once, then produces {@link ZohoRecruit} client instances for each {@link ZohoRecruitConfig}.
|
|
2056
|
+
* Each client handles OAuth token refresh on {@link ZohoInvalidTokenError}, rate limiting,
|
|
2057
|
+
* and Zoho Recruit's non-standard error responses (200 status with error body).
|
|
2058
|
+
*
|
|
2059
|
+
* @param factoryConfig - Configuration providing account credentials and optional overrides
|
|
2060
|
+
* @returns A factory function that creates authenticated Zoho Recruit clients
|
|
2061
|
+
*
|
|
2062
|
+
* @example
|
|
2063
|
+
* ```typescript
|
|
2064
|
+
* const factory = zohoRecruitFactory({
|
|
2065
|
+
* accountsContext: zohoAccountsApi.accountsContext
|
|
2066
|
+
* });
|
|
2067
|
+
*
|
|
2068
|
+
* const zohoRecruit = factory({
|
|
2069
|
+
* apiUrl: 'https://recruit.zoho.com'
|
|
2070
|
+
* });
|
|
2071
|
+
*
|
|
2072
|
+
* // Use the recruit context for API calls:
|
|
2073
|
+
* const { recruitContext } = zohoRecruit;
|
|
2074
|
+
* ```
|
|
2075
|
+
*/
|
|
1304
2076
|
function zohoRecruitFactory(factoryConfig) {
|
|
1305
2077
|
const { accountsContext } = factoryConfig;
|
|
1306
2078
|
const accessTokenStringFactory = zohoAccessTokenStringFactory(accountsContext.loadAccessToken);
|
|
@@ -1355,7 +2127,13 @@ function zohoRecruitFactory(factoryConfig) {
|
|
|
1355
2127
|
*/
|
|
1356
2128
|
const ZOHO_RECRUIT_TAG_NAME_MAX_LENGTH = 25;
|
|
1357
2129
|
|
|
2130
|
+
/**
|
|
2131
|
+
* Service identifier used for Zoho CRM API access token resolution and service routing.
|
|
2132
|
+
*/
|
|
1358
2133
|
const ZOHO_CRM_SERVICE_NAME = 'crm';
|
|
2134
|
+
/**
|
|
2135
|
+
* Resolves a CRM API URL input to its full base URL. Well-known keys ('sandbox', 'production') map to their respective Zoho CRM endpoints; custom URLs pass through unchanged.
|
|
2136
|
+
*/
|
|
1359
2137
|
function zohoCrmConfigApiUrl(input) {
|
|
1360
2138
|
switch (input) {
|
|
1361
2139
|
case 'sandbox':
|
|
@@ -1398,16 +2176,41 @@ const isZohoCrmValidUrl = isStandardInternetAccessibleWebsiteUrl;
|
|
|
1398
2176
|
const ZOHO_CRM_RECORD_ATTACHMENT_METADATA_ATTACH_TYPE_RESUME = 'Resume';
|
|
1399
2177
|
|
|
1400
2178
|
/**
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1403
|
-
* https://www.zoho.com/crm/developer/docs/api/v8/search-records.html
|
|
2179
|
+
* Maximum number of criteria allowed per CRM search query (10).
|
|
1404
2180
|
*
|
|
1405
2181
|
* "You can search for a maximum of 10 criteria (with the same or different column) with equals and starts_with conditions."
|
|
2182
|
+
*
|
|
2183
|
+
* Re-exports {@link MAX_ZOHO_SEARCH_MODULE_RECORDS_CRITERIA}.
|
|
2184
|
+
*
|
|
2185
|
+
* @see https://www.zoho.com/crm/developer/docs/api/v8/search-records.html
|
|
1406
2186
|
*/
|
|
1407
2187
|
const MAX_ZOHO_CRM_SEARCH_MODULE_RECORDS_CRITERIA = MAX_ZOHO_SEARCH_MODULE_RECORDS_CRITERIA;
|
|
2188
|
+
/**
|
|
2189
|
+
* CRM-specific re-export of {@link zohoSearchRecordsCriteriaString}.
|
|
2190
|
+
*
|
|
2191
|
+
* Compiles a criteria tree element (entry array, nested tree, or raw string) into a
|
|
2192
|
+
* URL-ready criteria string. Returns `undefined` when the input is nullish or empty.
|
|
2193
|
+
*/
|
|
1408
2194
|
const zohoCrmSearchRecordsCriteriaString = zohoSearchRecordsCriteriaString;
|
|
2195
|
+
/**
|
|
2196
|
+
* CRM-specific re-export of {@link zohoSearchRecordsCriteriaStringForTree}.
|
|
2197
|
+
*
|
|
2198
|
+
* Compiles a {@link ZohoCrmSearchRecordsCriteriaTree} into a criteria string by
|
|
2199
|
+
* recursively resolving nested AND/OR groups.
|
|
2200
|
+
*/
|
|
1409
2201
|
const zohoCrmSearchRecordsCriteriaStringForTree = zohoSearchRecordsCriteriaStringForTree;
|
|
2202
|
+
/**
|
|
2203
|
+
* CRM-specific re-export of {@link escapeZohoFieldValueForCriteriaString}.
|
|
2204
|
+
*
|
|
2205
|
+
* Escapes parentheses and commas in a field value for use in a criteria string.
|
|
2206
|
+
*/
|
|
1410
2207
|
const escapeZohoCrmFieldValueForCriteriaString = escapeZohoFieldValueForCriteriaString;
|
|
2208
|
+
/**
|
|
2209
|
+
* CRM-specific re-export of {@link zohoSearchRecordsCriteriaEntryToCriteriaString}.
|
|
2210
|
+
*
|
|
2211
|
+
* Converts a single criteria entry into a parenthesized criteria string
|
|
2212
|
+
* in the format `(field:filter:escapedValue)`.
|
|
2213
|
+
*/
|
|
1411
2214
|
const zohoCrmSearchRecordsCriteriaEntryToCriteriaString = zohoSearchRecordsCriteriaEntryToCriteriaString;
|
|
1412
2215
|
|
|
1413
2216
|
/**
|
|
@@ -1428,19 +2231,37 @@ class ZohoCrmRecordNoContentError extends BaseError {
|
|
|
1428
2231
|
this.recordId = recordId;
|
|
1429
2232
|
}
|
|
1430
2233
|
}
|
|
2234
|
+
/**
|
|
2235
|
+
* Base error for Zoho CRM record CRUD operations. Wraps the server-provided error data including field-level details.
|
|
2236
|
+
*/
|
|
1431
2237
|
class ZohoCrmRecordCrudError extends ZohoServerError {
|
|
1432
2238
|
}
|
|
2239
|
+
/**
|
|
2240
|
+
* Thrown when a CRM create/update request is missing a required field defined in the module layout.
|
|
2241
|
+
*/
|
|
1433
2242
|
class ZohoCrmRecordCrudMandatoryFieldNotFoundError extends ZohoCrmRecordCrudError {
|
|
1434
2243
|
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Thrown when a CRM create/update request would produce a duplicate record based on unique field constraints.
|
|
2246
|
+
*/
|
|
1435
2247
|
class ZohoCrmRecordCrudDuplicateDataError extends ZohoCrmRecordCrudError {
|
|
1436
2248
|
}
|
|
2249
|
+
/**
|
|
2250
|
+
* Thrown when a CRM request contains invalid field data. Provides access to the offending field details via {@link invalidFieldDetails}.
|
|
2251
|
+
*/
|
|
1437
2252
|
class ZohoCrmRecordCrudInvalidDataError extends ZohoCrmRecordCrudError {
|
|
1438
2253
|
get invalidFieldDetails() {
|
|
1439
2254
|
return this.error.details;
|
|
1440
2255
|
}
|
|
1441
2256
|
}
|
|
2257
|
+
/**
|
|
2258
|
+
* Thrown when an invalid data error targets the 'id' field, indicating the referenced record does not exist.
|
|
2259
|
+
*/
|
|
1442
2260
|
class ZohoCrmRecordCrudNoMatchingRecordError extends ZohoCrmRecordCrudInvalidDataError {
|
|
1443
2261
|
}
|
|
2262
|
+
/**
|
|
2263
|
+
* Maps a Zoho CRM server error to the appropriate typed {@link ZohoCrmRecordCrudError} subclass based on the error code and affected field.
|
|
2264
|
+
*/
|
|
1444
2265
|
function zohoCrmRecordCrudError(error) {
|
|
1445
2266
|
let result;
|
|
1446
2267
|
switch (error.code) {
|
|
@@ -1465,6 +2286,9 @@ function zohoCrmRecordCrudError(error) {
|
|
|
1465
2286
|
}
|
|
1466
2287
|
return result;
|
|
1467
2288
|
}
|
|
2289
|
+
/**
|
|
2290
|
+
* Returns an assertion function that throws {@link ZohoCrmRecordNoContentError} when a data array result is empty or null, typically indicating a missing record.
|
|
2291
|
+
*/
|
|
1468
2292
|
function assertZohoCrmRecordDataArrayResultHasContent(moduleName, recordId) {
|
|
1469
2293
|
return (x) => {
|
|
1470
2294
|
if (x == null || !x.data?.length) {
|
|
@@ -1475,7 +2299,13 @@ function assertZohoCrmRecordDataArrayResultHasContent(moduleName, recordId) {
|
|
|
1475
2299
|
}
|
|
1476
2300
|
};
|
|
1477
2301
|
}
|
|
2302
|
+
/**
|
|
2303
|
+
* Pre-configured console logger for Zoho CRM server errors. Data array errors are suppressed since they are handled separately by CRUD error classes.
|
|
2304
|
+
*/
|
|
1478
2305
|
const logZohoCrmErrorToConsole = logZohoServerErrorFunction('ZohoCrm', { logDataArrayErrors: false });
|
|
2306
|
+
/**
|
|
2307
|
+
* Parses a fetch response error into a typed Zoho CRM server error by extracting and interpreting the JSON error body.
|
|
2308
|
+
*/
|
|
1479
2309
|
async function parseZohoCrmError(responseError) {
|
|
1480
2310
|
const data = await responseError.response.json().catch((x) => undefined);
|
|
1481
2311
|
let result;
|
|
@@ -1484,6 +2314,9 @@ async function parseZohoCrmError(responseError) {
|
|
|
1484
2314
|
}
|
|
1485
2315
|
return result;
|
|
1486
2316
|
}
|
|
2317
|
+
/**
|
|
2318
|
+
* Parses a Zoho CRM error response body into a typed error. Delegates to CRM-specific error code handling before falling back to the generic Zoho error parser.
|
|
2319
|
+
*/
|
|
1487
2320
|
function parseZohoCrmServerErrorResponseData(errorResponseData, responseError) {
|
|
1488
2321
|
let result;
|
|
1489
2322
|
const error = tryFindZohoServerErrorData(errorResponseData, responseError);
|
|
@@ -1498,7 +2331,13 @@ function parseZohoCrmServerErrorResponseData(errorResponseData, responseError) {
|
|
|
1498
2331
|
}
|
|
1499
2332
|
return result;
|
|
1500
2333
|
}
|
|
2334
|
+
/**
|
|
2335
|
+
* Fetch response interceptor that detects Zoho CRM error payloads hidden within HTTP 200 responses and converts them into proper errors.
|
|
2336
|
+
*/
|
|
1501
2337
|
const interceptZohoCrm200StatusWithErrorResponse = interceptZohoErrorResponseFactory(parseZohoCrmServerErrorResponseData);
|
|
2338
|
+
/**
|
|
2339
|
+
* Wraps a fetch function with Zoho CRM error parsing and console logging, ensuring all CRM API errors are surfaced as typed exceptions.
|
|
2340
|
+
*/
|
|
1502
2341
|
const handleZohoCrmErrorFetch = handleZohoErrorFetchFactory(parseZohoCrmError, logZohoCrmErrorToConsole);
|
|
1503
2342
|
|
|
1504
2343
|
// MARK: Insert/Update/Upsert Response
|
|
@@ -1509,9 +2348,10 @@ const handleZohoCrmErrorFetch = handleZohoErrorFetchFactory(parseZohoCrmError, l
|
|
|
1509
2348
|
*/
|
|
1510
2349
|
const ZOHO_CRM_CRUD_FUNCTION_MAX_RECORDS_LIMIT = 100;
|
|
1511
2350
|
/**
|
|
1512
|
-
*
|
|
2351
|
+
* Shared implementation for the Insert, Upsert, and Update endpoints, which all share the same request/response structure.
|
|
1513
2352
|
*
|
|
1514
|
-
*
|
|
2353
|
+
* When a single record is provided, the function returns the change details directly or throws on error.
|
|
2354
|
+
* When multiple records are provided, it returns a paired success/error result.
|
|
1515
2355
|
*/
|
|
1516
2356
|
function updateRecordLikeFunction(context, fetchUrlPrefix, fetchMethod) {
|
|
1517
2357
|
return (({ data, module }) => context
|
|
@@ -1535,45 +2375,145 @@ function updateRecordLikeFunction(context, fetchUrlPrefix, fetchMethod) {
|
|
|
1535
2375
|
}));
|
|
1536
2376
|
}
|
|
1537
2377
|
/**
|
|
1538
|
-
*
|
|
2378
|
+
* Creates a {@link ZohoCrmInsertRecordFunction} bound to the given context.
|
|
1539
2379
|
*
|
|
1540
|
-
*
|
|
2380
|
+
* Inserts one or more records into a CRM module. When a single record is
|
|
2381
|
+
* provided, returns the {@link ZohoCrmChangeObjectDetails} directly or
|
|
2382
|
+
* throws on error. When multiple records are provided, returns a
|
|
2383
|
+
* {@link ZohoCrmUpdateRecordResult} with paired success/error arrays.
|
|
1541
2384
|
*
|
|
1542
|
-
* @
|
|
1543
|
-
*
|
|
2385
|
+
* Maximum of {@link ZOHO_CRM_CRUD_FUNCTION_MAX_RECORDS_LIMIT} records per call.
|
|
2386
|
+
*
|
|
2387
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2388
|
+
* @returns Function that inserts records into the specified module
|
|
2389
|
+
*
|
|
2390
|
+
* @example
|
|
2391
|
+
* ```typescript
|
|
2392
|
+
* const insertRecord = zohoCrmInsertRecord(context);
|
|
2393
|
+
*
|
|
2394
|
+
* // Single record — returns details directly or throws on error:
|
|
2395
|
+
* const details = await insertRecord({
|
|
2396
|
+
* module: 'Contacts',
|
|
2397
|
+
* data: { First_Name: 'Jane', Last_Name: 'Doe', Email: 'jane@example.com' }
|
|
2398
|
+
* });
|
|
2399
|
+
*
|
|
2400
|
+
* // Multiple records — returns paired success/error arrays:
|
|
2401
|
+
* const result = await insertRecord({
|
|
2402
|
+
* module: 'Contacts',
|
|
2403
|
+
* data: [
|
|
2404
|
+
* { First_Name: 'Jane', Last_Name: 'Doe', Email: 'jane@example.com' },
|
|
2405
|
+
* { First_Name: 'John', Last_Name: 'Doe', Email: 'john@example.com' }
|
|
2406
|
+
* ]
|
|
2407
|
+
* });
|
|
2408
|
+
* ```
|
|
2409
|
+
*
|
|
2410
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/insert-records.html
|
|
1544
2411
|
*/
|
|
1545
2412
|
function zohoCrmInsertRecord(context) {
|
|
1546
2413
|
return updateRecordLikeFunction(context, '', 'POST');
|
|
1547
2414
|
}
|
|
1548
2415
|
/**
|
|
1549
|
-
*
|
|
2416
|
+
* Creates a {@link ZohoCrmUpsertRecordFunction} bound to the given context.
|
|
1550
2417
|
*
|
|
1551
|
-
*
|
|
2418
|
+
* Inserts or updates one or more records in a CRM module based on whether
|
|
2419
|
+
* each record includes an `id`. Uses the `/upsert` endpoint. Single-record
|
|
2420
|
+
* calls return details directly or throw; multi-record calls return paired
|
|
2421
|
+
* success/error arrays.
|
|
1552
2422
|
*
|
|
1553
|
-
* @
|
|
1554
|
-
*
|
|
2423
|
+
* Maximum of {@link ZOHO_CRM_CRUD_FUNCTION_MAX_RECORDS_LIMIT} records per call.
|
|
2424
|
+
*
|
|
2425
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2426
|
+
* @returns Function that upserts records in the specified module
|
|
2427
|
+
*
|
|
2428
|
+
* @example
|
|
2429
|
+
* ```typescript
|
|
2430
|
+
* const upsertRecord = zohoCrmUpsertRecord(context);
|
|
2431
|
+
*
|
|
2432
|
+
* // Create (no id) — returns details directly:
|
|
2433
|
+
* const created = await upsertRecord({
|
|
2434
|
+
* module: 'Contacts',
|
|
2435
|
+
* data: { Email: 'new@example.com', Last_Name: 'New' }
|
|
2436
|
+
* });
|
|
2437
|
+
*
|
|
2438
|
+
* // Update (with id) — returns details directly:
|
|
2439
|
+
* const updated = await upsertRecord({
|
|
2440
|
+
* module: 'Contacts',
|
|
2441
|
+
* data: { id: existingId, First_Name: 'Updated' }
|
|
2442
|
+
* });
|
|
2443
|
+
*
|
|
2444
|
+
* // Mixed create and update — returns paired arrays:
|
|
2445
|
+
* const result = await upsertRecord({
|
|
2446
|
+
* module: 'Contacts',
|
|
2447
|
+
* data: [
|
|
2448
|
+
* { Email: 'create@example.com', Last_Name: 'Create' },
|
|
2449
|
+
* { id: existingId, First_Name: 'Update' }
|
|
2450
|
+
* ]
|
|
2451
|
+
* });
|
|
2452
|
+
* ```
|
|
2453
|
+
*
|
|
2454
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/upsert-records.html
|
|
1555
2455
|
*/
|
|
1556
2456
|
function zohoCrmUpsertRecord(context) {
|
|
1557
2457
|
return updateRecordLikeFunction(context, '/upsert', 'POST');
|
|
1558
2458
|
}
|
|
1559
2459
|
/**
|
|
1560
|
-
*
|
|
2460
|
+
* Creates a {@link ZohoCrmUpdateRecordFunction} bound to the given context.
|
|
1561
2461
|
*
|
|
1562
|
-
*
|
|
2462
|
+
* Updates one or more existing records in a CRM module. Each record must
|
|
2463
|
+
* include an `id` field. Single-record calls return details directly or throw;
|
|
2464
|
+
* multi-record calls return paired success/error arrays.
|
|
1563
2465
|
*
|
|
1564
|
-
* @
|
|
1565
|
-
*
|
|
2466
|
+
* Maximum of {@link ZOHO_CRM_CRUD_FUNCTION_MAX_RECORDS_LIMIT} records per call.
|
|
2467
|
+
*
|
|
2468
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2469
|
+
* @returns Function that updates records in the specified module
|
|
2470
|
+
*
|
|
2471
|
+
* @example
|
|
2472
|
+
* ```typescript
|
|
2473
|
+
* const updateRecord = zohoCrmUpdateRecord(context);
|
|
2474
|
+
*
|
|
2475
|
+
* // Single record — returns details directly:
|
|
2476
|
+
* const details = await updateRecord({
|
|
2477
|
+
* module: 'Contacts',
|
|
2478
|
+
* data: { id: recordId, First_Name: 'Updated Name' }
|
|
2479
|
+
* });
|
|
2480
|
+
*
|
|
2481
|
+
* // Multiple records — returns paired arrays:
|
|
2482
|
+
* const result = await updateRecord({
|
|
2483
|
+
* module: 'Contacts',
|
|
2484
|
+
* data: [
|
|
2485
|
+
* { id: recordId1, First_Name: 'Updated 1' },
|
|
2486
|
+
* { id: recordId2, First_Name: 'Updated 2' }
|
|
2487
|
+
* ]
|
|
2488
|
+
* });
|
|
2489
|
+
* ```
|
|
2490
|
+
*
|
|
2491
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/update-records.html
|
|
1566
2492
|
*/
|
|
1567
2493
|
function zohoCrmUpdateRecord(context) {
|
|
1568
2494
|
return updateRecordLikeFunction(context, '', 'PUT');
|
|
1569
2495
|
}
|
|
1570
2496
|
/**
|
|
1571
|
-
*
|
|
2497
|
+
* Creates a {@link ZohoCrmDeleteRecordFunction} bound to the given context.
|
|
1572
2498
|
*
|
|
1573
|
-
*
|
|
2499
|
+
* Deletes one or more records from a CRM module by their IDs. Supports
|
|
2500
|
+
* an optional `wf_trigger` flag to execute workflow rules on deletion. Returns
|
|
2501
|
+
* a response with separated success and error entries.
|
|
1574
2502
|
*
|
|
1575
|
-
* @param context
|
|
1576
|
-
* @returns
|
|
2503
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2504
|
+
* @returns Function that deletes records from the specified module
|
|
2505
|
+
*
|
|
2506
|
+
* @example
|
|
2507
|
+
* ```typescript
|
|
2508
|
+
* const deleteRecord = zohoCrmDeleteRecord(context);
|
|
2509
|
+
*
|
|
2510
|
+
* const result = await deleteRecord({
|
|
2511
|
+
* module: 'Contacts',
|
|
2512
|
+
* ids: contactId
|
|
2513
|
+
* });
|
|
2514
|
+
* ```
|
|
2515
|
+
*
|
|
2516
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/delete-records.html
|
|
1577
2517
|
*/
|
|
1578
2518
|
function zohoCrmDeleteRecord(context) {
|
|
1579
2519
|
return ({ ids, module, wf_trigger }) => {
|
|
@@ -1584,12 +2524,26 @@ function zohoCrmDeleteRecord(context) {
|
|
|
1584
2524
|
};
|
|
1585
2525
|
}
|
|
1586
2526
|
/**
|
|
1587
|
-
*
|
|
2527
|
+
* Creates a {@link ZohoCrmGetRecordByIdFunction} bound to the given context.
|
|
1588
2528
|
*
|
|
1589
|
-
*
|
|
2529
|
+
* Retrieves a single record from a CRM module by its ID. The response is
|
|
2530
|
+
* unwrapped from the standard data array, returning the record directly.
|
|
2531
|
+
* Throws if the record is not found.
|
|
1590
2532
|
*
|
|
1591
|
-
* @param context
|
|
1592
|
-
* @returns
|
|
2533
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2534
|
+
* @returns Function that retrieves a record by module name and ID
|
|
2535
|
+
*
|
|
2536
|
+
* @example
|
|
2537
|
+
* ```typescript
|
|
2538
|
+
* const getRecordById = zohoCrmGetRecordById(context);
|
|
2539
|
+
*
|
|
2540
|
+
* const record = await getRecordById({
|
|
2541
|
+
* module: 'Contacts',
|
|
2542
|
+
* id: contactId
|
|
2543
|
+
* });
|
|
2544
|
+
* ```
|
|
2545
|
+
*
|
|
2546
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/get-records.html
|
|
1593
2547
|
*/
|
|
1594
2548
|
function zohoCrmGetRecordById(context) {
|
|
1595
2549
|
return (input) => context
|
|
@@ -1598,23 +2552,62 @@ function zohoCrmGetRecordById(context) {
|
|
|
1598
2552
|
.then((x) => x.data[0]);
|
|
1599
2553
|
}
|
|
1600
2554
|
/**
|
|
1601
|
-
*
|
|
2555
|
+
* Creates a {@link ZohoCrmGetRecordsFunction} bound to the given context.
|
|
1602
2556
|
*
|
|
1603
|
-
*
|
|
2557
|
+
* Retrieves a paginated list of records from a CRM module. Supports field
|
|
2558
|
+
* selection, sorting, custom view filtering, territory filtering, and
|
|
2559
|
+
* conversion/approval status filters via {@link ZohoCrmGetRecordsInput}.
|
|
1604
2560
|
*
|
|
1605
|
-
* @param context
|
|
1606
|
-
* @returns
|
|
2561
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2562
|
+
* @returns Function that retrieves paginated records from a module
|
|
2563
|
+
*
|
|
2564
|
+
* @example
|
|
2565
|
+
* ```typescript
|
|
2566
|
+
* const getRecords = zohoCrmGetRecords(context);
|
|
2567
|
+
*
|
|
2568
|
+
* const page = await getRecords({
|
|
2569
|
+
* module: 'Contacts',
|
|
2570
|
+
* fields: 'First_Name,Last_Name,Email',
|
|
2571
|
+
* per_page: 10
|
|
2572
|
+
* });
|
|
2573
|
+
* ```
|
|
2574
|
+
*
|
|
2575
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/get-records.html
|
|
1607
2576
|
*/
|
|
1608
2577
|
function zohoCrmGetRecords(context) {
|
|
1609
2578
|
return ((input) => context.fetchJson(`/v8/${input.module}?${zohoCrmUrlSearchParamsMinusModule(input).toString()}`, zohoCrmApiFetchJsonInput('GET')));
|
|
1610
2579
|
}
|
|
1611
2580
|
/**
|
|
1612
|
-
*
|
|
2581
|
+
* Creates a {@link ZohoCrmSearchRecordsFunction} bound to the given context.
|
|
1613
2582
|
*
|
|
1614
|
-
*
|
|
2583
|
+
* Searches records in a CRM module using one of: criteria tree (compiled
|
|
2584
|
+
* via {@link zohoCrmSearchRecordsCriteriaString}), email, phone, cvid, or keyword.
|
|
2585
|
+
* At least one search parameter must be provided. Returns a paginated result,
|
|
2586
|
+
* defaulting to an empty data array when no matches are found.
|
|
1615
2587
|
*
|
|
1616
|
-
* @param context
|
|
1617
|
-
* @returns
|
|
2588
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2589
|
+
* @returns Function that searches records in the specified module
|
|
2590
|
+
* @throws {Error} If none of `criteria`, `email`, `phone`, `cvid`, or `word` are provided
|
|
2591
|
+
*
|
|
2592
|
+
* @example
|
|
2593
|
+
* ```typescript
|
|
2594
|
+
* const searchRecords = zohoCrmSearchRecords(context);
|
|
2595
|
+
*
|
|
2596
|
+
* // Search by criteria:
|
|
2597
|
+
* const result = await searchRecords({
|
|
2598
|
+
* module: 'Contacts',
|
|
2599
|
+
* criteria: [{ field: 'Last_Name', filter: 'starts_with', value: 'Smith' }],
|
|
2600
|
+
* per_page: 10
|
|
2601
|
+
* });
|
|
2602
|
+
*
|
|
2603
|
+
* // Search by keyword:
|
|
2604
|
+
* const wordResult = await searchRecords({
|
|
2605
|
+
* module: 'Contacts',
|
|
2606
|
+
* word: 'engineer'
|
|
2607
|
+
* });
|
|
2608
|
+
* ```
|
|
2609
|
+
*
|
|
2610
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/search-records.html
|
|
1618
2611
|
*/
|
|
1619
2612
|
function zohoCrmSearchRecords(context) {
|
|
1620
2613
|
function searchRecordsUrlSearchParams(input) {
|
|
@@ -1632,16 +2625,60 @@ function zohoCrmSearchRecords(context) {
|
|
|
1632
2625
|
}
|
|
1633
2626
|
return ((input) => context.fetchJson(`/v8/${input.module}/search?${searchRecordsUrlSearchParams(input).toString()}`, zohoCrmApiFetchJsonInput('GET')).then((x) => x ?? { data: [], info: { more_records: false } }));
|
|
1634
2627
|
}
|
|
2628
|
+
/**
|
|
2629
|
+
* Creates a {@link ZohoCrmSearchRecordsPageFactory} bound to the given context.
|
|
2630
|
+
*
|
|
2631
|
+
* Returns a page factory that automatically handles Zoho CRM's pagination,
|
|
2632
|
+
* making it easy to iterate through all search results across multiple pages.
|
|
2633
|
+
*
|
|
2634
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2635
|
+
* @returns Page factory for iterating over search results
|
|
2636
|
+
*
|
|
2637
|
+
* @example
|
|
2638
|
+
* ```typescript
|
|
2639
|
+
* const pageFactory = zohoCrmSearchRecordsPageFactory(context);
|
|
2640
|
+
*
|
|
2641
|
+
* const fetchPage = pageFactory({
|
|
2642
|
+
* module: 'Contacts',
|
|
2643
|
+
* criteria: [{ field: 'Last_Name', filter: 'starts_with', value: 'Smith' }],
|
|
2644
|
+
* per_page: 5
|
|
2645
|
+
* });
|
|
2646
|
+
*
|
|
2647
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
2648
|
+
* const secondPage = await firstPage.fetchNext();
|
|
2649
|
+
* ```
|
|
2650
|
+
*/
|
|
1635
2651
|
function zohoCrmSearchRecordsPageFactory(context) {
|
|
1636
2652
|
return zohoFetchPageFactory(zohoCrmSearchRecords(context));
|
|
1637
2653
|
}
|
|
1638
2654
|
/**
|
|
1639
|
-
* Creates a ZohoCrmGetRelatedRecordsFunctionFactory
|
|
2655
|
+
* Creates a {@link ZohoCrmGetRelatedRecordsFunctionFactory} bound to the given context.
|
|
2656
|
+
*
|
|
2657
|
+
* Returns a factory that produces typed functions for fetching related records
|
|
2658
|
+
* (e.g. Notes, Emails, Attachments) of a specific target module. The factory
|
|
2659
|
+
* accepts a {@link ZohoCrmGetRelatedRecordsFunctionConfig} to specify the
|
|
2660
|
+
* target module and empty-result behavior. By default, returns an empty page
|
|
2661
|
+
* result instead of null when no records are found.
|
|
2662
|
+
*
|
|
2663
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2664
|
+
* @returns Factory that creates typed related-records retrieval functions
|
|
2665
|
+
*
|
|
2666
|
+
* @example
|
|
2667
|
+
* ```typescript
|
|
2668
|
+
* const factory = zohoCrmGetRelatedRecordsFunctionFactory(context);
|
|
1640
2669
|
*
|
|
1641
|
-
*
|
|
2670
|
+
* // Create a typed function for fetching related Notes:
|
|
2671
|
+
* const getNotesForRecord = factory<ZohoCrmRecordNote>({
|
|
2672
|
+
* targetModule: ZOHO_CRM_NOTES_MODULE
|
|
2673
|
+
* });
|
|
1642
2674
|
*
|
|
1643
|
-
*
|
|
1644
|
-
*
|
|
2675
|
+
* const notes = await getNotesForRecord({
|
|
2676
|
+
* module: 'Contacts',
|
|
2677
|
+
* id: contactId
|
|
2678
|
+
* });
|
|
2679
|
+
* ```
|
|
2680
|
+
*
|
|
2681
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/get-related-records.html
|
|
1645
2682
|
*/
|
|
1646
2683
|
function zohoCrmGetRelatedRecordsFunctionFactory(context) {
|
|
1647
2684
|
return (config) => {
|
|
@@ -1649,6 +2686,29 @@ function zohoCrmGetRelatedRecordsFunctionFactory(context) {
|
|
|
1649
2686
|
return (input) => context.fetchJson(`/v8/${input.module}/${input.id}/${targetModule}?${zohoCrmUrlSearchParamsMinusIdAndModule(input, input.filter).toString()}`, zohoCrmApiFetchJsonInput('GET')).then((x) => x ?? (returnEmptyRecordsInsteadOfNull !== false ? emptyZohoPageResult() : x));
|
|
1650
2687
|
};
|
|
1651
2688
|
}
|
|
2689
|
+
/**
|
|
2690
|
+
* Creates a {@link ZohoCrmGetEmailsForRecordFunction} bound to the given context.
|
|
2691
|
+
*
|
|
2692
|
+
* Retrieves email metadata related to a specific record by targeting the
|
|
2693
|
+
* Emails module via the related records API. Normalizes the Zoho API response
|
|
2694
|
+
* which returns email data under an `Emails` key instead of the standard `data` key.
|
|
2695
|
+
* Returns a paginated result of {@link ZohoCrmRecordEmailMetadata} entries.
|
|
2696
|
+
*
|
|
2697
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2698
|
+
* @returns Function that retrieves emails for a record
|
|
2699
|
+
*
|
|
2700
|
+
* @example
|
|
2701
|
+
* ```typescript
|
|
2702
|
+
* const getEmailsForRecord = zohoCrmGetEmailsForRecord(context);
|
|
2703
|
+
*
|
|
2704
|
+
* const result = await getEmailsForRecord({
|
|
2705
|
+
* id: contactId,
|
|
2706
|
+
* module: 'Contacts'
|
|
2707
|
+
* });
|
|
2708
|
+
* ```
|
|
2709
|
+
*
|
|
2710
|
+
* @see https://www.zoho.com/crm/developer/docs/api/v8/get-email-rel-list.html
|
|
2711
|
+
*/
|
|
1652
2712
|
function zohoCrmGetEmailsForRecord(context) {
|
|
1653
2713
|
const getEmailsFactory = zohoCrmGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_CRM_EMAILS_MODULE });
|
|
1654
2714
|
return (input) => getEmailsFactory(input).then((x) => {
|
|
@@ -1656,12 +2716,96 @@ function zohoCrmGetEmailsForRecord(context) {
|
|
|
1656
2716
|
return { ...x, data };
|
|
1657
2717
|
});
|
|
1658
2718
|
}
|
|
2719
|
+
/**
|
|
2720
|
+
* Creates a {@link ZohoCrmGetEmailsForRecordPageFactory} bound to the given context.
|
|
2721
|
+
*
|
|
2722
|
+
* Returns a page factory for iterating over emails related to a record across
|
|
2723
|
+
* multiple pages. Wraps {@link zohoCrmGetEmailsForRecord} with automatic
|
|
2724
|
+
* pagination handling via {@link zohoFetchPageFactory}.
|
|
2725
|
+
*
|
|
2726
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2727
|
+
* @returns Page factory for iterating over record emails
|
|
2728
|
+
*
|
|
2729
|
+
* @example
|
|
2730
|
+
* ```typescript
|
|
2731
|
+
* const pageFactory = zohoCrmGetEmailsForRecordPageFactory(context);
|
|
2732
|
+
*
|
|
2733
|
+
* const fetchPage = pageFactory({
|
|
2734
|
+
* id: contactId,
|
|
2735
|
+
* module: 'Contacts',
|
|
2736
|
+
* per_page: 5
|
|
2737
|
+
* });
|
|
2738
|
+
*
|
|
2739
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
2740
|
+
*
|
|
2741
|
+
* if (firstPage.result.info.more_records) {
|
|
2742
|
+
* const secondPage = await firstPage.fetchNext();
|
|
2743
|
+
* }
|
|
2744
|
+
* ```
|
|
2745
|
+
*
|
|
2746
|
+
* @see https://www.zoho.com/crm/developer/docs/api/v8/get-email-rel-list.html
|
|
2747
|
+
*/
|
|
1659
2748
|
function zohoCrmGetEmailsForRecordPageFactory(context) {
|
|
1660
2749
|
return zohoFetchPageFactory(zohoCrmGetEmailsForRecord(context));
|
|
1661
2750
|
}
|
|
2751
|
+
/**
|
|
2752
|
+
* Creates a {@link ZohoCrmGetAttachmentsForRecordFunction} bound to the given context.
|
|
2753
|
+
*
|
|
2754
|
+
* Retrieves attachment metadata related to a specific record by targeting the
|
|
2755
|
+
* Attachments module via the related records API. Returns a paginated result of
|
|
2756
|
+
* {@link ZohoCrmRecordAttachmentMetadata} entries including file names, sizes,
|
|
2757
|
+
* and category information. When no attachments exist for the record, the result
|
|
2758
|
+
* contains an empty data array rather than null.
|
|
2759
|
+
*
|
|
2760
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2761
|
+
* @returns Function that retrieves attachments for a record
|
|
2762
|
+
*
|
|
2763
|
+
* @example
|
|
2764
|
+
* ```typescript
|
|
2765
|
+
* const getAttachmentsForRecord = zohoCrmGetAttachmentsForRecord(context);
|
|
2766
|
+
*
|
|
2767
|
+
* const result = await getAttachmentsForRecord({
|
|
2768
|
+
* id: contactId,
|
|
2769
|
+
* module: 'Contacts',
|
|
2770
|
+
* fields: 'File_Name,Size,Created_Time'
|
|
2771
|
+
* });
|
|
2772
|
+
* ```
|
|
2773
|
+
*
|
|
2774
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/get-related-records.html
|
|
2775
|
+
*/
|
|
1662
2776
|
function zohoCrmGetAttachmentsForRecord(context) {
|
|
1663
2777
|
return zohoCrmGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_CRM_ATTACHMENTS_MODULE });
|
|
1664
2778
|
}
|
|
2779
|
+
/**
|
|
2780
|
+
* Creates a {@link ZohoCrmGetAttachmentsForRecordPageFactory} bound to the given context.
|
|
2781
|
+
*
|
|
2782
|
+
* Returns a page factory for iterating over attachments related to a record
|
|
2783
|
+
* across multiple pages. Wraps {@link zohoCrmGetAttachmentsForRecord} with
|
|
2784
|
+
* automatic pagination handling via {@link zohoFetchPageFactory}.
|
|
2785
|
+
*
|
|
2786
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2787
|
+
* @returns Page factory for iterating over record attachments
|
|
2788
|
+
*
|
|
2789
|
+
* @example
|
|
2790
|
+
* ```typescript
|
|
2791
|
+
* const pageFactory = zohoCrmGetAttachmentsForRecordPageFactory(context);
|
|
2792
|
+
*
|
|
2793
|
+
* const fetchPage = pageFactory({
|
|
2794
|
+
* id: contactId,
|
|
2795
|
+
* module: 'Contacts',
|
|
2796
|
+
* fields: 'File_Name,Size',
|
|
2797
|
+
* per_page: 10
|
|
2798
|
+
* });
|
|
2799
|
+
*
|
|
2800
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
2801
|
+
*
|
|
2802
|
+
* if (firstPage.result.info.more_records) {
|
|
2803
|
+
* const secondPage = await firstPage.fetchNext();
|
|
2804
|
+
* }
|
|
2805
|
+
* ```
|
|
2806
|
+
*
|
|
2807
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/get-related-records.html
|
|
2808
|
+
*/
|
|
1665
2809
|
function zohoCrmGetAttachmentsForRecordPageFactory(context) {
|
|
1666
2810
|
return zohoFetchPageFactory(zohoCrmGetAttachmentsForRecord(context));
|
|
1667
2811
|
}
|
|
@@ -1672,88 +2816,101 @@ function zohoCrmGetAttachmentsForRecordPageFactory(context) {
|
|
|
1672
2816
|
*/
|
|
1673
2817
|
const ZOHO_CRM_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
1674
2818
|
/**
|
|
1675
|
-
*
|
|
2819
|
+
* Creates a {@link ZohoCrmUploadAttachmentForRecordFunction} bound to the given context.
|
|
1676
2820
|
*
|
|
1677
|
-
*
|
|
2821
|
+
* Uploads a file attachment to a specific record. The file is sent as
|
|
2822
|
+
* multipart/form-data. An attachment category must be specified by ID or name.
|
|
2823
|
+
* Maximum file size is {@link ZOHO_CRM_ATTACHMENT_MAX_SIZE} (20MB).
|
|
1678
2824
|
*
|
|
1679
|
-
* @param context
|
|
1680
|
-
* @returns
|
|
2825
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2826
|
+
* @returns Function that uploads an attachment to a record
|
|
2827
|
+
* @throws {Error} If neither `attachmentCategoryId` nor `attachmentCategoryName` is provided
|
|
2828
|
+
*
|
|
2829
|
+
* @example
|
|
2830
|
+
* ```typescript
|
|
2831
|
+
* const uploadAttachment = zohoCrmUploadAttachmentForRecord(context);
|
|
2832
|
+
*
|
|
2833
|
+
* await uploadAttachment({
|
|
2834
|
+
* module: 'Contacts',
|
|
2835
|
+
* id: contactId,
|
|
2836
|
+
* file: new File(['content'], 'resume.pdf', { type: 'application/pdf' }),
|
|
2837
|
+
* attachmentCategoryName: 'Resume'
|
|
2838
|
+
* });
|
|
2839
|
+
* ```
|
|
2840
|
+
*
|
|
2841
|
+
* @see https://www.zoho.com/crm/developer/docs/api/v2.1/upload-attachment.html
|
|
1681
2842
|
*/
|
|
1682
2843
|
function zohoCrmUploadAttachmentForRecord(context) {
|
|
1683
2844
|
return (input) => {
|
|
1684
|
-
const { attachmentCategoryId, attachmentCategoryName,
|
|
2845
|
+
const { attachmentCategoryId, attachmentCategoryName, file } = input;
|
|
1685
2846
|
const urlParams = {
|
|
1686
2847
|
attachments_category_id: joinStringsWithCommas(attachmentCategoryId),
|
|
1687
|
-
attachments_category: joinStringsWithCommas(attachmentCategoryName)
|
|
1688
|
-
attachment_url: input.attachmentUrl
|
|
2848
|
+
attachments_category: joinStringsWithCommas(attachmentCategoryName)
|
|
1689
2849
|
};
|
|
1690
2850
|
if (!urlParams.attachments_category_id?.length && !urlParams.attachments_category?.length) {
|
|
1691
2851
|
throw new Error('attachmentCategoryId or attachmentCategoryName must be provided and not empty.');
|
|
1692
2852
|
}
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
if (urlParams.attachment_url) {
|
|
1699
|
-
response = context.fetch(url, { method: 'POST' });
|
|
1700
|
-
}
|
|
1701
|
-
else if (formData != null) {
|
|
1702
|
-
throw new Error('unsupported currently. Use the attachmentUrl parameter instead.');
|
|
1703
|
-
// There is something weird going on with sending requests this way and zoho's server is rejecting it.
|
|
1704
|
-
/*
|
|
1705
|
-
response = context.fetch(url, {
|
|
1706
|
-
method: 'POST',
|
|
1707
|
-
headers: {
|
|
1708
|
-
'Content-Type': 'multipart/form-data',
|
|
1709
|
-
'content-length': '210'
|
|
1710
|
-
},
|
|
1711
|
-
body: formData
|
|
1712
|
-
});
|
|
1713
|
-
*/
|
|
1714
|
-
/*
|
|
1715
|
-
const fullUrl = (context.config.apiUrl as string) + url;
|
|
1716
|
-
const accessToken = await context.accessTokenStringFactory();
|
|
1717
|
-
|
|
1718
|
-
response = fetch(fullUrl, {
|
|
1719
|
-
headers: {
|
|
1720
|
-
Authorization: `Bearer ${accessToken}`
|
|
1721
|
-
},
|
|
1722
|
-
body: formData,
|
|
1723
|
-
method: 'POST'
|
|
1724
|
-
});
|
|
1725
|
-
|
|
1726
|
-
console.log({ response });
|
|
1727
|
-
*/
|
|
1728
|
-
}
|
|
1729
|
-
else {
|
|
1730
|
-
throw new Error('body or attachmentUrl must be provided.');
|
|
1731
|
-
}
|
|
1732
|
-
return response;
|
|
2853
|
+
const url = `/v8/${input.module}/${input.id}/${ZOHO_CRM_ATTACHMENTS_MODULE}?${makeUrlSearchParams(urlParams).toString()}`;
|
|
2854
|
+
const body = new FormData();
|
|
2855
|
+
body.append('file', file);
|
|
2856
|
+
// Clear the base Content-Type header (empty string removes it via mergeRequestHeaders) so fetch auto-detects multipart/form-data with the correct boundary from the FormData body.
|
|
2857
|
+
return context.fetch(url, { method: 'POST', headers: { 'Content-Type': '' }, body });
|
|
1733
2858
|
};
|
|
1734
2859
|
}
|
|
1735
2860
|
/**
|
|
1736
|
-
*
|
|
2861
|
+
* Creates a {@link ZohoCrmDownloadAttachmentForRecordFunction} bound to the given context.
|
|
1737
2862
|
*
|
|
1738
|
-
*
|
|
2863
|
+
* Downloads a specific attachment from a record. Returns a parsed
|
|
2864
|
+
* {@link FetchFileResponse} containing the file data and metadata extracted
|
|
2865
|
+
* from the response headers.
|
|
1739
2866
|
*
|
|
1740
|
-
* @param context
|
|
1741
|
-
* @returns
|
|
2867
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2868
|
+
* @returns Function that downloads an attachment by record and attachment ID
|
|
2869
|
+
*
|
|
2870
|
+
* @example
|
|
2871
|
+
* ```typescript
|
|
2872
|
+
* const downloadAttachment = zohoCrmDownloadAttachmentForRecord(context);
|
|
2873
|
+
*
|
|
2874
|
+
* const fileResponse = await downloadAttachment({
|
|
2875
|
+
* module: 'Contacts',
|
|
2876
|
+
* id: contactId,
|
|
2877
|
+
* attachment_id: attachmentId
|
|
2878
|
+
* });
|
|
2879
|
+
* ```
|
|
2880
|
+
*
|
|
2881
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/download-attachments.html
|
|
1742
2882
|
*/
|
|
1743
2883
|
function zohoCrmDownloadAttachmentForRecord(context) {
|
|
1744
2884
|
return (input) => context.fetch(`/v8/${input.module}/${input.id}/${ZOHO_CRM_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'GET' }).then(parseFetchFileResponse);
|
|
1745
2885
|
}
|
|
1746
2886
|
/**
|
|
1747
|
-
*
|
|
2887
|
+
* Creates a {@link ZohoCrmDeleteAttachmentFromRecordFunction} bound to the given context.
|
|
1748
2888
|
*
|
|
1749
|
-
*
|
|
2889
|
+
* Deletes a specific attachment from a record by its attachment ID.
|
|
2890
|
+
* Returns the raw {@link Response}.
|
|
1750
2891
|
*
|
|
1751
|
-
* @param context
|
|
1752
|
-
* @returns
|
|
2892
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2893
|
+
* @returns Function that deletes an attachment by record and attachment ID
|
|
2894
|
+
*
|
|
2895
|
+
* @example
|
|
2896
|
+
* ```typescript
|
|
2897
|
+
* const deleteAttachment = zohoCrmDeleteAttachmentFromRecord(context);
|
|
2898
|
+
*
|
|
2899
|
+
* const response = await deleteAttachment({
|
|
2900
|
+
* module: 'Contacts',
|
|
2901
|
+
* id: contactId,
|
|
2902
|
+
* attachment_id: attachmentId
|
|
2903
|
+
* });
|
|
2904
|
+
* ```
|
|
2905
|
+
*
|
|
2906
|
+
* @see https://www.zoho.com/crm/developer-guide/apiv2/delete-attachments.html
|
|
1753
2907
|
*/
|
|
1754
2908
|
function zohoCrmDeleteAttachmentFromRecord(context) {
|
|
1755
2909
|
return (input) => context.fetch(`/v8/${input.module}/${input.id}/${ZOHO_CRM_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'DELETE' });
|
|
1756
2910
|
}
|
|
2911
|
+
/**
|
|
2912
|
+
* Thrown when a Zoho CRM serverless function returns a non-success response code.
|
|
2913
|
+
*/
|
|
1757
2914
|
class ZohoCrmExecuteRestApiFunctionError extends BaseError {
|
|
1758
2915
|
error;
|
|
1759
2916
|
constructor(error) {
|
|
@@ -1762,15 +2919,41 @@ class ZohoCrmExecuteRestApiFunctionError extends BaseError {
|
|
|
1762
2919
|
}
|
|
1763
2920
|
}
|
|
1764
2921
|
/**
|
|
1765
|
-
* Creates a ZohoCrmExecuteRestApiFunctionFunction
|
|
2922
|
+
* Creates a {@link ZohoCrmExecuteRestApiFunctionFunction} bound to the given context.
|
|
2923
|
+
*
|
|
2924
|
+
* Executes Zoho CRM serverless functions via the REST API. Supports both
|
|
2925
|
+
* OAuth-based and API-key-based authentication. When using an API key, a custom
|
|
2926
|
+
* target URL can be specified for cross-environment calls.
|
|
1766
2927
|
*
|
|
1767
2928
|
* OAuth Details:
|
|
1768
2929
|
* - https://www.zoho.com/crm/developer/docs/functions/serverless-fn-oauth.html#OAuth2
|
|
1769
2930
|
* - There is no documentation for ZohoCrm specifically, but it seems to behave the same way
|
|
1770
2931
|
* - You will need the following scopes: ZohoCrm.functions.execute.READ,ZohoCrm.functions.execute.CREATE
|
|
1771
2932
|
*
|
|
1772
|
-
* @param context
|
|
1773
|
-
* @returns
|
|
2933
|
+
* @param context - Authenticated Zoho CRM context providing fetch and rate limiting
|
|
2934
|
+
* @returns Function that executes serverless functions via the REST API
|
|
2935
|
+
* @throws {ZohoCrmExecuteRestApiFunctionError} If the function execution fails
|
|
2936
|
+
*
|
|
2937
|
+
* @example
|
|
2938
|
+
* ```typescript
|
|
2939
|
+
* const executeFunction = zohoCrmExecuteRestApiFunction(context);
|
|
2940
|
+
*
|
|
2941
|
+
* // Execute using OAuth credentials:
|
|
2942
|
+
* const result = await executeFunction({ functionName: 'my_function' });
|
|
2943
|
+
*
|
|
2944
|
+
* // Execute with parameters:
|
|
2945
|
+
* const paramResult = await executeFunction({
|
|
2946
|
+
* functionName: 'process_contact',
|
|
2947
|
+
* params: { contact_id: '12345', action: 'approve' }
|
|
2948
|
+
* });
|
|
2949
|
+
*
|
|
2950
|
+
* // Execute using an API key (cross-environment):
|
|
2951
|
+
* const apiResult = await executeFunction({
|
|
2952
|
+
* functionName: 'my_function',
|
|
2953
|
+
* apiKey: 'your-api-key',
|
|
2954
|
+
* apiUrl: 'production'
|
|
2955
|
+
* });
|
|
2956
|
+
* ```
|
|
1774
2957
|
*/
|
|
1775
2958
|
function zohoCrmExecuteRestApiFunction(context) {
|
|
1776
2959
|
return (input) => {
|
|
@@ -1792,9 +2975,15 @@ function zohoCrmExecuteRestApiFunction(context) {
|
|
|
1792
2975
|
};
|
|
1793
2976
|
}
|
|
1794
2977
|
// MARK: Util
|
|
2978
|
+
/**
|
|
2979
|
+
* Builds URL search params from the input objects, omitting the `module` key since it is used in the URL path rather than as a query parameter.
|
|
2980
|
+
*/
|
|
1795
2981
|
function zohoCrmUrlSearchParamsMinusModule(...input) {
|
|
1796
2982
|
return makeUrlSearchParams(input, { omitKeys: 'module' });
|
|
1797
2983
|
}
|
|
2984
|
+
/**
|
|
2985
|
+
* Builds URL search params from the input objects, omitting both `id` and `module` keys since they are used in the URL path.
|
|
2986
|
+
*/
|
|
1798
2987
|
function zohoCrmUrlSearchParamsMinusIdAndModule(...input) {
|
|
1799
2988
|
return makeUrlSearchParams(input, { omitKeys: ['id', 'module'] });
|
|
1800
2989
|
}
|
|
@@ -1802,6 +2991,9 @@ function zohoCrmUrlSearchParamsMinusIdAndModule(...input) {
|
|
|
1802
2991
|
* @deprecated use makeUrlSearchParams instead.
|
|
1803
2992
|
*/
|
|
1804
2993
|
const zohoCrmUrlSearchParams = makeUrlSearchParams;
|
|
2994
|
+
/**
|
|
2995
|
+
* Constructs the standard FetchJsonInput used by CRM API calls, pairing the HTTP method with an optional body.
|
|
2996
|
+
*/
|
|
1805
2997
|
function zohoCrmApiFetchJsonInput(method, body) {
|
|
1806
2998
|
const result = {
|
|
1807
2999
|
method,
|
|
@@ -1827,6 +3019,28 @@ function zohoCrmCatchZohoCrmChangeObjectLikeResponseError(e) {
|
|
|
1827
3019
|
}
|
|
1828
3020
|
return result;
|
|
1829
3021
|
}
|
|
3022
|
+
/**
|
|
3023
|
+
* Separates a change response's entries into success and error arrays based on their status.
|
|
3024
|
+
*
|
|
3025
|
+
* Iterates over the `data` array from a Zoho CRM change operation response and
|
|
3026
|
+
* partitions entries into `successItems` and `errorItems` based on their `status` field.
|
|
3027
|
+
* The original response is spread into the result, so all original fields remain accessible.
|
|
3028
|
+
*
|
|
3029
|
+
* Used internally by {@link zohoCrmDeleteRecord} and similar functions to provide
|
|
3030
|
+
* convenient access to separated success/error results.
|
|
3031
|
+
*
|
|
3032
|
+
* @param response - Raw change operation response containing mixed success/error entries
|
|
3033
|
+
* @returns The response augmented with pre-separated `successItems` and `errorItems` arrays
|
|
3034
|
+
*
|
|
3035
|
+
* @example
|
|
3036
|
+
* ```typescript
|
|
3037
|
+
* const rawResponse = await context.fetchJson<ZohoCrmChangeObjectLikeResponse>(...);
|
|
3038
|
+
* const result = zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs(rawResponse);
|
|
3039
|
+
*
|
|
3040
|
+
* result.successItems; // entries with status === 'success'
|
|
3041
|
+
* result.errorItems; // entries with non-success status
|
|
3042
|
+
* ```
|
|
3043
|
+
*/
|
|
1830
3044
|
function zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs(response) {
|
|
1831
3045
|
const { data } = response;
|
|
1832
3046
|
const successItems = [];
|
|
@@ -1846,6 +3060,20 @@ function zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs(response) {
|
|
|
1846
3060
|
};
|
|
1847
3061
|
return result;
|
|
1848
3062
|
}
|
|
3063
|
+
/**
|
|
3064
|
+
* Pairs each input record with its corresponding API result and separates them into success and error arrays by status.
|
|
3065
|
+
*
|
|
3066
|
+
* Iterates over the `input` and `results` arrays in parallel, matching each input record
|
|
3067
|
+
* to its positional result. Entries are classified as success or error based on
|
|
3068
|
+
* the result's `status` field matching {@link ZOHO_SUCCESS_STATUS}.
|
|
3069
|
+
*
|
|
3070
|
+
* Used internally by {@link updateRecordLikeFunction} to pair input data with API outcomes
|
|
3071
|
+
* for insert, update, and upsert operations.
|
|
3072
|
+
*
|
|
3073
|
+
* @param input - Array of input records that were submitted to the API
|
|
3074
|
+
* @param results - Array of per-record results returned by the API, positionally aligned with `input`
|
|
3075
|
+
* @returns Object with `successItems` and `errorItems`, each containing paired `{ input, result }` entries
|
|
3076
|
+
*/
|
|
1849
3077
|
function zohoCrmMultiRecordResult(input, results) {
|
|
1850
3078
|
const successItems = [];
|
|
1851
3079
|
const errorItems = [];
|
|
@@ -1871,27 +3099,40 @@ function zohoCrmMultiRecordResult(input, results) {
|
|
|
1871
3099
|
return result;
|
|
1872
3100
|
}
|
|
1873
3101
|
|
|
3102
|
+
/**
|
|
3103
|
+
* Creates notes directly in the CRM Notes module. Each note must include the parent record reference and module name.
|
|
3104
|
+
*
|
|
3105
|
+
* For creating notes associated with a specific record, prefer {@link zohoCrmCreateNotesForRecord} which handles parent binding automatically.
|
|
3106
|
+
*/
|
|
1874
3107
|
function zohoCrmCreateNotes(context) {
|
|
1875
3108
|
return (input) => context.fetchJson(`/v2/${ZOHO_CRM_NOTES_MODULE}`, zohoCrmApiFetchJsonInput('POST', { data: input.data })).then((x) => {
|
|
1876
3109
|
return zohoCrmMultiRecordResult(asArray(input.data), x.data);
|
|
1877
3110
|
});
|
|
1878
3111
|
}
|
|
3112
|
+
/**
|
|
3113
|
+
* Deletes one or more notes from the CRM Notes module by their IDs.
|
|
3114
|
+
*/
|
|
1879
3115
|
function zohoCrmDeleteNotes(context) {
|
|
1880
3116
|
return (input) => context.fetchJson(`/v2/${ZOHO_CRM_NOTES_MODULE}?${makeUrlSearchParams({ ids: input.ids })}`, zohoCrmApiFetchJsonInput('DELETE')).then((x) => {
|
|
1881
3117
|
return zohoCrmMultiRecordResult(asArray(input.ids), x.data);
|
|
1882
3118
|
});
|
|
1883
3119
|
}
|
|
3120
|
+
/**
|
|
3121
|
+
* Retrieves paginated notes associated with a specific CRM record using the related records API.
|
|
3122
|
+
*/
|
|
1884
3123
|
function zohoCrmGetNotesForRecord(context) {
|
|
1885
3124
|
return zohoCrmGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_CRM_NOTES_MODULE });
|
|
1886
3125
|
}
|
|
3126
|
+
/**
|
|
3127
|
+
* Creates a page factory for iterating through all notes for a record across multiple pages.
|
|
3128
|
+
*/
|
|
1887
3129
|
function zohoCrmGetNotesForRecordPageFactory(context) {
|
|
1888
3130
|
return zohoFetchPageFactory(zohoCrmGetNotesForRecord(context));
|
|
1889
3131
|
}
|
|
1890
3132
|
/**
|
|
1891
|
-
*
|
|
3133
|
+
* Creates notes for a specific record, automatically binding the parent module and record ID to each note entry.
|
|
1892
3134
|
*
|
|
1893
|
-
*
|
|
1894
|
-
* @returns
|
|
3135
|
+
* https://www.zoho.com/crm/developer/docs/api/v8/create-notes.html
|
|
1895
3136
|
*/
|
|
1896
3137
|
function zohoCrmCreateNotesForRecord(context) {
|
|
1897
3138
|
const createNotesInstance = zohoCrmCreateNotes(context);
|
|
@@ -1908,6 +3149,9 @@ function zohoCrmCreateNotesForRecord(context) {
|
|
|
1908
3149
|
};
|
|
1909
3150
|
}
|
|
1910
3151
|
|
|
3152
|
+
/**
|
|
3153
|
+
* Creates one or more tags for a CRM module. Duplicate tag errors are separated from other errors in the result to simplify idempotent workflows.
|
|
3154
|
+
*/
|
|
1911
3155
|
function zohoCrmCreateTagsForModule(context) {
|
|
1912
3156
|
return (input) => context
|
|
1913
3157
|
.fetchJson(`/v8/settings/tags?${makeUrlSearchParams({ module: input.module })}`, zohoCrmApiFetchJsonInput('POST', { tags: asArray(input.tags) }))
|
|
@@ -1969,12 +3213,15 @@ function zohoCrmGetTagsForModule(context) {
|
|
|
1969
3213
|
};
|
|
1970
3214
|
});
|
|
1971
3215
|
}
|
|
3216
|
+
/**
|
|
3217
|
+
* Creates a page factory for iterating through all tags in a module across multiple pages.
|
|
3218
|
+
*/
|
|
1972
3219
|
function zohoCrmGetTagsForModulePageFactory(context) {
|
|
1973
3220
|
return zohoFetchPageFactory(zohoCrmGetTagsForModule(context));
|
|
1974
3221
|
}
|
|
1975
3222
|
// MARK: Add Tag To Record
|
|
1976
3223
|
/**
|
|
1977
|
-
*
|
|
3224
|
+
* Maximum number of record IDs allowed per add-tags request, enforced by Zoho CRM.
|
|
1978
3225
|
*/
|
|
1979
3226
|
const ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
1980
3227
|
/**
|
|
@@ -1993,6 +3240,9 @@ function zohoCrmAddTagsToRecords(context) {
|
|
|
1993
3240
|
});
|
|
1994
3241
|
};
|
|
1995
3242
|
}
|
|
3243
|
+
/**
|
|
3244
|
+
* Builds the request body for the add/remove tags endpoints, merging `tag_names` into `tags` and enforcing the max ID limit.
|
|
3245
|
+
*/
|
|
1996
3246
|
function zohoCrmAddTagsToRecordsRequestBody(input) {
|
|
1997
3247
|
if (Array.isArray(input.ids) && input.ids.length > ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED) {
|
|
1998
3248
|
throw new Error(`Cannot add/remove tags from more than ${ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED} records at once.`);
|
|
@@ -2014,7 +3264,7 @@ function zohoCrmAddTagsToRecordsRequestBody(input) {
|
|
|
2014
3264
|
}
|
|
2015
3265
|
// MARK: Remove Tag From Record
|
|
2016
3266
|
/**
|
|
2017
|
-
*
|
|
3267
|
+
* Maximum number of record IDs allowed per remove-tags request, enforced by Zoho CRM.
|
|
2018
3268
|
*/
|
|
2019
3269
|
const ZOHO_CRM_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
2020
3270
|
/**
|
|
@@ -2034,6 +3284,31 @@ function zohoCrmRemoveTagsFromRecords(context) {
|
|
|
2034
3284
|
};
|
|
2035
3285
|
}
|
|
2036
3286
|
|
|
3287
|
+
/**
|
|
3288
|
+
* Creates a {@link ZohoCrmFactory} from the given configuration.
|
|
3289
|
+
*
|
|
3290
|
+
* The factory pre-initializes shared resources (access token provider, rate limiter)
|
|
3291
|
+
* once, then produces {@link ZohoCrm} client instances for each {@link ZohoCrmConfig}.
|
|
3292
|
+
* Each client handles OAuth token refresh on {@link ZohoInvalidTokenError}, rate limiting,
|
|
3293
|
+
* and Zoho CRM's non-standard error responses (200 status with error body).
|
|
3294
|
+
*
|
|
3295
|
+
* @param factoryConfig - Configuration providing account credentials and optional overrides
|
|
3296
|
+
* @returns A factory function that creates authenticated Zoho CRM clients
|
|
3297
|
+
*
|
|
3298
|
+
* @example
|
|
3299
|
+
* ```typescript
|
|
3300
|
+
* const factory = zohoCrmFactory({
|
|
3301
|
+
* accountsContext: zohoAccountsApi.accountsContext
|
|
3302
|
+
* });
|
|
3303
|
+
*
|
|
3304
|
+
* const zohoCrm = factory({
|
|
3305
|
+
* apiUrl: 'https://www.zohoapis.com/crm'
|
|
3306
|
+
* });
|
|
3307
|
+
*
|
|
3308
|
+
* // Use the CRM context for API calls:
|
|
3309
|
+
* const { crmContext } = zohoCrm;
|
|
3310
|
+
* ```
|
|
3311
|
+
*/
|
|
2037
3312
|
function zohoCrmFactory(factoryConfig) {
|
|
2038
3313
|
const { accountsContext } = factoryConfig;
|
|
2039
3314
|
const accessTokenStringFactory = zohoAccessTokenStringFactory(accountsContext.loadAccessToken);
|
|
@@ -2089,9 +3364,543 @@ function zohoCrmFactory(factoryConfig) {
|
|
|
2089
3364
|
const ZOHO_CRM_TAG_NAME_MAX_LENGTH = 25;
|
|
2090
3365
|
|
|
2091
3366
|
/**
|
|
2092
|
-
*
|
|
2093
|
-
*
|
|
2094
|
-
*
|
|
3367
|
+
* Creates a page factory that wraps a Zoho Sign fetch function with automatic offset-based pagination.
|
|
3368
|
+
*
|
|
3369
|
+
* The factory reads `page_context.has_more_rows` from each response to determine if additional
|
|
3370
|
+
* pages exist, and automatically advances `start_index` by `row_count` for subsequent requests.
|
|
3371
|
+
*
|
|
3372
|
+
* @param fetch - The Zoho Sign fetch function to paginate over
|
|
3373
|
+
* @param defaults - Optional default configuration for the page factory
|
|
3374
|
+
* @returns A page factory that produces iterable page fetchers
|
|
3375
|
+
*
|
|
3376
|
+
* @example
|
|
3377
|
+
* ```typescript
|
|
3378
|
+
* const pageFactory = zohoSignFetchPageFactory(zohoSignGetDocumentsList(context));
|
|
3379
|
+
*
|
|
3380
|
+
* const fetchPage = pageFactory({ row_count: 10 });
|
|
3381
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
3382
|
+
*
|
|
3383
|
+
* if (firstPage.result.page_context.has_more_rows) {
|
|
3384
|
+
* const secondPage = await firstPage.fetchNext();
|
|
3385
|
+
* }
|
|
3386
|
+
* ```
|
|
3387
|
+
*/
|
|
3388
|
+
function zohoSignFetchPageFactory(fetch, defaults) {
|
|
3389
|
+
return fetchPageFactory({
|
|
3390
|
+
...defaults,
|
|
3391
|
+
fetch,
|
|
3392
|
+
readFetchPageResultInfo: function (result) {
|
|
3393
|
+
return {
|
|
3394
|
+
hasNext: result.page_context?.has_more_rows ?? false
|
|
3395
|
+
};
|
|
3396
|
+
},
|
|
3397
|
+
buildInputForNextPage: function (pageResult, input, options) {
|
|
3398
|
+
const previousResult = pageResult.result;
|
|
3399
|
+
const previousPageContext = previousResult?.page_context;
|
|
3400
|
+
const rowCount = options.maxItemsPerPage ?? input.row_count ?? previousPageContext?.row_count ?? 20;
|
|
3401
|
+
const nextStartIndex = (previousPageContext?.start_index ?? input.start_index ?? 1) + rowCount;
|
|
3402
|
+
return { ...input, start_index: nextStartIndex, row_count: rowCount };
|
|
3403
|
+
}
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
// MARK: Utility
|
|
3408
|
+
/**
|
|
3409
|
+
* Builds a {@link FetchJsonInput} for Zoho Sign API calls.
|
|
3410
|
+
*/
|
|
3411
|
+
function zohoSignApiFetchJsonInput(method, body) {
|
|
3412
|
+
return {
|
|
3413
|
+
method,
|
|
3414
|
+
body: body ?? undefined
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
/**
|
|
3418
|
+
* Creates a {@link ZohoSignGetDocumentFunction} bound to the given context.
|
|
3419
|
+
*
|
|
3420
|
+
* Fetches the full details of a single Zoho Sign request (envelope) by its ID,
|
|
3421
|
+
* including actions, documents, and field data.
|
|
3422
|
+
*
|
|
3423
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3424
|
+
* @returns Function that retrieves a document by request ID
|
|
3425
|
+
*
|
|
3426
|
+
* @example
|
|
3427
|
+
* ```typescript
|
|
3428
|
+
* const getDocument = zohoSignGetDocument(context);
|
|
3429
|
+
* const response = await getDocument({ requestId: '12345' });
|
|
3430
|
+
* ```
|
|
3431
|
+
*
|
|
3432
|
+
* @see https://www.zoho.com/sign/api/document-managment/get-details-of-a-particular-document.html
|
|
3433
|
+
*/
|
|
3434
|
+
function zohoSignGetDocument(context) {
|
|
3435
|
+
return ({ requestId }) => context.fetchJson(`/requests/${requestId}`, zohoSignApiFetchJsonInput('GET'));
|
|
3436
|
+
}
|
|
3437
|
+
/**
|
|
3438
|
+
* Creates a {@link ZohoSignGetDocumentsFunction} bound to the given context.
|
|
3439
|
+
*
|
|
3440
|
+
* Fetches a paginated list of Zoho Sign requests. Supports sorting via
|
|
3441
|
+
* {@link ZohoSignPageFilter} and filtering via {@link ZohoSignSearchColumns}.
|
|
3442
|
+
* Pagination parameters (`start_index`, `row_count`) are serialized as a
|
|
3443
|
+
* JSON `data` query parameter per the Zoho Sign API convention.
|
|
3444
|
+
*
|
|
3445
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3446
|
+
* @returns Function that retrieves a paginated list of documents
|
|
3447
|
+
*
|
|
3448
|
+
* @example
|
|
3449
|
+
* ```typescript
|
|
3450
|
+
* const getDocuments = zohoSignGetDocuments(context);
|
|
3451
|
+
* const response = await getDocuments({ start_index: 1, row_count: 10 });
|
|
3452
|
+
* ```
|
|
3453
|
+
*
|
|
3454
|
+
* @see https://www.zoho.com/sign/api/document-managment/get-document-list.html
|
|
3455
|
+
*/
|
|
3456
|
+
function zohoSignGetDocuments(context) {
|
|
3457
|
+
return (input) => {
|
|
3458
|
+
const { search_columns, ...pageFilter } = input;
|
|
3459
|
+
const data = {
|
|
3460
|
+
page_context: {
|
|
3461
|
+
...pageFilter,
|
|
3462
|
+
...(search_columns ? { search_columns } : {})
|
|
3463
|
+
}
|
|
3464
|
+
};
|
|
3465
|
+
return context.fetchJson({
|
|
3466
|
+
url: `/requests`,
|
|
3467
|
+
queryParams: { data: JSON.stringify(data) }
|
|
3468
|
+
}, zohoSignApiFetchJsonInput('GET'));
|
|
3469
|
+
};
|
|
3470
|
+
}
|
|
3471
|
+
/**
|
|
3472
|
+
* Creates a {@link zohoSignFetchPageFactory} bound to the given context.
|
|
3473
|
+
*
|
|
3474
|
+
* Returns a page factory that automatically handles Zoho Sign's
|
|
3475
|
+
* `start_index`/`row_count` pagination, making it easy to iterate
|
|
3476
|
+
* through all documents across multiple pages.
|
|
3477
|
+
*
|
|
3478
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3479
|
+
* @returns Page factory for iterating through documents
|
|
3480
|
+
*
|
|
3481
|
+
* @example
|
|
3482
|
+
* ```typescript
|
|
3483
|
+
* const pageFactory = zohoSignGetDocumentsPageFactory(context);
|
|
3484
|
+
* const fetchPage = pageFactory({ row_count: 5 });
|
|
3485
|
+
*
|
|
3486
|
+
* const firstPage = await fetchPage.fetchNext();
|
|
3487
|
+
* const secondPage = await firstPage.fetchNext();
|
|
3488
|
+
* ```
|
|
3489
|
+
*/
|
|
3490
|
+
function zohoSignGetDocumentsPageFactory(context) {
|
|
3491
|
+
const getDocuments = zohoSignGetDocuments(context);
|
|
3492
|
+
return zohoSignFetchPageFactory(getDocuments);
|
|
3493
|
+
}
|
|
3494
|
+
/**
|
|
3495
|
+
* Creates a {@link ZohoSignGetDocumentFormDataFunction} bound to the given context.
|
|
3496
|
+
*
|
|
3497
|
+
* Retrieves the filled form field values for a completed document. Only
|
|
3498
|
+
* returns data after all recipients have signed. The response includes
|
|
3499
|
+
* field labels and values grouped by recipient action.
|
|
3500
|
+
*
|
|
3501
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3502
|
+
* @returns Function that retrieves form data for a completed document
|
|
3503
|
+
*
|
|
3504
|
+
* @example
|
|
3505
|
+
* ```typescript
|
|
3506
|
+
* const getFormData = zohoSignGetDocumentFormData(context);
|
|
3507
|
+
* const response = await getFormData({ requestId: '12345' });
|
|
3508
|
+
* ```
|
|
3509
|
+
*
|
|
3510
|
+
* @see https://www.zoho.com/sign/api/document-managment/get-document-form-data.html
|
|
3511
|
+
*/
|
|
3512
|
+
function zohoSignGetDocumentFormData(context) {
|
|
3513
|
+
return ({ requestId }) => context.fetchJson(`/requests/${requestId}/fielddata`, zohoSignApiFetchJsonInput('GET'));
|
|
3514
|
+
}
|
|
3515
|
+
/**
|
|
3516
|
+
* Creates a {@link ZohoSignRetrieveFieldTypesFunction} bound to the given context.
|
|
3517
|
+
*
|
|
3518
|
+
* Retrieves all available field types (e.g. Signature, Textfield, Checkbox)
|
|
3519
|
+
* that can be placed on documents. Useful for dynamically building document
|
|
3520
|
+
* templates or validating field configurations.
|
|
3521
|
+
*
|
|
3522
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3523
|
+
* @returns Function that retrieves all available field types
|
|
3524
|
+
*
|
|
3525
|
+
* @example
|
|
3526
|
+
* ```typescript
|
|
3527
|
+
* const retrieveFieldTypes = zohoSignRetrieveFieldTypes(context);
|
|
3528
|
+
* const response = await retrieveFieldTypes();
|
|
3529
|
+
* ```
|
|
3530
|
+
*
|
|
3531
|
+
* @see https://www.zoho.com/sign/api/document-managment/retrieve-field-type.html
|
|
3532
|
+
*/
|
|
3533
|
+
function zohoSignRetrieveFieldTypes(context) {
|
|
3534
|
+
return () => context.fetchJson(`/fieldtypes`, zohoSignApiFetchJsonInput('GET'));
|
|
3535
|
+
}
|
|
3536
|
+
/**
|
|
3537
|
+
* Creates a {@link ZohoSignDownloadPdfFunction} bound to the given context.
|
|
3538
|
+
*
|
|
3539
|
+
* Downloads the signed PDF document(s) for a completed request. Returns a
|
|
3540
|
+
* raw {@link Response} containing either a PDF (single document) or a ZIP
|
|
3541
|
+
* archive (multiple documents). Supports optional parameters to include the
|
|
3542
|
+
* completion certificate, merge all documents, or provide a password for
|
|
3543
|
+
* protected files.
|
|
3544
|
+
*
|
|
3545
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3546
|
+
* @returns Function that downloads signed PDFs by request ID
|
|
3547
|
+
*
|
|
3548
|
+
* @example
|
|
3549
|
+
* ```typescript
|
|
3550
|
+
* const downloadPdf = zohoSignDownloadPdf(context);
|
|
3551
|
+
*
|
|
3552
|
+
* // Download signed PDF with completion certificate merged in:
|
|
3553
|
+
* const response = await downloadPdf({
|
|
3554
|
+
* requestId: '12345',
|
|
3555
|
+
* with_coc: true,
|
|
3556
|
+
* merge: true
|
|
3557
|
+
* });
|
|
3558
|
+
*
|
|
3559
|
+
* const blob = await response.blob();
|
|
3560
|
+
* ```
|
|
3561
|
+
*
|
|
3562
|
+
* @see https://www.zoho.com/sign/api/document-managment/download-pdf.html
|
|
3563
|
+
*/
|
|
3564
|
+
function zohoSignDownloadPdf(context) {
|
|
3565
|
+
return ({ requestId, ...params }) => {
|
|
3566
|
+
const searchParams = makeUrlSearchParams(params);
|
|
3567
|
+
const queryString = searchParams.toString();
|
|
3568
|
+
const url = `/requests/${requestId}/pdf${queryString ? `?${queryString}` : ''}`;
|
|
3569
|
+
return context.fetch(url, { method: 'GET' });
|
|
3570
|
+
};
|
|
3571
|
+
}
|
|
3572
|
+
/**
|
|
3573
|
+
* Creates a {@link ZohoSignDownloadCompletionCertificateFunction} bound to the given context.
|
|
3574
|
+
*
|
|
3575
|
+
* Downloads the completion certificate PDF for a finished request. The
|
|
3576
|
+
* certificate contains an audit trail of the signing process including
|
|
3577
|
+
* timestamps and recipient details. Returns a raw {@link Response}.
|
|
3578
|
+
*
|
|
3579
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3580
|
+
* @returns Function that downloads the completion certificate by request ID
|
|
3581
|
+
*
|
|
3582
|
+
* @example
|
|
3583
|
+
* ```typescript
|
|
3584
|
+
* const downloadCert = zohoSignDownloadCompletionCertificate(context);
|
|
3585
|
+
* const response = await downloadCert({ requestId: '12345' });
|
|
3586
|
+
* const blob = await response.blob();
|
|
3587
|
+
* ```
|
|
3588
|
+
*
|
|
3589
|
+
* @see https://www.zoho.com/sign/api/document-managment/download-completion-certificate.html
|
|
3590
|
+
*/
|
|
3591
|
+
function zohoSignDownloadCompletionCertificate(context) {
|
|
3592
|
+
return ({ requestId }) => context.fetch(`/requests/${requestId}/completioncertificate`, { method: 'GET' });
|
|
3593
|
+
}
|
|
3594
|
+
/**
|
|
3595
|
+
* Creates a {@link ZohoSignCreateDocumentFunction} bound to the given context.
|
|
3596
|
+
*
|
|
3597
|
+
* Creates a new document draft in Zoho Sign. The request data and file are
|
|
3598
|
+
* sent as multipart/form-data. The `Content-Type` header is intentionally
|
|
3599
|
+
* cleared so that `fetch` auto-detects the correct multipart boundary from
|
|
3600
|
+
* the {@link FormData} body.
|
|
3601
|
+
*
|
|
3602
|
+
* The created document starts in draft status and must be submitted
|
|
3603
|
+
* separately via {@link zohoSignSendDocumentForSignature}.
|
|
3604
|
+
*
|
|
3605
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3606
|
+
* @returns Function that creates a new document draft
|
|
3607
|
+
*
|
|
3608
|
+
* @example
|
|
3609
|
+
* ```typescript
|
|
3610
|
+
* const createDocument = zohoSignCreateDocument(context);
|
|
3611
|
+
*
|
|
3612
|
+
* const response = await createDocument({
|
|
3613
|
+
* requestData: {
|
|
3614
|
+
* request_name: 'NDA Agreement',
|
|
3615
|
+
* is_sequential: true,
|
|
3616
|
+
* actions: [
|
|
3617
|
+
* {
|
|
3618
|
+
* action_type: 'SIGN',
|
|
3619
|
+
* recipient_name: 'Jane Doe',
|
|
3620
|
+
* recipient_email: 'jane@example.com'
|
|
3621
|
+
* }
|
|
3622
|
+
* ]
|
|
3623
|
+
* },
|
|
3624
|
+
* file: new File([pdfBuffer], 'nda.pdf', { type: 'application/pdf' })
|
|
3625
|
+
* });
|
|
3626
|
+
*
|
|
3627
|
+
* const draftId = response.requests.request_id;
|
|
3628
|
+
* ```
|
|
3629
|
+
*
|
|
3630
|
+
* @see https://www.zoho.com/sign/api/document-managment/create-document.html
|
|
3631
|
+
*/
|
|
3632
|
+
function zohoSignCreateDocument(context) {
|
|
3633
|
+
return ({ requestData, file }) => {
|
|
3634
|
+
const body = new FormData();
|
|
3635
|
+
body.append('data', JSON.stringify({ requests: requestData }));
|
|
3636
|
+
body.append('file', file);
|
|
3637
|
+
// Clear the base Content-Type header (empty string removes it via mergeRequestHeaders) so fetch auto-detects multipart/form-data with the correct boundary from the FormData body.
|
|
3638
|
+
return context.fetch(`/requests`, { method: 'POST', headers: { 'Content-Type': '' }, body }).then((response) => response.json());
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3641
|
+
/**
|
|
3642
|
+
* Creates a {@link ZohoSignUpdateDocumentFunction} bound to the given context.
|
|
3643
|
+
*
|
|
3644
|
+
* Updates an existing document that is still in draft status. Accepts partial
|
|
3645
|
+
* {@link ZohoSignRequestData} to modify fields such as actions, notes, or
|
|
3646
|
+
* expiration settings. Cannot be used on documents that have already been
|
|
3647
|
+
* submitted for signature.
|
|
3648
|
+
*
|
|
3649
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3650
|
+
* @returns Function that updates a draft document by request ID
|
|
3651
|
+
*
|
|
3652
|
+
* @example
|
|
3653
|
+
* ```typescript
|
|
3654
|
+
* const updateDocument = zohoSignUpdateDocument(context);
|
|
3655
|
+
*
|
|
3656
|
+
* await updateDocument({
|
|
3657
|
+
* requestId: '12345',
|
|
3658
|
+
* data: { notes: 'Updated notes for this document' }
|
|
3659
|
+
* });
|
|
3660
|
+
* ```
|
|
3661
|
+
*
|
|
3662
|
+
* @see https://www.zoho.com/sign/api/document-managment/update-document.html
|
|
3663
|
+
*/
|
|
3664
|
+
function zohoSignUpdateDocument(context) {
|
|
3665
|
+
return ({ requestId, data }) => context.fetchJson(`/requests/${requestId}`, zohoSignApiFetchJsonInput('PUT', { requests: data }));
|
|
3666
|
+
}
|
|
3667
|
+
/**
|
|
3668
|
+
* Creates a {@link ZohoSignSendDocumentForSignatureFunction} bound to the given context.
|
|
3669
|
+
*
|
|
3670
|
+
* Submits a draft document to its recipients for signing. Optionally accepts
|
|
3671
|
+
* partial {@link ZohoSignRequestData} to apply last-minute updates before
|
|
3672
|
+
* submission. Once submitted, the document transitions from draft to
|
|
3673
|
+
* "inprogress" status and recipients receive signing notifications.
|
|
3674
|
+
*
|
|
3675
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3676
|
+
* @returns Function that sends a document for signature by request ID
|
|
3677
|
+
*
|
|
3678
|
+
* @example
|
|
3679
|
+
* ```typescript
|
|
3680
|
+
* const sendForSignature = zohoSignSendDocumentForSignature(context);
|
|
3681
|
+
*
|
|
3682
|
+
* // Submit a draft for signing:
|
|
3683
|
+
* await sendForSignature({ requestId: '12345' });
|
|
3684
|
+
*
|
|
3685
|
+
* // Submit with last-minute updates:
|
|
3686
|
+
* await sendForSignature({
|
|
3687
|
+
* requestId: '12345',
|
|
3688
|
+
* data: { expiration_days: 30 }
|
|
3689
|
+
* });
|
|
3690
|
+
* ```
|
|
3691
|
+
*
|
|
3692
|
+
* @see https://www.zoho.com/sign/api/document-managment/send-document-for-signature.html
|
|
3693
|
+
*/
|
|
3694
|
+
function zohoSignSendDocumentForSignature(context) {
|
|
3695
|
+
return ({ requestId, data }) => {
|
|
3696
|
+
const body = data ? { requests: data } : undefined;
|
|
3697
|
+
return context.fetchJson(`/requests/${requestId}/submit`, zohoSignApiFetchJsonInput('POST', body));
|
|
3698
|
+
};
|
|
3699
|
+
}
|
|
3700
|
+
/**
|
|
3701
|
+
* Creates a {@link ZohoSignExtendDocumentFunction} bound to the given context.
|
|
3702
|
+
*
|
|
3703
|
+
* Extends the expiration date of an in-progress document. The new date is
|
|
3704
|
+
* provided as a human-readable string (e.g. "30 November 2024"). Useful for
|
|
3705
|
+
* giving recipients additional time to complete signing.
|
|
3706
|
+
*
|
|
3707
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3708
|
+
* @returns Function that extends a document's expiration by request ID
|
|
3709
|
+
*
|
|
3710
|
+
* @example
|
|
3711
|
+
* ```typescript
|
|
3712
|
+
* const extendDocument = zohoSignExtendDocument(context);
|
|
3713
|
+
* await extendDocument({ requestId: '12345', expire_by: '30 November 2024' });
|
|
3714
|
+
* ```
|
|
3715
|
+
*
|
|
3716
|
+
* @see https://www.zoho.com/sign/api/document-managment/extend-document.html
|
|
3717
|
+
*/
|
|
3718
|
+
function zohoSignExtendDocument(context) {
|
|
3719
|
+
return ({ requestId, expire_by }) => context.fetchJson(`/requests/${requestId}/extend`, zohoSignApiFetchJsonInput('PUT', { expire_by }));
|
|
3720
|
+
}
|
|
3721
|
+
/**
|
|
3722
|
+
* Creates a {@link ZohoSignDeleteDocumentFunction} bound to the given context.
|
|
3723
|
+
*
|
|
3724
|
+
* Deletes a document from Zoho Sign. For documents that are currently
|
|
3725
|
+
* in-progress, set `recall_inprogress` to `true` to recall the document
|
|
3726
|
+
* from recipients before deletion. An optional `reason` can be provided
|
|
3727
|
+
* to explain the recall. Sends the parameters as URL-encoded form data.
|
|
3728
|
+
*
|
|
3729
|
+
* @param context - Authenticated Zoho Sign context providing fetch and rate limiting
|
|
3730
|
+
* @returns Function that deletes a document by request ID
|
|
3731
|
+
*
|
|
3732
|
+
* @example
|
|
3733
|
+
* ```typescript
|
|
3734
|
+
* const deleteDocument = zohoSignDeleteDocument(context);
|
|
3735
|
+
*
|
|
3736
|
+
* // Delete a draft:
|
|
3737
|
+
* await deleteDocument({ requestId: '12345' });
|
|
3738
|
+
*
|
|
3739
|
+
* // Recall an in-progress document before deleting:
|
|
3740
|
+
* await deleteDocument({
|
|
3741
|
+
* requestId: '12345',
|
|
3742
|
+
* recall_inprogress: true,
|
|
3743
|
+
* reason: 'Contract terms changed'
|
|
3744
|
+
* });
|
|
3745
|
+
* ```
|
|
3746
|
+
*
|
|
3747
|
+
* @see https://www.zoho.com/sign/api/document-managment/delete-document.html
|
|
3748
|
+
*/
|
|
3749
|
+
function zohoSignDeleteDocument(context) {
|
|
3750
|
+
return ({ requestId, recall_inprogress, reason }) => {
|
|
3751
|
+
const params = {};
|
|
3752
|
+
if (recall_inprogress != null) {
|
|
3753
|
+
params['recall_inprogress'] = String(recall_inprogress);
|
|
3754
|
+
}
|
|
3755
|
+
if (reason != null) {
|
|
3756
|
+
params['reason'] = reason;
|
|
3757
|
+
}
|
|
3758
|
+
const form = makeUrlSearchParams(params);
|
|
3759
|
+
const hasForm = form.toString().length > 0;
|
|
3760
|
+
return context.fetchJson(`/requests/${requestId}/delete`, {
|
|
3761
|
+
method: 'PUT',
|
|
3762
|
+
...(hasForm ? { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: form.toString() } : {})
|
|
3763
|
+
});
|
|
3764
|
+
};
|
|
3765
|
+
}
|
|
3766
|
+
|
|
3767
|
+
const ZOHO_SIGN_SERVICE_NAME = 'sign';
|
|
3768
|
+
function zohoSignConfigApiUrl(input) {
|
|
3769
|
+
switch (input) {
|
|
3770
|
+
case 'sandbox':
|
|
3771
|
+
return 'https://signsandbox.zoho.com/api/v1';
|
|
3772
|
+
case 'production':
|
|
3773
|
+
return 'https://sign.zoho.com/api/v1';
|
|
3774
|
+
default:
|
|
3775
|
+
return input;
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
const logZohoSignErrorToConsole = logZohoServerErrorFunction('ZohoSign', { logDataArrayErrors: false });
|
|
3780
|
+
async function parseZohoSignError(responseError) {
|
|
3781
|
+
const data = await responseError.response.json().catch(() => undefined);
|
|
3782
|
+
let result;
|
|
3783
|
+
if (data) {
|
|
3784
|
+
result = parseZohoSignServerErrorResponseData(data, responseError);
|
|
3785
|
+
}
|
|
3786
|
+
return result;
|
|
3787
|
+
}
|
|
3788
|
+
function parseZohoSignServerErrorResponseData(errorResponseData, responseError) {
|
|
3789
|
+
let result;
|
|
3790
|
+
const error = tryFindZohoServerErrorData(errorResponseData, responseError);
|
|
3791
|
+
if (error) {
|
|
3792
|
+
const errorData = zohoServerErrorData(error);
|
|
3793
|
+
switch (errorData.code) {
|
|
3794
|
+
// TODO: Add sign-specific error codes here.
|
|
3795
|
+
default:
|
|
3796
|
+
result = parseZohoServerErrorResponseData(errorResponseData, responseError);
|
|
3797
|
+
break;
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
return result;
|
|
3801
|
+
}
|
|
3802
|
+
const interceptZohoSign200StatusWithErrorResponse = interceptZohoErrorResponseFactory(parseZohoSignServerErrorResponseData);
|
|
3803
|
+
const handleZohoSignErrorFetch = handleZohoErrorFetchFactory(parseZohoSignError, logZohoSignErrorToConsole);
|
|
3804
|
+
|
|
3805
|
+
/**
|
|
3806
|
+
* Creates a {@link ZohoSignFactory} from the given configuration.
|
|
3807
|
+
*
|
|
3808
|
+
* The factory pre-initializes shared resources (access token provider, rate limiter)
|
|
3809
|
+
* once, then produces {@link ZohoSign} client instances for each {@link ZohoSignConfig}.
|
|
3810
|
+
* Each client handles OAuth token refresh on {@link ZohoInvalidTokenError}, rate limiting,
|
|
3811
|
+
* and Zoho Sign's non-standard error responses (200 status with error body).
|
|
3812
|
+
*
|
|
3813
|
+
* @param factoryConfig - Configuration providing account credentials and optional overrides
|
|
3814
|
+
* @returns A factory function that creates authenticated Zoho Sign clients
|
|
3815
|
+
*
|
|
3816
|
+
* @example
|
|
3817
|
+
* ```typescript
|
|
3818
|
+
* const factory = zohoSignFactory({
|
|
3819
|
+
* accountsContext: zohoAccountsApi.accountsContext
|
|
3820
|
+
* });
|
|
3821
|
+
*
|
|
3822
|
+
* const zohoSign = factory({
|
|
3823
|
+
* apiUrl: 'https://sign.zoho.com'
|
|
3824
|
+
* });
|
|
3825
|
+
*
|
|
3826
|
+
* // Use the sign context for API calls:
|
|
3827
|
+
* const { signContext } = zohoSign;
|
|
3828
|
+
* ```
|
|
3829
|
+
*/
|
|
3830
|
+
function zohoSignFactory(factoryConfig) {
|
|
3831
|
+
const { accountsContext } = factoryConfig;
|
|
3832
|
+
const accessTokenStringFactory = zohoAccessTokenStringFactory(accountsContext.loadAccessToken);
|
|
3833
|
+
const fetchHandler = zohoRateLimitedFetchHandler(factoryConfig.rateLimiterConfig);
|
|
3834
|
+
const { logZohoServerErrorFunction, fetchFactory = (input) => fetchApiFetchService.makeFetch({
|
|
3835
|
+
baseUrl: input.apiUrl,
|
|
3836
|
+
baseRequest: async () => ({
|
|
3837
|
+
headers: {
|
|
3838
|
+
'Content-Type': 'application/json',
|
|
3839
|
+
Authorization: `Bearer ${await accessTokenStringFactory()}`
|
|
3840
|
+
}
|
|
3841
|
+
}),
|
|
3842
|
+
fetchHandler,
|
|
3843
|
+
timeout: 20 * 1000, // 20 second timeout
|
|
3844
|
+
requireOkResponse: true, // enforce ok response
|
|
3845
|
+
useTimeout: true // use timeout
|
|
3846
|
+
}) } = factoryConfig;
|
|
3847
|
+
return (config) => {
|
|
3848
|
+
if (!config.apiUrl) {
|
|
3849
|
+
throw new Error('ZohoConfig missing api url.');
|
|
3850
|
+
}
|
|
3851
|
+
const apiUrl = zohoSignConfigApiUrl(config.apiUrl);
|
|
3852
|
+
const baseFetch = fetchFactory({ apiUrl });
|
|
3853
|
+
const fetch = handleZohoSignErrorFetch(baseFetch, logZohoServerErrorFunction, (x) => {
|
|
3854
|
+
if (x instanceof ZohoInvalidTokenError) {
|
|
3855
|
+
accountsContext.loadAccessToken.resetAccessToken();
|
|
3856
|
+
}
|
|
3857
|
+
});
|
|
3858
|
+
const fetchJson = fetchJsonFunction(fetch, {
|
|
3859
|
+
interceptJsonResponse: interceptZohoSign200StatusWithErrorResponse, // intercept errors that return status 200
|
|
3860
|
+
handleFetchJsonParseErrorFunction: returnNullHandleFetchJsonParseErrorFunction
|
|
3861
|
+
});
|
|
3862
|
+
const signContext = {
|
|
3863
|
+
fetch,
|
|
3864
|
+
fetchJson,
|
|
3865
|
+
accessTokenStringFactory,
|
|
3866
|
+
config: {
|
|
3867
|
+
...config,
|
|
3868
|
+
apiUrl
|
|
3869
|
+
},
|
|
3870
|
+
zohoRateLimiter: fetchHandler._rateLimiter
|
|
3871
|
+
};
|
|
3872
|
+
const zohoSign = {
|
|
3873
|
+
signContext
|
|
3874
|
+
};
|
|
3875
|
+
return zohoSign;
|
|
3876
|
+
};
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3879
|
+
/**
|
|
3880
|
+
* Creates a function that exchanges a refresh token for a new short-lived access token
|
|
3881
|
+
* via the Zoho OAuth `/oauth/v2/token` endpoint.
|
|
3882
|
+
*
|
|
3883
|
+
* The returned function accepts optional overrides for client credentials and refresh token.
|
|
3884
|
+
* When omitted, values are read from the {@link ZohoAccountsContext}'s config.
|
|
3885
|
+
*
|
|
3886
|
+
* @param context - Authenticated Zoho Accounts context providing fetch and config
|
|
3887
|
+
* @returns Function that exchanges a refresh token for an access token
|
|
3888
|
+
*
|
|
3889
|
+
* @example
|
|
3890
|
+
* ```typescript
|
|
3891
|
+
* const getAccessToken = zohoAccountsAccessToken(accountsContext);
|
|
3892
|
+
*
|
|
3893
|
+
* // Using config defaults:
|
|
3894
|
+
* const { access_token, expires_in } = await getAccessToken();
|
|
3895
|
+
*
|
|
3896
|
+
* // With overrides:
|
|
3897
|
+
* const response = await getAccessToken({
|
|
3898
|
+
* client: { clientId: 'other-id', clientSecret: 'other-secret' },
|
|
3899
|
+
* refreshToken: 'other-refresh-token'
|
|
3900
|
+
* });
|
|
3901
|
+
* ```
|
|
3902
|
+
*
|
|
3903
|
+
* @see https://www.zoho.com/accounts/protocol/oauth/web-apps/access-token-expiry.html
|
|
2095
3904
|
*/
|
|
2096
3905
|
function zohoAccountsAccessToken(context) {
|
|
2097
3906
|
return (input) => {
|
|
@@ -2100,9 +3909,62 @@ function zohoAccountsAccessToken(context) {
|
|
|
2100
3909
|
const clientId = client?.clientId ?? configClientId;
|
|
2101
3910
|
const clientSecret = client?.clientSecret ?? configClientSecret;
|
|
2102
3911
|
const refreshToken = inputRefreshToken ?? configRefreshToken;
|
|
2103
|
-
|
|
3912
|
+
const params = makeUrlSearchParams({
|
|
3913
|
+
grant_type: 'refresh_token',
|
|
3914
|
+
client_id: clientId,
|
|
3915
|
+
client_secret: clientSecret,
|
|
3916
|
+
refresh_token: refreshToken
|
|
3917
|
+
});
|
|
3918
|
+
return context.fetchJson(`/oauth/v2/token?${params}`, zohoAccountsApiFetchJsonInput('POST'));
|
|
2104
3919
|
};
|
|
2105
3920
|
}
|
|
3921
|
+
/**
|
|
3922
|
+
* Creates a function that exchanges a single-use OAuth authorization code for
|
|
3923
|
+
* an access token and (optionally) a long-lived refresh token via the Zoho
|
|
3924
|
+
* `/oauth/v2/token` endpoint with `grant_type=authorization_code`.
|
|
3925
|
+
*
|
|
3926
|
+
* This is the second step of the Zoho OAuth 2.0 web server flow:
|
|
3927
|
+
* 1. Redirect the user to Zoho's consent page to obtain an authorization code
|
|
3928
|
+
* 2. Exchange the authorization code for tokens using this function
|
|
3929
|
+
* 3. Use the refresh token with {@link zohoAccountsAccessToken} to obtain new access tokens
|
|
3930
|
+
*
|
|
3931
|
+
* The refresh token is only returned if `access_type=offline` was passed during
|
|
3932
|
+
* the initial authorization request.
|
|
3933
|
+
*
|
|
3934
|
+
* @param context - Zoho Accounts context providing fetch and config (clientId/clientSecret)
|
|
3935
|
+
* @returns Function that exchanges an authorization code for tokens
|
|
3936
|
+
*
|
|
3937
|
+
* @example
|
|
3938
|
+
* ```typescript
|
|
3939
|
+
* const exchangeCode = zohoAccountsRefreshTokenFromAuthorizationCode(accountsContext);
|
|
3940
|
+
*
|
|
3941
|
+
* const { access_token, refresh_token } = await exchangeCode({
|
|
3942
|
+
* code: '1000.abc123.def456',
|
|
3943
|
+
* redirectUri: 'https://myapp.example.com/oauth/callback'
|
|
3944
|
+
* });
|
|
3945
|
+
* ```
|
|
3946
|
+
*
|
|
3947
|
+
* @see https://www.zoho.com/accounts/protocol/oauth/web-apps/access-token.html
|
|
3948
|
+
*/
|
|
3949
|
+
function zohoAccountsRefreshTokenFromAuthorizationCode(context) {
|
|
3950
|
+
return (input) => {
|
|
3951
|
+
const { clientId: configClientId, clientSecret: configClientSecret } = context.config;
|
|
3952
|
+
const { client, code, redirectUri } = input;
|
|
3953
|
+
const clientId = client?.clientId ?? configClientId;
|
|
3954
|
+
const clientSecret = client?.clientSecret ?? configClientSecret;
|
|
3955
|
+
const params = makeUrlSearchParams({
|
|
3956
|
+
grant_type: 'authorization_code',
|
|
3957
|
+
client_id: clientId,
|
|
3958
|
+
client_secret: clientSecret,
|
|
3959
|
+
code,
|
|
3960
|
+
redirect_uri: redirectUri
|
|
3961
|
+
});
|
|
3962
|
+
return context.fetchJson(`/oauth/v2/token?${params}`, zohoAccountsApiFetchJsonInput('POST'));
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
/**
|
|
3966
|
+
* Constructs a standard {@link FetchJsonInput} for Zoho Accounts API calls with the given HTTP method and optional body.
|
|
3967
|
+
*/
|
|
2106
3968
|
function zohoAccountsApiFetchJsonInput(method, body) {
|
|
2107
3969
|
const result = {
|
|
2108
3970
|
method,
|
|
@@ -2124,6 +3986,38 @@ function zohoAccountsConfigApiUrl(input) {
|
|
|
2124
3986
|
}
|
|
2125
3987
|
}
|
|
2126
3988
|
|
|
3989
|
+
/**
|
|
3990
|
+
* Creates a {@link ZohoAccountsFactory} from the given configuration.
|
|
3991
|
+
*
|
|
3992
|
+
* The factory pre-initializes shared resources (rate limiter) once, then produces
|
|
3993
|
+
* {@link ZohoAccounts} client instances for each {@link ZohoAccountsConfig}. Each client
|
|
3994
|
+
* handles OAuth token refresh via the configured `refreshToken`, `clientId`, and `clientSecret`,
|
|
3995
|
+
* with in-memory caching and optional external {@link ZohoAccessTokenCache} support.
|
|
3996
|
+
*
|
|
3997
|
+
* The Accounts client is the foundation for CRM, Recruit, and Sign clients, as it provides
|
|
3998
|
+
* the {@link ZohoAccountsContext} needed for OAuth token management.
|
|
3999
|
+
*
|
|
4000
|
+
* @param factoryConfig - Configuration providing optional fetch and logging overrides
|
|
4001
|
+
* @returns A factory function that creates authenticated Zoho Accounts clients
|
|
4002
|
+
* @throws {Error} If `refreshToken`, `clientId`, or `clientSecret` are missing from the config
|
|
4003
|
+
*
|
|
4004
|
+
* @example
|
|
4005
|
+
* ```typescript
|
|
4006
|
+
* const factory = zohoAccountsFactory({});
|
|
4007
|
+
*
|
|
4008
|
+
* const zohoAccounts = factory({
|
|
4009
|
+
* refreshToken: 'your-refresh-token',
|
|
4010
|
+
* clientId: 'your-client-id',
|
|
4011
|
+
* clientSecret: 'your-client-secret',
|
|
4012
|
+
* apiUrl: 'us'
|
|
4013
|
+
* });
|
|
4014
|
+
*
|
|
4015
|
+
* // Pass the accounts context to CRM/Recruit/Sign factories:
|
|
4016
|
+
* const crmFactory = zohoCrmFactory({
|
|
4017
|
+
* accountsContext: zohoAccounts.accountsContext
|
|
4018
|
+
* });
|
|
4019
|
+
* ```
|
|
4020
|
+
*/
|
|
2127
4021
|
function zohoAccountsFactory(factoryConfig) {
|
|
2128
4022
|
const fetchHandler = zohoRateLimitedFetchHandler();
|
|
2129
4023
|
const { logZohoServerErrorFunction, fetchFactory = (input) => fetchApiFetchService.makeFetch({
|
|
@@ -2190,10 +4084,20 @@ function zohoAccountsFactory(factoryConfig) {
|
|
|
2190
4084
|
};
|
|
2191
4085
|
}
|
|
2192
4086
|
/**
|
|
2193
|
-
* Creates a
|
|
4087
|
+
* Creates a {@link ZohoAccessTokenFactory} that manages access token lifecycle with
|
|
4088
|
+
* in-memory caching, optional external cache support, and automatic refresh.
|
|
2194
4089
|
*
|
|
2195
|
-
*
|
|
2196
|
-
*
|
|
4090
|
+
* Token resolution order:
|
|
4091
|
+
* 1. Return the in-memory cached token if valid (not expired within the buffer)
|
|
4092
|
+
* 2. Load from the external {@link ZohoAccessTokenCache} if available
|
|
4093
|
+
* 3. Fetch a fresh token via the {@link ZohoAccessTokenRefresher}
|
|
4094
|
+
*
|
|
4095
|
+
* The returned function also exposes a `resetAccessToken()` method to invalidate
|
|
4096
|
+
* the current cached token, typically called on {@link ZohoInvalidTokenError}.
|
|
4097
|
+
*
|
|
4098
|
+
* @param config - Token refresh, caching, and expiration buffer configuration
|
|
4099
|
+
* @returns A token factory function with `resetAccessToken` for cache invalidation
|
|
4100
|
+
* @throws {ZohoAccountsAuthFailureError} If the token refresher fails
|
|
2197
4101
|
*/
|
|
2198
4102
|
function zohoAccountsZohoAccessTokenFactory(config) {
|
|
2199
4103
|
const { tokenRefresher, accessTokenCache, tokenExpirationBuffer: inputTokenExpirationBuffer } = config;
|
|
@@ -2248,14 +4152,21 @@ function safeZohoDateTimeString(date) {
|
|
|
2248
4152
|
return date != null ? zohoDateTimeString(date) : date;
|
|
2249
4153
|
}
|
|
2250
4154
|
/**
|
|
2251
|
-
* Converts
|
|
4155
|
+
* Converts a {@link Date} to a {@link ZohoDateTimeString} by stripping milliseconds
|
|
4156
|
+
* from the ISO 8601 representation.
|
|
2252
4157
|
*
|
|
2253
|
-
* @param date
|
|
2254
|
-
* @returns
|
|
4158
|
+
* @param date - Date to convert
|
|
4159
|
+
* @returns Zoho-formatted date-time string (e.g. `'2019-05-02T11:17:33Z'`)
|
|
4160
|
+
*
|
|
4161
|
+
* @example
|
|
4162
|
+
* ```typescript
|
|
4163
|
+
* zohoDateTimeString(new Date('2019-05-02T11:17:33.000Z'));
|
|
4164
|
+
* // => '2019-05-02T11:17:33Z'
|
|
4165
|
+
* ```
|
|
2255
4166
|
*/
|
|
2256
4167
|
function zohoDateTimeString(date) {
|
|
2257
4168
|
const isoDate = date.toISOString();
|
|
2258
4169
|
return isoDate.substring(0, isoDate.length - 5) + 'Z';
|
|
2259
4170
|
}
|
|
2260
4171
|
|
|
2261
|
-
export { DEFAULT_ZOHO_API_RATE_LIMIT, DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD, DEFAULT_ZOHO_RATE_LIMITED_TOO_MANY_REQUETS_LOG_FUNCTION, MAX_ZOHO_CRM_SEARCH_MODULE_RECORDS_CRITERIA, MAX_ZOHO_RECRUIT_SEARCH_MODULE_RECORDS_CRITERIA, ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE, ZOHO_ACCOUNTS_INVALID_CODE_ERROR_CODE, ZOHO_ACCOUNTS_US_API_URL, ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED, ZOHO_CRM_ALREADY_ASSOCIATED_ERROR_CODE, ZOHO_CRM_ATTACHMENTS_MODULE, ZOHO_CRM_ATTACHMENT_MAX_SIZE, ZOHO_CRM_CONTACTS_MODULE, ZOHO_CRM_CRUD_FUNCTION_MAX_RECORDS_LIMIT, ZOHO_CRM_EMAILS_MODULE, ZOHO_CRM_LEADS_MODULE, ZOHO_CRM_NOTES_MODULE, ZOHO_CRM_RECORD_ATTACHMENT_METADATA_ATTACH_TYPE_RESUME, ZOHO_CRM_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED, ZOHO_CRM_SERVICE_NAME, ZOHO_CRM_TAG_NAME_MAX_LENGTH, ZOHO_CRM_TASKS_MODULE, ZOHO_DATA_ARRAY_BLANK_ERROR_CODE, ZOHO_DUPLICATE_DATA_ERROR_CODE, ZOHO_ERROR_STATUS, ZOHO_FAILURE_ERROR_CODE, ZOHO_INTERNAL_ERROR_CODE, ZOHO_INVALID_AUTHORIZATION_ERROR_CODE, ZOHO_INVALID_DATA_ERROR_CODE, ZOHO_INVALID_QUERY_ERROR_CODE, ZOHO_INVALID_TOKEN_ERROR_CODE, ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE, ZOHO_RATE_LIMIT_LIMIT_HEADER, ZOHO_RATE_LIMIT_REMAINING_HEADER, ZOHO_RATE_LIMIT_RESET_HEADER, ZOHO_RECRUIT_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED, ZOHO_RECRUIT_ALREADY_ASSOCIATED_ERROR_CODE, ZOHO_RECRUIT_ATTACHMENTS_MODULE, ZOHO_RECRUIT_ATTACHMENT_MAX_SIZE, ZOHO_RECRUIT_CANDIDATES_MODULE, ZOHO_RECRUIT_CRUD_FUNCTION_MAX_RECORDS_LIMIT, ZOHO_RECRUIT_EMAILS_MODULE, ZOHO_RECRUIT_JOB_OPENINGS_MODULE, ZOHO_RECRUIT_NOTES_MODULE, ZOHO_RECRUIT_RECORD_ATTACHMENT_METADATA_ATTACH_TYPE_RESUME, ZOHO_RECRUIT_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED, ZOHO_RECRUIT_SERVICE_NAME, ZOHO_RECRUIT_TAG_NAME_MAX_LENGTH, ZOHO_SUCCESS_CODE, ZOHO_SUCCESS_STATUS, ZOHO_TOO_MANY_REQUESTS_ERROR_CODE, ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE, ZohoAccountsAccessTokenError, ZohoAccountsAuthFailureError, ZohoCrmExecuteRestApiFunctionError, ZohoCrmRecordCrudDuplicateDataError, ZohoCrmRecordCrudError, ZohoCrmRecordCrudInvalidDataError, ZohoCrmRecordCrudMandatoryFieldNotFoundError, ZohoCrmRecordCrudNoMatchingRecordError, ZohoCrmRecordNoContentError, ZohoInternalError, ZohoInvalidAuthorizationError, ZohoInvalidQueryError, ZohoInvalidTokenError, ZohoRecruitExecuteRestApiFunctionError, ZohoRecruitRecordCrudDuplicateDataError, ZohoRecruitRecordCrudError, ZohoRecruitRecordCrudInvalidDataError, ZohoRecruitRecordCrudMandatoryFieldNotFoundError, ZohoRecruitRecordCrudNoMatchingRecordError, ZohoRecruitRecordNoContentError, ZohoServerError, ZohoServerFetchResponseDataArrayError, ZohoServerFetchResponseError, ZohoTooManyRequestsError, addTagsToRecords, assertRecordDataArrayResultHasContent, assertZohoCrmRecordDataArrayResultHasContent, assertZohoRecruitRecordDataArrayResultHasContent, createNotes, createNotesForRecord, createTagsForModule, deleteAttachmentFromRecord, deleteNotes, deleteRecord, downloadAttachmentForRecord, emptyZohoPageResult, escapeZohoCrmFieldValueForCriteriaString, executeRestApiFunction, getAttachmentsForRecord, getAttachmentsForRecordPageFactory, getEmailsForRecord, getEmailsForRecordPageFactory, getNotesForRecord, getNotesForRecordPageFactory, getRecordById, getRecords, getRelatedRecordsFunctionFactory, getTagsForModule, getTagsForModulePageFactory, handleZohoAccountsErrorFetch, handleZohoCrmErrorFetch, handleZohoErrorFetchFactory, handleZohoRecruitErrorFetch, insertRecord, interceptZohoAccounts200StatusWithErrorResponse, interceptZohoCrm200StatusWithErrorResponse, interceptZohoErrorResponseFactory, interceptZohoRecruit200StatusWithErrorResponse, isZohoCrmValidUrl, isZohoRecruitValidUrl, isZohoServerErrorResponseDataArrayRef, logZohoAccountsErrorToConsole, logZohoCrmErrorToConsole, logZohoRecruitErrorToConsole, logZohoServerErrorFunction, parseZohoAccountsError, parseZohoAccountsServerErrorResponseData, parseZohoCrmError, parseZohoCrmServerErrorResponseData, parseZohoRecruitError, parseZohoRecruitServerErrorResponseData, parseZohoServerErrorResponseData, removeTagsFromRecords, safeZohoDateTimeString, searchRecords, searchRecordsPageFactory, tryFindZohoServerErrorData, updateRecord, uploadAttachmentForRecord, upsertRecord, zohoAccessTokenStringFactory, zohoAccountsAccessToken, zohoAccountsApiFetchJsonInput, zohoAccountsConfigApiUrl, zohoAccountsFactory, zohoAccountsZohoAccessTokenFactory, zohoCrmAddTagsToRecords, zohoCrmAddTagsToRecordsRequestBody, zohoCrmApiFetchJsonInput, zohoCrmCatchZohoCrmChangeObjectLikeResponseError, zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs, zohoCrmConfigApiUrl, zohoCrmCreateNotes, zohoCrmCreateNotesForRecord, zohoCrmCreateTagsForModule, zohoCrmDeleteAttachmentFromRecord, zohoCrmDeleteNotes, zohoCrmDeleteRecord, zohoCrmDeleteTag, zohoCrmDownloadAttachmentForRecord, zohoCrmExecuteRestApiFunction, zohoCrmFactory, zohoCrmGetAttachmentsForRecord, zohoCrmGetAttachmentsForRecordPageFactory, zohoCrmGetEmailsForRecord, zohoCrmGetEmailsForRecordPageFactory, zohoCrmGetNotesForRecord, zohoCrmGetNotesForRecordPageFactory, zohoCrmGetRecordById, zohoCrmGetRecords, zohoCrmGetRelatedRecordsFunctionFactory, zohoCrmGetTagsForModule, zohoCrmGetTagsForModulePageFactory, zohoCrmInsertRecord, zohoCrmMultiRecordResult, zohoCrmRecordCrudError, zohoCrmRemoveTagsFromRecords, zohoCrmSearchRecords, zohoCrmSearchRecordsCriteriaEntryToCriteriaString, zohoCrmSearchRecordsCriteriaString, zohoCrmSearchRecordsCriteriaStringForTree, zohoCrmSearchRecordsPageFactory, zohoCrmUpdateRecord, zohoCrmUploadAttachmentForRecord, zohoCrmUpsertRecord, zohoCrmUrlSearchParams, zohoCrmUrlSearchParamsMinusIdAndModule, zohoCrmUrlSearchParamsMinusModule, zohoDateTimeString, zohoFetchPageFactory, zohoRateLimitHeaderDetails, zohoRateLimitedFetchHandler, zohoRecruitAddTagsToRecords, zohoRecruitApiFetchJsonInput, zohoRecruitAssociateCandidateRecordsWithJobOpenings, zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs, zohoRecruitConfigApiUrl, zohoRecruitCreateNotes, zohoRecruitCreateNotesForRecord, zohoRecruitCreateTagsForModule, zohoRecruitDeleteAttachmentFromRecord, zohoRecruitDeleteNotes, zohoRecruitDeleteRecord, zohoRecruitDownloadAttachmentForRecord, zohoRecruitExecuteRestApiFunction, zohoRecruitFactory, zohoRecruitGetAttachmentsForRecord, zohoRecruitGetAttachmentsForRecordPageFactory, zohoRecruitGetEmailsForRecord, zohoRecruitGetEmailsForRecordPageFactory, zohoRecruitGetNotesForRecord, zohoRecruitGetNotesForRecordPageFactory, zohoRecruitGetRecordById, zohoRecruitGetRecords, zohoRecruitGetRelatedRecordsFunctionFactory, zohoRecruitGetTagsForModule, zohoRecruitGetTagsForModulePageFactory, zohoRecruitInsertRecord, zohoRecruitMultiRecordResult, zohoRecruitRecordCrudError, zohoRecruitRemoveTagsFromRecords, zohoRecruitSearchAssociatedRecords, zohoRecruitSearchCandidateAssociatedJobOpeningRecords, zohoRecruitSearchCandidateAssociatedJobOpeningRecordsPageFactory, zohoRecruitSearchJobOpeningAssociatedCandidateRecords, zohoRecruitSearchJobOpeningAssociatedCandidateRecordsPageFactory, zohoRecruitSearchRecords, zohoRecruitSearchRecordsCriteriaEntryToCriteriaString, zohoRecruitSearchRecordsCriteriaString, zohoRecruitSearchRecordsCriteriaStringForTree, zohoRecruitSearchRecordsPageFactory, zohoRecruitUpdateRecord, zohoRecruitUploadAttachmentForRecord, zohoRecruitUpsertRecord, zohoRecruitUrlSearchParams, zohoRecruitUrlSearchParamsMinusIdAndModule, zohoRecruitUrlSearchParamsMinusModule, zohoServerErrorData };
|
|
4172
|
+
export { DEFAULT_ZOHO_API_RATE_LIMIT, DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD, DEFAULT_ZOHO_RATE_LIMITED_TOO_MANY_REQUETS_LOG_FUNCTION, MAX_ZOHO_CRM_SEARCH_MODULE_RECORDS_CRITERIA, MAX_ZOHO_RECRUIT_SEARCH_MODULE_RECORDS_CRITERIA, ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE, ZOHO_ACCOUNTS_INVALID_CODE_ERROR_CODE, ZOHO_ACCOUNTS_US_API_URL, ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED, ZOHO_CRM_ALREADY_ASSOCIATED_ERROR_CODE, ZOHO_CRM_ATTACHMENTS_MODULE, ZOHO_CRM_ATTACHMENT_MAX_SIZE, ZOHO_CRM_CONTACTS_MODULE, ZOHO_CRM_CRUD_FUNCTION_MAX_RECORDS_LIMIT, ZOHO_CRM_EMAILS_MODULE, ZOHO_CRM_LEADS_MODULE, ZOHO_CRM_NOTES_MODULE, ZOHO_CRM_RECORD_ATTACHMENT_METADATA_ATTACH_TYPE_RESUME, ZOHO_CRM_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED, ZOHO_CRM_SERVICE_NAME, ZOHO_CRM_TAG_NAME_MAX_LENGTH, ZOHO_CRM_TASKS_MODULE, ZOHO_DATA_ARRAY_BLANK_ERROR_CODE, ZOHO_DUPLICATE_DATA_ERROR_CODE, ZOHO_ERROR_STATUS, ZOHO_FAILURE_ERROR_CODE, ZOHO_INTERNAL_ERROR_CODE, ZOHO_INVALID_AUTHORIZATION_ERROR_CODE, ZOHO_INVALID_DATA_ERROR_CODE, ZOHO_INVALID_QUERY_ERROR_CODE, ZOHO_INVALID_TOKEN_ERROR_CODE, ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE, ZOHO_RATE_LIMIT_LIMIT_HEADER, ZOHO_RATE_LIMIT_REMAINING_HEADER, ZOHO_RATE_LIMIT_RESET_HEADER, ZOHO_RECRUIT_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED, ZOHO_RECRUIT_ALREADY_ASSOCIATED_ERROR_CODE, ZOHO_RECRUIT_ATTACHMENTS_MODULE, ZOHO_RECRUIT_ATTACHMENT_MAX_SIZE, ZOHO_RECRUIT_CANDIDATES_MODULE, ZOHO_RECRUIT_CRUD_FUNCTION_MAX_RECORDS_LIMIT, ZOHO_RECRUIT_EMAILS_MODULE, ZOHO_RECRUIT_JOB_OPENINGS_MODULE, ZOHO_RECRUIT_NOTES_MODULE, ZOHO_RECRUIT_RECORD_ATTACHMENT_METADATA_ATTACH_TYPE_RESUME, ZOHO_RECRUIT_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED, ZOHO_RECRUIT_SERVICE_NAME, ZOHO_RECRUIT_TAG_NAME_MAX_LENGTH, ZOHO_SIGN_SERVICE_NAME, ZOHO_SUCCESS_CODE, ZOHO_SUCCESS_STATUS, ZOHO_TOO_MANY_REQUESTS_ERROR_CODE, ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE, ZohoAccountsAccessTokenError, ZohoAccountsAuthFailureError, ZohoCrmExecuteRestApiFunctionError, ZohoCrmRecordCrudDuplicateDataError, ZohoCrmRecordCrudError, ZohoCrmRecordCrudInvalidDataError, ZohoCrmRecordCrudMandatoryFieldNotFoundError, ZohoCrmRecordCrudNoMatchingRecordError, ZohoCrmRecordNoContentError, ZohoInternalError, ZohoInvalidAuthorizationError, ZohoInvalidQueryError, ZohoInvalidTokenError, ZohoRecruitExecuteRestApiFunctionError, ZohoRecruitRecordCrudDuplicateDataError, ZohoRecruitRecordCrudError, ZohoRecruitRecordCrudInvalidDataError, ZohoRecruitRecordCrudMandatoryFieldNotFoundError, ZohoRecruitRecordCrudNoMatchingRecordError, ZohoRecruitRecordNoContentError, ZohoServerError, ZohoServerFetchResponseDataArrayError, ZohoServerFetchResponseError, ZohoTooManyRequestsError, addTagsToRecords, assertRecordDataArrayResultHasContent, assertZohoCrmRecordDataArrayResultHasContent, assertZohoRecruitRecordDataArrayResultHasContent, createNotes, createNotesForRecord, createTagsForModule, deleteAttachmentFromRecord, deleteNotes, deleteRecord, downloadAttachmentForRecord, emptyZohoPageResult, escapeZohoCrmFieldValueForCriteriaString, executeRestApiFunction, getAttachmentsForRecord, getAttachmentsForRecordPageFactory, getEmailsForRecord, getEmailsForRecordPageFactory, getNotesForRecord, getNotesForRecordPageFactory, getRecordById, getRecords, getRelatedRecordsFunctionFactory, getTagsForModule, getTagsForModulePageFactory, handleZohoAccountsErrorFetch, handleZohoCrmErrorFetch, handleZohoErrorFetchFactory, handleZohoRecruitErrorFetch, handleZohoSignErrorFetch, insertRecord, interceptZohoAccounts200StatusWithErrorResponse, interceptZohoCrm200StatusWithErrorResponse, interceptZohoErrorResponseFactory, interceptZohoRecruit200StatusWithErrorResponse, interceptZohoSign200StatusWithErrorResponse, isZohoCrmValidUrl, isZohoRecruitValidUrl, isZohoServerErrorResponseDataArrayRef, logZohoAccountsErrorToConsole, logZohoCrmErrorToConsole, logZohoRecruitErrorToConsole, logZohoServerErrorFunction, logZohoSignErrorToConsole, parseZohoAccountsError, parseZohoAccountsServerErrorResponseData, parseZohoCrmError, parseZohoCrmServerErrorResponseData, parseZohoRecruitError, parseZohoRecruitServerErrorResponseData, parseZohoServerErrorResponseData, parseZohoSignError, parseZohoSignServerErrorResponseData, removeTagsFromRecords, safeZohoDateTimeString, searchRecords, searchRecordsPageFactory, tryFindZohoServerErrorData, updateRecord, uploadAttachmentForRecord, upsertRecord, zohoAccessTokenStringFactory, zohoAccountsAccessToken, zohoAccountsApiFetchJsonInput, zohoAccountsConfigApiUrl, zohoAccountsFactory, zohoAccountsRefreshTokenFromAuthorizationCode, zohoAccountsZohoAccessTokenFactory, zohoCrmAddTagsToRecords, zohoCrmAddTagsToRecordsRequestBody, zohoCrmApiFetchJsonInput, zohoCrmCatchZohoCrmChangeObjectLikeResponseError, zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs, zohoCrmConfigApiUrl, zohoCrmCreateNotes, zohoCrmCreateNotesForRecord, zohoCrmCreateTagsForModule, zohoCrmDeleteAttachmentFromRecord, zohoCrmDeleteNotes, zohoCrmDeleteRecord, zohoCrmDeleteTag, zohoCrmDownloadAttachmentForRecord, zohoCrmExecuteRestApiFunction, zohoCrmFactory, zohoCrmGetAttachmentsForRecord, zohoCrmGetAttachmentsForRecordPageFactory, zohoCrmGetEmailsForRecord, zohoCrmGetEmailsForRecordPageFactory, zohoCrmGetNotesForRecord, zohoCrmGetNotesForRecordPageFactory, zohoCrmGetRecordById, zohoCrmGetRecords, zohoCrmGetRelatedRecordsFunctionFactory, zohoCrmGetTagsForModule, zohoCrmGetTagsForModulePageFactory, zohoCrmInsertRecord, zohoCrmMultiRecordResult, zohoCrmRecordCrudError, zohoCrmRemoveTagsFromRecords, zohoCrmSearchRecords, zohoCrmSearchRecordsCriteriaEntryToCriteriaString, zohoCrmSearchRecordsCriteriaString, zohoCrmSearchRecordsCriteriaStringForTree, zohoCrmSearchRecordsPageFactory, zohoCrmUpdateRecord, zohoCrmUploadAttachmentForRecord, zohoCrmUpsertRecord, zohoCrmUrlSearchParams, zohoCrmUrlSearchParamsMinusIdAndModule, zohoCrmUrlSearchParamsMinusModule, zohoDateTimeString, zohoFetchPageFactory, zohoRateLimitHeaderDetails, zohoRateLimitedFetchHandler, zohoRecruitAddTagsToRecords, zohoRecruitApiFetchJsonInput, zohoRecruitAssociateCandidateRecordsWithJobOpenings, zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs, zohoRecruitConfigApiUrl, zohoRecruitCreateNotes, zohoRecruitCreateNotesForRecord, zohoRecruitCreateTagsForModule, zohoRecruitDeleteAttachmentFromRecord, zohoRecruitDeleteNotes, zohoRecruitDeleteRecord, zohoRecruitDownloadAttachmentForRecord, zohoRecruitExecuteRestApiFunction, zohoRecruitFactory, zohoRecruitGetAttachmentsForRecord, zohoRecruitGetAttachmentsForRecordPageFactory, zohoRecruitGetEmailsForRecord, zohoRecruitGetEmailsForRecordPageFactory, zohoRecruitGetNotesForRecord, zohoRecruitGetNotesForRecordPageFactory, zohoRecruitGetRecordById, zohoRecruitGetRecords, zohoRecruitGetRelatedRecordsFunctionFactory, zohoRecruitGetTagsForModule, zohoRecruitGetTagsForModulePageFactory, zohoRecruitInsertRecord, zohoRecruitMultiRecordResult, zohoRecruitRecordCrudError, zohoRecruitRemoveTagsFromRecords, zohoRecruitSearchAssociatedRecords, zohoRecruitSearchCandidateAssociatedJobOpeningRecords, zohoRecruitSearchCandidateAssociatedJobOpeningRecordsPageFactory, zohoRecruitSearchJobOpeningAssociatedCandidateRecords, zohoRecruitSearchJobOpeningAssociatedCandidateRecordsPageFactory, zohoRecruitSearchRecords, zohoRecruitSearchRecordsCriteriaEntryToCriteriaString, zohoRecruitSearchRecordsCriteriaString, zohoRecruitSearchRecordsCriteriaStringForTree, zohoRecruitSearchRecordsPageFactory, zohoRecruitUpdateRecord, zohoRecruitUploadAttachmentForRecord, zohoRecruitUpsertRecord, zohoRecruitUrlSearchParams, zohoRecruitUrlSearchParamsMinusIdAndModule, zohoRecruitUrlSearchParamsMinusModule, zohoServerErrorData, zohoSignConfigApiUrl, zohoSignCreateDocument, zohoSignDeleteDocument, zohoSignDownloadCompletionCertificate, zohoSignDownloadPdf, zohoSignExtendDocument, zohoSignFactory, zohoSignFetchPageFactory, zohoSignGetDocument, zohoSignGetDocumentFormData, zohoSignGetDocuments, zohoSignGetDocumentsPageFactory, zohoSignRetrieveFieldTypes, zohoSignSendDocumentForSignature, zohoSignUpdateDocument };
|