@unboundcx/sdk 4.4.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,263 @@
1
+ export class DocumentTemplatesService {
2
+ constructor(sdk) {
3
+ this.sdk = sdk;
4
+ }
5
+
6
+ /**
7
+ * Create a document template head (draft, no version row).
8
+ * @param {Object} params
9
+ * @param {string} params.name - Template name (required)
10
+ * @param {string} [params.description]
11
+ * @param {string} [params.tag]
12
+ * @param {'generative'|'overlay'} [params.engine='generative']
13
+ * @param {string} [params.sourcePdfStorageId] - Required when engine is overlay
14
+ * @param {Object} [params.draftSchemaJson]
15
+ * @param {Object} [params.draftLayoutJson]
16
+ * @param {Object} [params.draftPageJson]
17
+ * @param {Object} [params.draftThemeJson]
18
+ * @returns {Promise<Object>} Created template (includes draft*)
19
+ */
20
+ async create({
21
+ name,
22
+ description,
23
+ tag,
24
+ engine,
25
+ sourcePdfStorageId,
26
+ draftSchemaJson,
27
+ draftLayoutJson,
28
+ draftPageJson,
29
+ draftThemeJson,
30
+ }) {
31
+ this.sdk.validateParams(
32
+ { name },
33
+ {
34
+ name: { type: 'string', required: true },
35
+ description: { type: 'string', required: false },
36
+ tag: { type: 'string', required: false },
37
+ engine: { type: 'string', required: false },
38
+ sourcePdfStorageId: { type: 'string', required: false },
39
+ draftSchemaJson: { type: 'object', required: false },
40
+ draftLayoutJson: { type: 'object', required: false },
41
+ draftPageJson: { type: 'object', required: false },
42
+ draftThemeJson: { type: 'object', required: false },
43
+ },
44
+ );
45
+
46
+ const body = { name };
47
+ if (description !== undefined) body.description = description;
48
+ if (tag !== undefined) body.tag = tag;
49
+ if (engine !== undefined) body.engine = engine;
50
+ if (sourcePdfStorageId !== undefined) {
51
+ body.sourcePdfStorageId = sourcePdfStorageId;
52
+ }
53
+ if (draftSchemaJson !== undefined) body.draftSchemaJson = draftSchemaJson;
54
+ if (draftLayoutJson !== undefined) body.draftLayoutJson = draftLayoutJson;
55
+ if (draftPageJson !== undefined) body.draftPageJson = draftPageJson;
56
+ if (draftThemeJson !== undefined) body.draftThemeJson = draftThemeJson;
57
+
58
+ return this.sdk._fetch('/documents/templates', 'POST', { body });
59
+ }
60
+
61
+ /**
62
+ * List document templates (not deleted). Returns draft* for authoring.
63
+ * @param {Object} [params]
64
+ * @param {string} [params.tag]
65
+ * @param {string} [params.status]
66
+ * @param {number} [params.limit]
67
+ * @returns {Promise<{results: Object[]}>}
68
+ */
69
+ async list({ tag, status, limit } = {}) {
70
+ const query = {};
71
+ if (tag) query.tag = tag;
72
+ if (status) query.status = status;
73
+ if (limit) query.limit = limit;
74
+ return this.sdk._fetch('/documents/templates', 'GET', { query });
75
+ }
76
+
77
+ /**
78
+ * Get a document template by id (head + draft* + published version if any).
79
+ * @param {string} id
80
+ * @returns {Promise<Object>}
81
+ */
82
+ async get(id) {
83
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
84
+ return this.sdk._fetch(`/documents/templates/${id}`, 'GET');
85
+ }
86
+
87
+ /**
88
+ * Update name/description/tag/draft*. Cannot change engine.
89
+ * @param {string} id
90
+ * @param {Object} params
91
+ * @param {string} [params.name]
92
+ * @param {string} [params.description]
93
+ * @param {string} [params.tag]
94
+ * @param {Object} [params.draftSchemaJson]
95
+ * @param {Object} [params.draftLayoutJson]
96
+ * @param {Object} [params.draftPageJson]
97
+ * @param {Object} [params.draftThemeJson]
98
+ * @returns {Promise<Object>}
99
+ */
100
+ async update(
101
+ id,
102
+ {
103
+ name,
104
+ description,
105
+ tag,
106
+ draftSchemaJson,
107
+ draftLayoutJson,
108
+ draftPageJson,
109
+ draftThemeJson,
110
+ } = {},
111
+ ) {
112
+ this.sdk.validateParams(
113
+ { id },
114
+ {
115
+ id: { type: 'string', required: true },
116
+ name: { type: 'string', required: false },
117
+ description: { type: 'string', required: false },
118
+ tag: { type: 'string', required: false },
119
+ draftSchemaJson: { type: 'object', required: false },
120
+ draftLayoutJson: { type: 'object', required: false },
121
+ draftPageJson: { type: 'object', required: false },
122
+ draftThemeJson: { type: 'object', required: false },
123
+ },
124
+ );
125
+
126
+ const body = {};
127
+ if (name !== undefined) body.name = name;
128
+ if (description !== undefined) body.description = description;
129
+ if (tag !== undefined) body.tag = tag;
130
+ if (draftSchemaJson !== undefined) body.draftSchemaJson = draftSchemaJson;
131
+ if (draftLayoutJson !== undefined) body.draftLayoutJson = draftLayoutJson;
132
+ if (draftPageJson !== undefined) body.draftPageJson = draftPageJson;
133
+ if (draftThemeJson !== undefined) body.draftThemeJson = draftThemeJson;
134
+
135
+ return this.sdk._fetch(`/documents/templates/${id}`, 'PATCH', { body });
136
+ }
137
+
138
+ /**
139
+ * Snapshot draft* into a new published version and set currentVersionId.
140
+ * @param {string} id
141
+ * @returns {Promise<Object>}
142
+ */
143
+ async publish(id) {
144
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
145
+ return this.sdk._fetch(`/documents/templates/${id}/publish`, 'POST', {
146
+ body: {},
147
+ });
148
+ }
149
+
150
+ /**
151
+ * Soft-delete a document template.
152
+ * @param {string} id
153
+ * @returns {Promise<{id: string, deleted: boolean}>}
154
+ */
155
+ async delete(id) {
156
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
157
+ return this.sdk._fetch(`/documents/templates/${id}`, 'DELETE');
158
+ }
159
+ }
160
+
161
+ export class DocumentsService {
162
+ constructor(sdk) {
163
+ this.sdk = sdk;
164
+ this.templates = new DocumentTemplatesService(sdk);
165
+ }
166
+
167
+ /**
168
+ * Generate a PDF from the published template version.
169
+ * @param {Object} params
170
+ * @param {string} params.templateId
171
+ * @param {Object} params.data
172
+ * @param {string} [params.versionId]
173
+ * @param {Object} [params.options]
174
+ * @param {string} [params.options.filename]
175
+ * @param {Object} [params.source]
176
+ * @param {string} [params.source.type]
177
+ * @param {string} [params.source.id]
178
+ * @returns {Promise<Object>}
179
+ */
180
+ async generate({ templateId, data, versionId, options, source }) {
181
+ this.sdk.validateParams(
182
+ { templateId, data },
183
+ {
184
+ templateId: { type: 'string', required: true },
185
+ data: { type: 'object', required: true },
186
+ versionId: { type: 'string', required: false },
187
+ options: { type: 'object', required: false },
188
+ source: { type: 'object', required: false },
189
+ },
190
+ );
191
+
192
+ const body = { templateId, data };
193
+ if (versionId !== undefined) body.versionId = versionId;
194
+ if (options !== undefined) body.options = options;
195
+ if (source !== undefined) body.source = source;
196
+
197
+ return this.sdk._fetch('/documents/generate', 'POST', { body });
198
+ }
199
+
200
+ /**
201
+ * Preview a PDF from draft* (or a specific versionId). isPreview=1.
202
+ * @param {Object} params
203
+ * @param {string} params.templateId
204
+ * @param {Object} [params.data]
205
+ * @param {string} [params.versionId]
206
+ * @returns {Promise<Object>}
207
+ */
208
+ async preview({ templateId, data, versionId }) {
209
+ this.sdk.validateParams(
210
+ { templateId },
211
+ {
212
+ templateId: { type: 'string', required: true },
213
+ data: { type: 'object', required: false },
214
+ versionId: { type: 'string', required: false },
215
+ },
216
+ );
217
+
218
+ const body = { templateId };
219
+ if (data !== undefined) body.data = data;
220
+ if (versionId !== undefined) body.versionId = versionId;
221
+
222
+ return this.sdk._fetch('/documents/preview', 'POST', { body });
223
+ }
224
+
225
+ /**
226
+ * Attach a consumer id (e.g. fax document) after send.
227
+ * @param {Object} params
228
+ * @param {string} params.id - generatedDocuments id
229
+ * @param {string} [params.sourceId]
230
+ * @param {string} [params.sourceType]
231
+ * @returns {Promise<Object>}
232
+ */
233
+ async updateGenerated({ id, sourceId, sourceType }) {
234
+ this.sdk.validateParams(
235
+ { id },
236
+ {
237
+ id: { type: 'string', required: true },
238
+ sourceId: { type: 'string', required: false },
239
+ sourceType: { type: 'string', required: false },
240
+ },
241
+ );
242
+
243
+ const body = {};
244
+ if (sourceId !== undefined) body.sourceId = sourceId;
245
+ if (sourceType !== undefined) body.sourceType = sourceType;
246
+
247
+ return this.sdk._fetch(`/documents/generated/${id}`, 'PATCH', { body });
248
+ }
249
+
250
+ /**
251
+ * Page count / size for a stored PDF.
252
+ * @param {Object} params
253
+ * @param {string} params.storageId
254
+ * @returns {Promise<{pageCount: number, pageSize: string|null}>}
255
+ */
256
+ async inspect({ storageId }) {
257
+ this.sdk.validateParams(
258
+ { storageId },
259
+ { storageId: { type: 'string', required: true } },
260
+ );
261
+ return this.sdk._fetch('/documents/inspect', 'POST', { body: { storageId } });
262
+ }
263
+ }
@@ -141,6 +141,7 @@ export class ExternalOAuthService {
141
141
  scopes,
142
142
  authorizationUrl,
143
143
  tokenUrl,
144
+ fromConnectionId,
144
145
  }) {
145
146
  this.sdk.validateParams(
146
147
  { name, provider },
@@ -152,6 +153,7 @@ export class ExternalOAuthService {
152
153
  scopes: { type: 'array', required: false },
153
154
  authorizationUrl: { type: 'string', required: false },
154
155
  tokenUrl: { type: 'string', required: false },
156
+ fromConnectionId: { type: 'string', required: false },
155
157
  },
156
158
  );
157
159
 
@@ -161,10 +163,30 @@ export class ExternalOAuthService {
161
163
  if (scopes) body.scopes = scopes;
162
164
  if (authorizationUrl) body.authorizationUrl = authorizationUrl;
163
165
  if (tokenUrl) body.tokenUrl = tokenUrl;
166
+ if (fromConnectionId) body.fromConnectionId = fromConnectionId;
164
167
 
165
168
  const result = await this.sdk._fetch('/externalOAuth/authorize', 'POST', {
166
169
  body,
167
170
  });
168
171
  return result;
169
172
  }
173
+
174
+ /**
175
+ * Check whether a connection can be used for a purpose (e.g. Google Ads / Meta ads).
176
+ *
177
+ * @param {string} id
178
+ * @param {object} [args]
179
+ * @param {string} [args.purpose='googleAds']
180
+ * @returns {Promise<object>}
181
+ */
182
+ async verify(id, { purpose = 'googleAds' } = {}) {
183
+ this.sdk.validateParams(
184
+ { id },
185
+ { id: { type: 'string', required: true } },
186
+ );
187
+
188
+ return this.sdk._fetch(`/externalOAuth/${id}/verify`, 'POST', {
189
+ body: { purpose },
190
+ });
191
+ }
170
192
  }
