@unboundcx/sdk 4.6.0 → 4.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -175,6 +175,41 @@ await api.objects.updateById('contacts', 'contact-123', { name: 'Jane' });
175
175
  await api.objects.deleteById('contacts', 'contact-123');
176
176
  await api.objects.describe('contacts'); // Get schema
177
177
  await api.objects.list(); // List all object types
178
+
179
+ // Skip trigger execution on a write (imports / bulk tools)
180
+ await api.objects.updateById({
181
+ object: 'people',
182
+ id: '013…',
183
+ update: { leadScore: 200 },
184
+ skipTriggers: true,
185
+ });
186
+ ```
187
+
188
+ #### Triggers (`api.triggers`)
189
+
190
+ ```javascript
191
+ await api.triggers.listObjects();
192
+ await api.triggers.list({ objectName: 'people', status: 'enabled' });
193
+ await api.triggers.create({
194
+ name: 'Hot lead',
195
+ objectName: 'people',
196
+ actions: ['update'],
197
+ recordFilter: { type: { op: 'eq', value: 'lead' } },
198
+ changeFilters: [
199
+ {
200
+ field: 'leadScore',
201
+ previous: { op: 'lt', value: 20 },
202
+ updated: { op: 'gt', value: 100 },
203
+ },
204
+ ],
205
+ actionType: 'workflow',
206
+ actionConfig: { workflowVersionId: '052…' },
207
+ });
208
+ await api.triggers.get('173…');
209
+ await api.triggers.update('173…', { status: 'paused' });
210
+ await api.triggers.setStatus('173…', 'enabled');
211
+ await api.triggers.listFires('173…', { limit: 20 });
212
+ await api.triggers.delete('173…');
178
213
  ```
179
214
 
180
215
  #### Live Queries (`api.objects.liveQuery`)
@@ -409,7 +444,6 @@ const fileUrl = api.storage.getFileUrl(files[0].storageId);
409
444
  await api.storage.deleteFile(files[0].storageId);
410
445
  ```
411
446
 
412
-
413
447
  #### Documents (`api.documents`)
414
448
 
415
449
  Generic templates → PDF. Implementation: `services/documents.js`.
@@ -419,7 +453,9 @@ Generic templates → PDF. Implementation: `services/documents.js`.
419
453
  const created = await api.documents.templates.create({
420
454
  name: 'Fax cover',
421
455
  engine: 'generative', // or 'overlay' + sourcePdfStorageId
456
+ uses: ['fax'], // omit / [] = every surface
422
457
  });
458
+ await api.documents.templates.list({ status: 'published', use: 'fax' });
423
459
  await api.documents.templates.update(created.id, { draftSchemaJson, draftLayoutJson });
424
460
  await api.documents.templates.publish(created.id);
425
461
 
package/index.js CHANGED
@@ -29,6 +29,7 @@ import { KnowledgeBaseService } from './services/knowledgeBase.js';
29
29
  import { FaxService } from './services/fax.js';
30
30
  import { DocumentsService } from './services/documents.js';
31
31
  import { PermissionsService } from './services/permissions.js';
32
+ import { TriggersService } from './services/triggers.js';
32
33
 
