quickbase-js 2.3.0 → 2.4.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.
Files changed (62) hide show
  1. package/README.md +145 -1107
  2. package/dist/auth/ticket.d.ts.map +1 -1
  3. package/dist/auth/ticket.js +4 -3
  4. package/dist/auth/ticket.js.map +1 -1
  5. package/dist/client/request.d.ts +4 -0
  6. package/dist/client/request.d.ts.map +1 -1
  7. package/dist/client/request.js +15 -3
  8. package/dist/client/request.js.map +1 -1
  9. package/dist/generated/client.d.ts +2 -0
  10. package/dist/generated/client.d.ts.map +1 -1
  11. package/dist/generated/client.js +134 -113
  12. package/dist/generated/client.js.map +1 -1
  13. package/dist/generated/types.d.ts +2700 -2256
  14. package/dist/generated/types.d.ts.map +1 -1
  15. package/dist/generated/types.js +0 -2
  16. package/dist/generated/types.js.map +1 -1
  17. package/dist/quickbase.esm.js +3 -3
  18. package/dist/quickbase.esm.js.map +3 -3
  19. package/dist/quickbase.min.js +3 -3
  20. package/dist/quickbase.min.js.map +3 -3
  21. package/package.json +16 -13
  22. package/src/auth/index.ts +55 -0
  23. package/src/auth/sso-token.ts +143 -0
  24. package/src/auth/temp-token.ts +160 -0
  25. package/src/auth/ticket.ts +329 -0
  26. package/src/auth/token-cache.ts +97 -0
  27. package/src/auth/types.ts +50 -0
  28. package/src/auth/user-token.ts +38 -0
  29. package/src/cli/schema.ts +512 -0
  30. package/src/client/index.ts +36 -0
  31. package/src/client/pagination.ts +337 -0
  32. package/src/client/request.ts +544 -0
  33. package/src/client/retry.ts +169 -0
  34. package/src/client/throttle.ts +105 -0
  35. package/src/core/config.ts +160 -0
  36. package/src/core/dates.ts +63 -0
  37. package/src/core/errors.ts +349 -0
  38. package/src/core/index.ts +50 -0
  39. package/src/core/logger.ts +113 -0
  40. package/src/core/schema.ts +213 -0
  41. package/src/core/transform.ts +295 -0
  42. package/src/core/types.ts +337 -0
  43. package/src/generated/client.ts +1785 -0
  44. package/src/generated/operations.json +672 -0
  45. package/src/generated/types.ts +4884 -0
  46. package/src/index.ts +259 -0
  47. package/src/xml/codepages.ts +119 -0
  48. package/src/xml/dbvars.ts +75 -0
  49. package/src/xml/errors.ts +133 -0
  50. package/src/xml/fields.ts +121 -0
  51. package/src/xml/groups.ts +560 -0
  52. package/src/xml/html.ts +152 -0
  53. package/src/xml/index.ts +1196 -0
  54. package/src/xml/metadata.ts +111 -0
  55. package/src/xml/records.ts +301 -0
  56. package/src/xml/request.ts +238 -0
  57. package/src/xml/roles.ts +321 -0
  58. package/src/xml/schema.ts +436 -0
  59. package/src/xml/transform.ts +381 -0
  60. package/src/xml/types.ts +602 -0
  61. package/src/xml/users.ts +221 -0
  62. package/src/xml/webhooks.ts +260 -0