package/services/fax.js CHANGED
@@ -78,6 +78,8 @@ export class FaxService {
78
78
  * Required if pdfStorageId and tiffStorageId are not provided.
79
79
  * @param {string} [options.pdfStorageId] - Storage ID of the PDF version. Required if storageId is not provided.
80
80
  * @param {string} [options.tiffStorageId] - Storage ID of the TIFF version. Required if storageId is not provided.
81
+ * @param {string} [options.coverStorageId] - Optional cover PDF (or TIFF). Concatenated in front of the body before TIFF convert.
82
+ * @param {('letter'|'legal'|'a4')} [options.paperSize] - Paper size hint for TIFF conversion. Server also reads PDF MediaBox.
81
83
  * @param {string} [options.faxHeader] - TSI header text (defaults to mailbox faxHeader)
82
84
  * @param {string} [options.resolution] - Fax resolution (defaults to mailbox resolution)
83
85
  * @param {boolean} [options.ecm] - Enable Error Correction Mode (default: true)
@@ -95,6 +97,8 @@ export class FaxService {
95
97
  * toNumber: '+15551234567',
96
98
  * fromNumber: '+15559876543',
97
99
  * storageId: '017xyz788...',
100
+ * paperSize: 'legal',
101
+ * coverStorageId: '017cover...',
98
102
  * });