33
34
  class UnboundSDK extends BaseSDK {
34
35
  constructor(options = {}) {
@@ -99,6 +100,7 @@ class UnboundSDK extends BaseSDK {
99
100
  this.fax = new FaxService(this);
100
101
  this.documents = new DocumentsService(this);
101
102
  this.permissions = new PermissionsService(this);
103
+ this.triggers = new TriggersService(this);
102
104
 
103
105
  // Add additional services that might be missing
104
106
  this._initializeAdditionalServices();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.6.0",
3
+ "version": "4.6.1",
4
4
  "description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -9,6 +9,7 @@ export class DocumentTemplatesService {
9
9
  * @param {string} params.name - Template name (required)
10
10
  * @param {string} [params.description]
11
11
  * @param {string} [params.tag]
12
+ * @param {string[]} [params.uses] - Consumer surfaces (`fax`). Empty = all.
12
13
  * @param {'generative'|'overlay'} [params.engine='generative']
13
14
  * @param {string} [params.sourcePdfStorageId] - Required when engine is overlay
14
15
  * @param {Object} [params.draftSchemaJson]
@@ -21,6 +22,7 @@ export class DocumentTemplatesService {
21
22
  name,
22
23
  description,
23
24
  tag,
25
+ uses,
24
26
  engine,
25
27
  sourcePdfStorageId,
26
28
  draftSchemaJson,
@@ -34,6 +36,7 @@ export class DocumentTemplatesService {
34
36
  name: { type: 'string', required: true },
35
37
  description: { type: 'string', required: false },
36
38
  tag: { type: 'string', required: false },
39
+ uses: { type: 'object', required: false },
37
40
  engine: { type: 'string', required: false },
38
41
  sourcePdfStorageId: { type: 'string', required: false },
39
42
  draftSchemaJson: { type: 'object', required: false },
@@ -46,6 +49,7 @@ export class DocumentTemplatesService {
46
49
  const body = { name };
47
50
  if (description !== undefined) body.description = description;
48
51
  if (tag !== undefined) body.tag = tag;
52
+ if (uses !== undefined) body.uses = uses;
49
53
  if (engine !== undefined) body.engine = engine;
50
54
  if (sourcePdfStorageId !== undefined) {
51
55
  body.sourcePdfStorageId = sourcePdfStorageId;
@@ -63,13 +67,15 @@ export class DocumentTemplatesService {
63
67
  * @param {Object} [params]
64
68
  * @param {string} [params.tag]
65
69
  * @param {string} [params.status]
70
+ * @param {string} [params.use] - Consumer surface (`fax`). Empty uses match all.
66
71
  * @param {number} [params.limit]
67
72
  * @returns {Promise<{results: Object[]}>}
68
73
  */
69
- async list({ tag, status, limit } = {}) {
74
+ async list({ tag, status, use, limit } = {}) {
70
75
  const query = {};
71
76
  if (tag) query.tag = tag;
72
77
  if (status) query.status = status;
78
+ if (use) query.use = use;
73
79
  if (limit) query.limit = limit;
74
80
  return this.sdk._fetch('/documents/templates', 'GET', { query });
75
81
  }
@@ -91,6 +97,7 @@ export class DocumentTemplatesService {
91
97
  * @param {string} [params.name]
92
98
  * @param {string} [params.description]
93
99
  * @param {string} [params.tag]
100
+ * @param {string[]} [params.uses]
94
101
  * @param {Object} [params.draftSchemaJson]
95
102
  * @param {Object} [params.draftLayoutJson]
96
103
  * @param {Object} [params.draftPageJson]
@@ -103,6 +110,8 @@ export class DocumentTemplatesService {
103
110
  name,
104
111
  description,
105
112
  tag,
113
+ uses,
114
+ recordTypeId,
106
115
  draftSchemaJson,
107
116
  draftLayoutJson,
108
117
  draftPageJson,
@@ -116,6 +125,8 @@ export class DocumentTemplatesService {
116
125
  name: { type: 'string', required: false },
117
126
  description: { type: 'string', required: false },
118
127
  tag: { type: 'string', required: false },
128
+ uses: { type: 'object', required: false },
129
+ recordTypeId: { type: 'string', required: false },
119
130
  draftSchemaJson: { type: 'object', required: false },
120
131
  draftLayoutJson: { type: 'object', required: false },
121
132
  draftPageJson: { type: 'object', required: false },
@@ -127,6 +138,8 @@ export class DocumentTemplatesService {
127
138
  if (name !== undefined) body.name = name;
128
139
  if (description !== undefined) body.description = description;
129
140
  if (tag !== undefined) body.tag = tag;
141
+ if (uses !== undefined) body.uses = uses;
142
+ if (recordTypeId !== undefined) body.recordTypeId = recordTypeId;
130
143
  if (draftSchemaJson !== undefined) body.draftSchemaJson = draftSchemaJson;
131
144
  if (draftLayoutJson !== undefined) body.draftLayoutJson = draftLayoutJson;
132
145
  if (draftPageJson !== undefined) body.draftPageJson = draftPageJson;
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Triggers Service — object-change automations (workflow or outbound webhook).
3
+ *
4
+ * Watch create/update/delete on a trigger-enabled object, filter on the
5
+ * current row and/or the field that changed, then run a workflow session
6
+ * or POST to a URL.
7
+ *
8
+ * @example
9
+ * const { results } = await sdk.triggers.list({ objectName: 'people' });
10
+ *
11
+ * @example
12
+ * await sdk.triggers.create({
13
+ * name: 'Hot lead',
14
+ * objectName: 'people',
15
+ * actions: ['update'],
16
+ * recordFilter: { type: { op: 'eq', value: 'lead' } },
17
+ * changeFilters: [{
18
+ * field: 'leadScore',
19
+ * previous: { op: 'lt', value: 20 },
20
+ * updated: { op: 'gt', value: 100 },
21
+ * }],
22
+ * actionType: 'workflow',
23
+ * actionConfig: { workflowVersionId: '052…' },
24
+ * });
25
+ */
26
+ export class TriggersService {
27
+ constructor(sdk) {
28
+ this.sdk = sdk;
29
+ }
30
+
31
+ /**
32
+ * List objects that may have triggers (`objectMetaData.triggersEnabled`).
33
+ *
34
+ * @returns {Promise<{results: Array<{id: string, name: string}>}>}
35
+ *
36
+ * @example
37
+ * const { results } = await sdk.triggers.listObjects();
38
+ */
39
+ async listObjects() {
40
+ return this.sdk._fetch('/triggers/objects', 'GET', {});
41
+ }
42
+
43
+ /**
44
+ * List triggers for the account.
45
+ *
46
+ * @param {object} [args]
47
+ * @param {string} [args.objectName] - Filter to one object (e.g. `'people'`)
48
+ * @param {('enabled'|'paused'|'disabled')} [args.status]
49
+ * @param {number} [args.limit=200]
50
+ * @returns {Promise<{results: object[]}>}
51
+ *
52
+ * @example
53
+ * await sdk.triggers.list({ objectName: 'people', status: 'enabled' });
54
+ */
55
+ async list({ objectName, status, limit } = {}) {
56
+ const query = {};
57
+ if (objectName) query.objectName = objectName;
58
+ if (status) query.status = status;
59
+ if (limit) query.limit = limit;
60
+ return this.sdk._fetch('/triggers/', 'GET', { query });
61
+ }
62
+
63
+ /**
64
+ * Get a trigger by id.
65
+ *
66
+ * @param {string} id
67
+ * @returns {Promise<object>}
68
+ *
69
+ * @example
70
+ * const trigger = await sdk.triggers.get('173…');
71
+ */
72
+ async get(id) {
73
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
74
+ return this.sdk._fetch(`/triggers/${id}`, 'GET', {});
75
+ }
76
+
77
+ /**
78
+ * Create a trigger.
79
+ *
80
+ * @param {object} args
81
+ * @param {string} args.name
82
+ * @param {string} [args.description]
83
+ * @param {string} args.objectName - Must have `triggersEnabled` (people, company, opportunities, projects, or custom `__c`)
84
+ * @param {Array<'create'|'update'|'delete'>} args.actions
85
+ * @param {('enabled'|'paused'|'disabled')} [args.status='enabled']
86
+ * @param {Object<string, {op: string, value: *}|*>} [args.recordFilter] - Current-row match (new row on create/update, old on delete)
87
+ * @param {Array<{field: string, previous?: {op: string, value: *}, updated?: {op: string, value: *}}>} [args.changeFilters] - Field must be in `changedFields`; optional previous/updated checks
88
+ * @param {('workflow'|'webhook')} args.actionType
89
+ * @param {object} args.actionConfig
90
+ * @param {string} [args.actionConfig.workflowVersionId] - Required when `actionType` is `'workflow'`
91
+ * @param {string} [args.actionConfig.workflowId]
92
+ * @param {string[]} [args.actionConfig.includeValues] - Field values to include (previous + updated). Empty = names only. `['*']` = every non-encrypted field. Encrypted columns are never sent.
93
+ * @param {string} [args.actionConfig.primaryUrl] - Required when `actionType` is `'webhook'`; must be `https://`
94
+ * @param {string} [args.actionConfig.secondaryUrl] - Failover URL; must be `https://` if set
95
+ * @param {string} [args.actionConfig.credentialId] - Stored webhook authorization id
96
+ * @param {number} [args.timeoutMinutes=15] - Queued-fire TTL, 1–1440
97
+ * @param {number} [args.retries=3] - Webhook retries, 0–5
98
+ * @returns {Promise<object>} Created trigger
99
+ *
100
+ * @example
101
+ * await sdk.triggers.create({
102
+ * name: 'Notify CRM',
103
+ * objectName: 'people',
104
+ * actions: ['update'],
105
+ * actionType: 'webhook',
106
+ * actionConfig: {
107
+ * primaryUrl: 'https://example.com/hooks/lead',
108
+ * secondaryUrl: 'https://backup.example.com/hooks/lead',
109
+ * includeValues: ['leadScore', 'email'],
110
+ * },
111
+ * timeoutMinutes: 15,
112
+ * retries: 3,
113
+ * });
114
+ */
115
+ async create({
116
+ name,
117
+ description,
118
+ objectName,
119
+ actions,
120
+ status,
121
+ recordFilter,
122
+ changeFilters,
123
+ actionType,
124
+ actionConfig,
125
+ timeoutMinutes,
126
+ retries,
127
+ recordTypeId,
128
+ }) {
129
+ const body = {
130
+ name,
131
+ description,
132
+ objectName,
133
+ actions,
134
+ status,
135
+ recordFilter,
136
+ changeFilters,
137
+ actionType,
138
+ actionConfig,
139
+ timeoutMinutes,
140
+ retries,
141
+ recordTypeId,
142
+ };
143
+
144
+ this.sdk.validateParams(
145
+ { name, objectName, actions, actionType, actionConfig },
146
+ {
147
+ name: { type: 'string', required: true },
148
+ objectName: { type: 'string', required: true },
149
+ actions: { type: 'object', required: true },
150
+ actionType: { type: 'string', required: true },
151
+ actionConfig: { type: 'object', required: true },
152
+ },
153
+ );
154
+
155
+ return this.sdk._fetch('/triggers/', 'POST', { body });
156
+ }
157
+
158
+ /**
159
+ * Update a trigger. Only provided fields are changed.
160
+ *
161
+ * @param {string} id
162
+ * @param {object} args - Same shape as {@link TriggersService#create}; all keys optional
163
+ * @returns {Promise<object>} Updated trigger
164
+ *
165
+ * @example
166
+ * await sdk.triggers.update('173…', { status: 'paused' });
167
+ */
168
+ async update(id, args = {}) {
169
+ this.sdk.validateParams(
170
+ { id, args },
171
+ {
172
+ id: { type: 'string', required: true },
173
+ args: { type: 'object', required: true },
174
+ },
175
+ );
176
+ return this.sdk._fetch(`/triggers/${id}`, 'PUT', { body: args });
177
+ }
178
+
179
+ /**
180
+ * Soft-delete a trigger.
181
+ *
182
+ * @param {string} id
183
+ * @returns {Promise<{id: string, deleted: boolean}>}
184
+ *
185
+ * @example
186
+ * await sdk.triggers.delete('173…');
187
+ */
188
+ async delete(id) {
189
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
190
+ return this.sdk._fetch(`/triggers/${id}`, 'DELETE', {});
191
+ }
192
+
193
+ /**
194
+ * Alias of {@link TriggersService#delete}.
195
+ *
196
+ * @param {string} id
197
+ * @returns {Promise<{id: string, deleted: boolean}>}
198
+ */
199
+ async remove(id) {
200
+ return this.delete(id);
201
+ }
202
+
203
+ /**
204
+ * Set trigger status without a full update.
205
+ *
206
+ * @param {string} id
207
+ * @param {('enabled'|'paused'|'disabled')} status
208
+ * @param {object} [opts]
209
+ * @param {string} [opts.pausedReason] - Stored when `status` is `'paused'`
210
+ * @returns {Promise<object>} Updated trigger
211
+ *
212
+ * @example
213
+ * await sdk.triggers.setStatus('173…', 'paused', { pausedReason: 'rate limit' });
214
+ */
215
+ async setStatus(id, status, { pausedReason } = {}) {
216
+ this.sdk.validateParams(
217
+ { id, status },
218
+ {
219
+ id: { type: 'string', required: true },
220
+ status: { type: 'string', required: true },
221
+ },
222
+ );
223
+ return this.sdk._fetch(`/triggers/${id}/status`, 'POST', {
224
+ body: { status, pausedReason },
225
+ });
226
+ }
227
+
228
+ /**
229
+ * Recent execution log for a trigger (queued / fired / dropped / rejected / timeout).
230
+ *
231
+ * @param {string} id
232
+ * @param {object} [opts]
233
+ * @param {number} [opts.limit=50]
234
+ * @returns {Promise<{results: object[]}>}
235
+ *
236
+ * @example
237
+ * const { results } = await sdk.triggers.listFires('173…', { limit: 20 });
238
+ */
239
+ async listFires(id, { limit } = {}) {
240
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
241
+ const query = {};
242
+ if (limit) query.limit = limit;
243
+ return this.sdk._fetch(`/triggers/${id}/fires`, 'GET', { query });
244
+ }
245
+ }
@@ -41,7 +41,7 @@ async function testPublicSDKCompleteness() {
41
41
  'phoneNumbers',
42
42
  'recordTypes',
43
43
  'generateId',
44
- 'documents',
44
+ 'triggers',
45
45
  ];
46
46
 
47
47
  console.log(`📊 Checking ${publicServices.length} public services...`);