@@ -0,0 +1,560 @@
1
+ /**
2
+ * XML API Group Management
3
+ *
4
+ * Endpoints for managing groups and group memberships.
5
+ *
6
+ * XML-API: Remove this file when QuickBase discontinues the XML API.
7
+ * To find all XML API code, search for: XML-API
8
+ */
9
+
10
+ import type {
11
+ XmlCaller,
12
+ Group,
13
+ GroupUser,
14
+ GroupManager,
15
+ Subgroup,
16
+ CreateGroupResult,
17
+ GetUsersInGroupResult,
18
+ GetGroupRoleResult,
19
+ GrantedGroupsResult,
20
+ GrantedDBsForGroupResult,
21
+ } from './types.js';
22
+ import { checkError } from './errors.js';
23
+ import {
24
+ buildRequest,
25
+ escapeXml,
26
+ parseBaseResponse,
27
+ getTagContent,
28
+ getAttribute,
29
+ getAllElements,
30
+ parseXmlNumber,
31
+ parseXmlBool,
32
+ } from './request.js';
33
+
34
+ /**
35
+ * Parse a group element from XML
36
+ */
37
+ function parseGroup(groupXml: string): Group {
38
+ const id = getAttribute(groupXml, 'id');
39
+ const name = getTagContent(groupXml, 'name');
40
+ const description = getTagContent(groupXml, 'description') || undefined;
41
+ const managedByUserStr = getTagContent(groupXml, 'managedByUser');
42
+ const managedByUser = managedByUserStr ? parseXmlBool(managedByUserStr) : undefined;
43
+
44
+ return { id, name, description, managedByUser };
45
+ }
46
+
47
+ /**
48
+ * Parse a user element from GetUsersInGroup response
49
+ */
50
+ function parseGroupUser(userXml: string): GroupUser {
51
+ return {
52
+ id: getAttribute(userXml, 'id'),
53
+ firstName: getTagContent(userXml, 'firstName'),
54
+ lastName: getTagContent(userXml, 'lastName'),
55
+ email: getTagContent(userXml, 'email'),
56
+ screenName: getTagContent(userXml, 'screenName') || undefined,
57
+ isAdmin: parseXmlBool(getTagContent(userXml, 'isAdmin')),
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Parse a manager element from GetUsersInGroup response
63
+ */
64
+ function parseGroupManager(managerXml: string): GroupManager {
65
+ return {
66
+ id: getAttribute(managerXml, 'id'),
67
+ firstName: getTagContent(managerXml, 'firstName'),
68
+ lastName: getTagContent(managerXml, 'lastName'),
69
+ email: getTagContent(managerXml, 'email'),
70
+ screenName: getTagContent(managerXml, 'screenName') || undefined,
71
+ isMember: parseXmlBool(getTagContent(managerXml, 'isMember')),
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Parse a subgroup element
77
+ */
78
+ function parseSubgroup(subgroupXml: string): Subgroup {
79
+ return { id: getAttribute(subgroupXml, 'id') };
80
+ }
81
+
82
+ /**
83
+ * Create a new group.
84
+ *
85
+ * The group will be created with the caller as owner and first member.
86
+ * Caller must be the manager of the account where the group is created.
87
+ *
88
+ * @see https://help.quickbase.com/docs/api-creategroup
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const result = await createGroup(caller, 'MarketingSupport', 'Support staff', '456789');
93
+ * console.log(`Created group: ${result.group.id}`);
94
+ * ```
95
+ */
96
+ export async function createGroup(
97
+ caller: XmlCaller,
98
+ name: string,
99
+ description?: string,
100
+ accountId?: string
101
+ ): Promise<CreateGroupResult> {
102
+ let inner = `<name>${escapeXml(name)}</name>`;
103
+ if (description) {
104
+ inner += `<description>${escapeXml(description)}</description>`;
105
+ }
106
+ if (accountId) {
107
+ inner += `<accountID>${escapeXml(accountId)}</accountID>`;
108
+ }
109
+ const body = buildRequest(inner);
110
+ const xml = await caller.doXml('main', 'API_CreateGroup', body);
111
+
112
+ const base = parseBaseResponse(xml);
113
+ checkError(base);
114
+
115
+ // Parse group element
116
+ const groupMatch = xml.match(/<group[^>]*>([\s\S]*?)<\/group>/);
117
+ if (!groupMatch) {
118
+ throw new Error('Invalid API_CreateGroup response: no group element');
119
+ }
120
+
121
+ const group = parseGroup(groupMatch[0]);
122
+ return { group };
123
+ }
124
+
125
+ /**
126
+ * Delete a group.
127
+ *
128
+ * **Warning:** Once deleted, a group cannot be restored.
129
+ *
130
+ * @see https://help.quickbase.com/docs/api-deletegroup
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * await deleteGroup(caller, '1217.dgpt');
135
+ * ```
136
+ */
137
+ export async function deleteGroup(
138
+ caller: XmlCaller,
139
+ groupId: string
140
+ ): Promise<void> {
141
+ const inner = `<gid>${escapeXml(groupId)}</gid>`;
142
+ const body = buildRequest(inner);
143
+ const xml = await caller.doXml('main', 'API_DeleteGroup', body);
144
+
145
+ const base = parseBaseResponse(xml);
146
+ checkError(base);
147
+ }
148
+
149
+ /**
150
+ * Copy a group.
151
+ *
152
+ * @see https://help.quickbase.com/docs/api-copygroup
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * const result = await copyGroup(caller, '1217.dgpt', 'NewGroupName', 'New description');
157
+ * ```
158
+ */
159
+ export async function copyGroup(
160
+ caller: XmlCaller,
161
+ groupId: string,
162
+ name?: string,
163
+ description?: string,
164
+ accountId?: string
165
+ ): Promise<CreateGroupResult> {
166
+ let inner = `<gid>${escapeXml(groupId)}</gid>`;
167
+ if (name) {
168
+ inner += `<name>${escapeXml(name)}</name>`;
169
+ }
170
+ if (description) {
171
+ inner += `<description>${escapeXml(description)}</description>`;
172
+ }
173
+ if (accountId) {
174
+ inner += `<accountID>${escapeXml(accountId)}</accountID>`;
175
+ }
176
+ const body = buildRequest(inner);
177
+ const xml = await caller.doXml('main', 'API_CopyGroup', body);
178
+
179
+ const base = parseBaseResponse(xml);
180
+ checkError(base);
181
+
182
+ const groupMatch = xml.match(/<group[^>]*>([\s\S]*?)<\/group>/);
183
+ if (!groupMatch) {
184
+ throw new Error('Invalid API_CopyGroup response: no group element');
185
+ }
186
+
187
+ const group = parseGroup(groupMatch[0]);
188
+ return { group };
189
+ }
190
+
191
+ /**
192
+ * Change group information (name, description).
193
+ *
194
+ * @see https://help.quickbase.com/docs/api-changegroupinfo
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * await changeGroupInfo(caller, '1217.dgpt', 'NewName', 'New description');
199
+ * ```
200
+ */
201
+ export async function changeGroupInfo(
202
+ caller: XmlCaller,
203
+ groupId: string,
204
+ name?: string,
205
+ description?: string,
206
+ accountId?: string
207
+ ): Promise<void> {
208
+ let inner = `<gid>${escapeXml(groupId)}</gid>`;
209
+ if (name) {
210
+ inner += `<name>${escapeXml(name)}</name>`;
211
+ }
212
+ if (description) {
213
+ inner += `<description>${escapeXml(description)}</description>`;
214
+ }
215
+ if (accountId) {
216
+ inner += `<accountID>${escapeXml(accountId)}</accountID>`;
217
+ }
218
+ const body = buildRequest(inner);
219
+ const xml = await caller.doXml('main', 'API_ChangeGroupInfo', body);
220
+
221
+ const base = parseBaseResponse(xml);
222
+ checkError(base);
223
+ }
224
+
225
+ /**
226
+ * Get users and managers in a group.
227
+ *
228
+ * @see https://help.quickbase.com/docs/api-getusersingroup
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * const result = await getUsersInGroup(caller, '2345.skdj', true);
233
+ * console.log(`Group: ${result.name}`);
234
+ * console.log(`Users: ${result.users.length}`);
235
+ * console.log(`Managers: ${result.managers.length}`);
236
+ * ```
237
+ */
238
+ export async function getUsersInGroup(
239
+ caller: XmlCaller,
240
+ groupId: string,
241
+ includeManagers?: boolean
242
+ ): Promise<GetUsersInGroupResult> {
243
+ let inner = `<gid>${escapeXml(groupId)}</gid>`;
244
+ if (includeManagers) {
245
+ inner += '<includeAllMgrs>true</includeAllMgrs>';
246
+ }
247
+ const body = buildRequest(inner);
248
+ const xml = await caller.doXml('main', 'API_GetUsersInGroup', body);
249
+
250
+ const base = parseBaseResponse(xml);
251
+ checkError(base);
252
+
253
+ // Parse group element
254
+ const groupMatch = xml.match(/<group[^>]*id="([^"]*)"[^>]*>([\s\S]*?)<\/group>/);
255
+ if (!groupMatch || !groupMatch[1]) {
256
+ throw new Error('Invalid API_GetUsersInGroup response: no group element');
257
+ }
258
+
259
+ const groupXml = groupMatch[0];
260
+ const id = groupMatch[1];
261
+ const name = getTagContent(groupXml, 'name');
262
+ const description = getTagContent(groupXml, 'description') || undefined;
263
+
264
+ // Parse users
265
+ const userElements = getAllElements(groupXml, 'user');
266
+ const users = userElements.map(parseGroupUser);
267
+
268
+ // Parse managers
269
+ const managerElements = getAllElements(groupXml, 'manager');
270
+ const managers = managerElements.map(parseGroupManager);
271
+
272
+ // Parse subgroups
273
+ const subgroupElements = getAllElements(groupXml, 'subgroup');
274
+ const subgroups = subgroupElements.map(parseSubgroup);
275
+
276
+ return { id, name, description, users, managers, subgroups };
277
+ }
278
+
279
+ /**
280
+ * Add a user to a group.
281
+ *
282
+ * The user can be added as member, manager, or both.
283
+ *
284
+ * @see https://help.quickbase.com/docs/api-addusertogroup
285
+ *
286
+ * @example
287
+ * ```typescript
288
+ * // Add as regular member
289
+ * await addUserToGroup(caller, '1217.dgpt', '112149.bhsv');
290
+ *
291
+ * // Add as manager
292
+ * await addUserToGroup(caller, '1217.dgpt', '112149.bhsv', true);
293
+ * ```
294
+ */
295
+ export async function addUserToGroup(
296
+ caller: XmlCaller,
297
+ groupId: string,
298
+ userId: string,
299
+ allowAdminAccess?: boolean
300
+ ): Promise<void> {
301
+ let inner = `<gid>${escapeXml(groupId)}</gid>`;
302
+ inner += `<uid>${escapeXml(userId)}</uid>`;
303
+ if (allowAdminAccess) {
304
+ inner += '<allowAdminAccess>true</allowAdminAccess>';
305
+ }
306
+ const body = buildRequest(inner);
307
+ const xml = await caller.doXml('main', 'API_AddUserToGroup', body);
308
+
309
+ const base = parseBaseResponse(xml);
310
+ checkError(base);
311
+ }
312
+
313
+ /**
314
+ * Remove a user from a group.
315
+ *
316
+ * @see https://help.quickbase.com/docs/api-removeuserfromgroup
317
+ *
318
+ * @example
319
+ * ```typescript
320
+ * await removeUserFromGroup(caller, '1217.dgpt', '112149.bhsv');
321
+ * ```
322
+ */
323
+ export async function removeUserFromGroup(
324
+ caller: XmlCaller,
325
+ groupId: string,
326
+ userId: string
327
+ ): Promise<void> {
328
+ const inner =
329
+ `<gid>${escapeXml(groupId)}</gid>` +
330
+ `<uid>${escapeXml(userId)}</uid>`;
331
+ const body = buildRequest(inner);
332
+ const xml = await caller.doXml('main', 'API_RemoveUserFromGroup', body);
333
+
334
+ const base = parseBaseResponse(xml);
335
+ checkError(base);
336
+ }
337
+
338
+ /**
339
+ * Get roles assigned to a group in an app.
340
+ *
341
+ * @see https://help.quickbase.com/docs/api-getgrouprole
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * const result = await getGroupRole(caller, 'bqxyz123', '1217.dgpt');
346
+ * for (const role of result.roles) {
347
+ * console.log(`Role ${role.id}: ${role.name}`);
348
+ * }
349
+ * ```
350
+ */
351
+ export async function getGroupRole(
352
+ caller: XmlCaller,
353
+ appId: string,
354
+ groupId: string
355
+ ): Promise<GetGroupRoleResult> {
356
+ const inner = `<gid>${escapeXml(groupId)}</gid>`;
357
+ const body = buildRequest(inner);
358
+ const xml = await caller.doXml(appId, 'API_GetGroupRole', body);
359
+
360
+ const base = parseBaseResponse(xml);
361
+ checkError(base);
362
+
363
+ // Parse roles
364
+ const roleElements = getAllElements(xml, 'role');
365
+ const roles = roleElements.map((roleXml) => ({
366
+ id: parseXmlNumber(getAttribute(roleXml, 'id')),
367
+ name: getTagContent(roleXml, 'name'),
368
+ }));
369
+
370
+ return { roles };
371
+ }
372
+
373
+ /**
374
+ * Assign a group to a role in an app.
375
+ *
376
+ * @see https://help.quickbase.com/docs/api-addgrouptorole
377
+ *
378
+ * @example
379
+ * ```typescript
380
+ * await addGroupToRole(caller, 'bqxyz123', '1217.dgpt', 11);
381
+ * ```
382
+ */
383
+ export async function addGroupToRole(
384
+ caller: XmlCaller,
385
+ appId: string,
386
+ groupId: string,
387
+ roleId: number
388
+ ): Promise<void> {
389
+ const inner =
390
+ `<gid>${escapeXml(groupId)}</gid>` +
391
+ `<roleid>${roleId}</roleid>`;
392
+ const body = buildRequest(inner);
393
+ const xml = await caller.doXml(appId, 'API_AddGroupToRole', body);
394
+
395
+ const base = parseBaseResponse(xml);
396
+ checkError(base);
397
+ }
398
+
399
+ /**
400
+ * Remove a group from a role in an app.
401
+ *
402
+ * @see https://help.quickbase.com/docs/api-removegroupfromrole
403
+ *
404
+ * @param allRoles - If true, remove from all roles (ignores roleId)
405
+ *
406
+ * @example
407
+ * ```typescript
408
+ * // Remove from specific role
409
+ * await removeGroupFromRole(caller, 'bqxyz123', '1217.dgpt', 11);
410
+ *
411
+ * // Remove from all roles
412
+ * await removeGroupFromRole(caller, 'bqxyz123', '1217.dgpt', 0, true);
413
+ * ```
414
+ */
415
+ export async function removeGroupFromRole(
416
+ caller: XmlCaller,
417
+ appId: string,
418
+ groupId: string,
419
+ roleId: number,
420
+ allRoles?: boolean
421
+ ): Promise<void> {
422
+ let inner = `<gid>${escapeXml(groupId)}</gid>`;
423
+ if (allRoles) {
424
+ inner += '<allRoles>true</allRoles>';
425
+ } else {
426
+ inner += `<roleid>${roleId}</roleid>`;
427
+ }
428
+ const body = buildRequest(inner);
429
+ const xml = await caller.doXml(appId, 'API_RemoveGroupFromRole', body);
430
+
431
+ const base = parseBaseResponse(xml);
432
+ checkError(base);
433
+ }
434
+
435
+ /**
436
+ * Get groups a user belongs to.
437
+ *
438
+ * If userId is omitted, returns groups for the current user.
439
+ *
440
+ * @see https://help.quickbase.com/docs/api-grantedgroups
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * const result = await grantedGroups(caller, '112149.bhsv');
445
+ * for (const group of result.groups) {
446
+ * console.log(`${group.name} (${group.id})`);
447
+ * }
448
+ * ```
449
+ */
450
+ export async function grantedGroups(
451
+ caller: XmlCaller,
452
+ userId?: string,
453
+ adminOnly?: boolean
454
+ ): Promise<GrantedGroupsResult> {
455
+ let inner = '';
456
+ if (userId) {
457
+ inner += `<userid>${escapeXml(userId)}</userid>`;
458
+ }
459
+ if (adminOnly) {
460
+ inner += '<adminOnly>true</adminOnly>';
461
+ }
462
+ const body = buildRequest(inner);
463
+ const xml = await caller.doXml('main', 'API_GrantedGroups', body);
464
+
465
+ const base = parseBaseResponse(xml);
466
+ checkError(base);
467
+
468
+ // Parse groups
469
+ const groupElements = getAllElements(xml, 'group');
470
+ const groups = groupElements.map((groupXml) => ({
471
+ id: getAttribute(groupXml, 'id'),
472
+ name: getTagContent(groupXml, 'name'),
473
+ }));
474
+
475
+ return { groups };
476
+ }
477
+
478
+ /**
479
+ * Get apps a group can access.
480
+ *
481
+ * @see https://help.quickbase.com/docs/api-granteddbsforgroup
482
+ *
483
+ * @example
484
+ * ```typescript
485
+ * const result = await grantedDBsForGroup(caller, '1217.dgpt');
486
+ * for (const db of result.databases) {
487
+ * console.log(`${db.name} (${db.dbid})`);
488
+ * }
489
+ * ```
490
+ */
491
+ export async function grantedDBsForGroup(
492
+ caller: XmlCaller,
493
+ groupId: string
494
+ ): Promise<GrantedDBsForGroupResult> {
495
+ const inner = `<gid>${escapeXml(groupId)}</gid>`;
496
+ const body = buildRequest(inner);
497
+ const xml = await caller.doXml('main', 'API_GrantedDBsForGroup', body);
498
+
499
+ const base = parseBaseResponse(xml);
500
+ checkError(base);
501
+
502
+ // Parse databases
503
+ const dbElements = getAllElements(xml, 'dbinfo');
504
+ const databases = dbElements.map((dbXml) => ({
505
+ dbid: getTagContent(dbXml, 'dbid'),
506
+ name: getTagContent(dbXml, 'dbname'),
507
+ }));
508
+
509
+ return { databases };
510
+ }
511
+
512
+ /**
513
+ * Add a subgroup to a group.
514
+ *
515
+ * @see https://help.quickbase.com/docs/api-addsubgroup
516
+ *
517
+ * @example
518
+ * ```typescript
519
+ * await addSubgroup(caller, '1217.dgpt', '3450.aefs');
520
+ * ```
521
+ */
522
+ export async function addSubgroup(
523
+ caller: XmlCaller,
524
+ groupId: string,
525
+ subgroupId: string
526
+ ): Promise<void> {
527
+ const inner =
528
+ `<gid>${escapeXml(groupId)}</gid>` +
529
+ `<subgroupid>${escapeXml(subgroupId)}</subgroupid>`;
530
+ const body = buildRequest(inner);
531
+ const xml = await caller.doXml('main', 'API_AddSubgroup', body);
532
+
533
+ const base = parseBaseResponse(xml);
534
+ checkError(base);
535
+ }
536
+
537
+ /**
538
+ * Remove a subgroup from a group.
539
+ *
540
+ * @see https://help.quickbase.com/docs/api-removesubgroup
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * await removeSubgroup(caller, '1217.dgpt', '3450.aefs');
545
+ * ```
546
+ */
547
+ export async function removeSubgroup(
548
+ caller: XmlCaller,
549
+ groupId: string,
550
+ subgroupId: string
551
+ ): Promise<void> {
552
+ const inner =
553
+ `<gid>${escapeXml(groupId)}</gid>` +
554
+ `<subgroupid>${escapeXml(subgroupId)}</subgroupid>`;
555
+ const body = buildRequest(inner);
556
+ const xml = await caller.doXml('main', 'API_RemoveSubgroup', body);
557
+
558
+ const base = parseBaseResponse(xml);
559
+ checkError(base);
560
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * XML API HTML Generation
3
+ *
4
+ * Endpoints for generating HTML forms and tables.
5
+ *
6
+ * XML-API: Remove this file when QuickBase discontinues the XML API.
7
+ * To find all XML API code, search for: XML-API
8
+ */
9
+
10
+ import type { XmlCaller } from './types.js';
11
+ import { checkError } from './errors.js';
12
+ import {
13
+ buildRequest,
14
+ escapeXml,
15
+ parseBaseResponse,
16
+ } from './request.js';
17
+
18
+ /**
19
+ * Generate HTML form for adding a record.
20
+ *
21
+ * @see https://help.quickbase.com/docs/api-genaddrecordform
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const html = await genAddRecordForm(caller, 'bqtable123');
26
+ * // Use the HTML form in your UI
27
+ * ```
28
+ */
29
+ export async function genAddRecordForm(
30
+ caller: XmlCaller,
31
+ tableId: string,
32
+ fields?: Array<{ id: number; value: string }>
33
+ ): Promise<string> {
34
+ let inner = '';
35
+ if (fields) {
36
+ for (const field of fields) {
37
+ inner += `<field fid="${field.id}">${escapeXml(field.value)}</field>`;
38
+ }
39
+ }
40
+
41
+ const body = buildRequest(inner);
42
+ const xml = await caller.doXml(tableId, 'API_GenAddRecordForm', body);
43
+
44
+ // Check for errors - the response may or may not be XML
45
+ if (xml.includes('<errcode>') && !xml.includes('<errcode>0</errcode>')) {
46
+ const base = parseBaseResponse(xml);
47
+ checkError(base);
48
+ }
49
+
50
+ return xml;
51
+ }
52
+
53
+ /**
54
+ * Generate HTML/JS/CSV table of query results.
55
+ *
56
+ * @see https://help.quickbase.com/docs/api-genresultstable
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const html = await genResultsTable(caller, 'bqtable123', {
61
+ * query: "{'7'.CT.'test'}",
62
+ * clist: [6, 7, 8],
63
+ * });
64
+ * ```
65
+ */
66
+ export async function genResultsTable(
67
+ caller: XmlCaller,
68
+ tableId: string,
69
+ options?: {
70
+ query?: string;
71
+ clist?: number[];
72
+ slist?: number[];
73
+ options?: string;
74
+ format?: 'structured' | 'csv';
75
+ }
76
+ ): Promise<string> {
77
+ let inner = '';
78
+
79
+ if (options?.query) {
80
+ inner += `<query>${escapeXml(options.query)}</query>`;
81
+ }
82
+ if (options?.clist && options.clist.length > 0) {
83
+ inner += `<clist>${options.clist.join('.')}</clist>`;
84
+ }
85
+ if (options?.slist && options.slist.length > 0) {
86
+ inner += `<slist>${options.slist.join('.')}</slist>`;
87
+ }
88
+ if (options?.options) {
89
+ inner += `<options>${escapeXml(options.options)}</options>`;
90
+ }
91
+ if (options?.format) {
92
+ inner += `<fmt>${options.format}</fmt>`;
93
+ }
94
+
95
+ const body = buildRequest(inner);
96
+ const xml = await caller.doXml(tableId, 'API_GenResultsTable', body);
97
+
98
+ // Check for errors
99
+ if (xml.includes('<errcode>') && !xml.includes('<errcode>0</errcode>')) {
100
+ const base = parseBaseResponse(xml);
101
+ checkError(base);
102
+ }
103
+
104
+ return xml;
105
+ }
106
+
107
+ /**
108
+ * Get a record rendered as HTML.
109
+ *
110
+ * @see https://help.quickbase.com/docs/api-getrecordashtml
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const html = await getRecordAsHTML(caller, 'bqtable123', { rid: 42 });
115
+ * ```
116
+ */
117
+ export async function getRecordAsHTML(
118
+ caller: XmlCaller,
119
+ tableId: string,
120
+ options: {
121
+ rid?: number;
122
+ key?: string;
123
+ jht?: boolean;
124
+ dfid?: number;
125
+ }
126
+ ): Promise<string> {
127
+ let inner = '';
128
+
129
+ if (options.rid !== undefined) {
130
+ inner += `<rid>${options.rid}</rid>`;
131
+ }
132
+ if (options.key) {
133
+ inner += `<key>${escapeXml(options.key)}</key>`;
134
+ }
135
+ if (options.jht) {
136
+ inner += '<jht>1</jht>';
137
+ }
138
+ if (options.dfid !== undefined) {
139
+ inner += `<dfid>${options.dfid}</dfid>`;
140
+ }
141
+
142
+ const body = buildRequest(inner);
143
+ const xml = await caller.doXml(tableId, 'API_GetRecordAsHTML', body);
144
+
145
+ // Check for errors
146
+ if (xml.includes('<errcode>') && !xml.includes('<errcode>0</errcode>')) {
147
+ const base = parseBaseResponse(xml);
148
+ checkError(base);
149
+ }
150
+
151
+ return xml;
152
+ }