99
103
  * console.log(result.id); // '158def456...'
100
104
  * console.log(result.status); // 'sending'
@@ -120,13 +124,15 @@ export class FaxService {
120
124
  storageId,
121
125
  pdfStorageId,
122
126
  tiffStorageId,
127
+ coverStorageId,
128
+ paperSize,
123
129
  faxHeader,
124
130
  resolution,
125
131
  ecm,
126
132
  timeout,
127
133
  }) {
128
134
  this.sdk.validateParams(
129
- { faxMailboxId, toNumber, fromNumber },
135
+ { faxMailboxId, toNumber, fromNumber, coverStorageId, paperSize },
130
136
  {
131
137
  faxMailboxId: { type: 'string', required: true },
132
138
  toNumber: { type: 'string', required: true },
@@ -134,6 +140,8 @@ export class FaxService {
134
140
  storageId: { type: 'string', required: false },
135
141
  pdfStorageId: { type: 'string', required: false },
136
142
  tiffStorageId: { type: 'string', required: false },
143
+ coverStorageId: { type: 'string', required: false },
144
+ paperSize: { type: 'string', required: false },
137
145
  },
138
146
  );
139
147
 
@@ -151,6 +159,8 @@ export class FaxService {
151
159
  storageId,
152
160
  pdfStorageId,
153
161
  tiffStorageId,
162
+ coverStorageId,
163
+ paperSize,
154
164
  faxHeader,
155
165
  resolution,
156
166
  ecm,
@@ -117,15 +117,20 @@ class LiveQueryHandle {
117
117
  filter,
118
118
  fields,
119
119
  recordTypeId,
120
+ uoql,
120
121
  onEvent,
121
122
  onStateChange,
122
123
  }) {
123
124
  this.manager = manager;
124
125
  this.socket = socket;
125
- this.object = object;
126
+ // Internal bookkeeping/log labels need an object-name-shaped string even
127
+ // in uoql mode - use the literal 'uoql' there (no single object name
128
+ // exists yet, that's resolved server-side by analyze()).
129
+ this.object = uoql !== undefined ? 'uoql' : object;
126
130
  this.filter = filter;
127
131
  this.fields = fields;
128
132
  this.recordTypeId = recordTypeId;
133
+ this.uoql = uoql;
129
134
  this.onEvent = onEvent;
130
135
  this.onStateChange = onStateChange;
131
136
 
@@ -136,7 +141,10 @@ class LiveQueryHandle {
136
141
  }
137
142
 
138
143
  async _subscribe() {
139
- const payload = { objectName: this.object, filter: this.filter, fields: this.fields };
144
+ const payload =
145
+ this.uoql !== undefined
146
+ ? { uoql: this.uoql }
147
+ : { objectName: this.object, filter: this.filter, fields: this.fields };
140
148
  if (this.recordTypeId !== undefined) payload.recordTypeId = this.recordTypeId;
141
149
 
142
150
  const ack = await new Promise((resolve, reject) => {
@@ -249,6 +257,11 @@ class LiveQueryHandle {
249
257
  * this account; falls back to `sdk.socket` if the sdk instance holds one.
250
258
  * - object, filter, fields, recordTypeId: subscribe-time query, same shape
251
259
  * as `sdk.objects.query`.
260
+ * - uoql: subscribe-time query as a UOQL string instead - mutually exclusive
261
+ * with object/filter/fields/recordTypeId (throws synchronously if both, or
262
+ * neither, are given). Sent to the server as `{ uoql }`; the server runs
263
+ * uoql analyze() to resolve it to a fine or coarse subscription. Also
264
+ * re-sent verbatim on reconnect resubscribe.
252
265
  * - onEvent(frame): called for every 'enter'|'change'|'leave'|'refresh'|
253
266
  * 'resync'|'revoked' frame (resync frames are also synthesized locally on
254
267
  * seq gaps and on reconnect).
@@ -257,7 +270,7 @@ class LiveQueryHandle {
257
270
  * Resolves to { subscriptionId, mode, unsubscribe() }.
258
271
  */
259
272
  export async function liveQuery(sdk, args = {}) {
260
- const { socket: providedSocket, object, filter, fields, recordTypeId, onEvent, onStateChange } = args;
273
+ const { socket: providedSocket, object, filter, fields, recordTypeId, uoql, onEvent, onStateChange } = args;
261
274
 
262
275
  const socket = providedSocket || sdk.socket;
263
276
  if (!socket || typeof socket.emit !== 'function' || typeof socket.on !== 'function') {
@@ -267,8 +280,15 @@ export async function liveQuery(sdk, args = {}) {
267
280
  'deviation from the locked liveQuery contract, see plan Phase 3',
268
281
  );
269
282
  }
270
- if (!object) {
271
- throw new Error('liveQuery :: init :: object is required');
283
+
284
+ const hasObjectForm = object !== undefined || filter !== undefined || fields !== undefined || recordTypeId !== undefined;
285
+ if (uoql !== undefined && hasObjectForm) {
286
+ throw new Error(
287
+ 'liveQuery :: init :: uoql is mutually exclusive with object/filter/fields/recordTypeId',
288
+ );
289
+ }
290
+ if (uoql === undefined && !object) {
291
+ throw new Error('liveQuery :: init :: either uoql or object is required');
272
292
  }
273
293
 
274
294
  const manager = getSocketManager(socket);
@@ -279,6 +299,7 @@ export async function liveQuery(sdk, args = {}) {
279
299
  filter,
280
300
  fields,
281
301
  recordTypeId,
302
+ uoql,
282
303
  onEvent,
283
304
  onStateChange,
284
305
  });