quickbase-js 2.4.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 (46) hide show
  1. package/README.md +144 -76
  2. package/dist/quickbase.esm.js +3 -3
  3. package/dist/quickbase.min.js +3 -3
  4. package/dist/quickbase.min.js.map +1 -1
  5. package/package.json +13 -9
  6. package/src/auth/index.ts +55 -0
  7. package/src/auth/sso-token.ts +143 -0
  8. package/src/auth/temp-token.ts +160 -0
  9. package/src/auth/ticket.ts +329 -0
  10. package/src/auth/token-cache.ts +97 -0
  11. package/src/auth/types.ts +50 -0
  12. package/src/auth/user-token.ts +38 -0
  13. package/src/cli/schema.ts +512 -0
  14. package/src/client/index.ts +36 -0
  15. package/src/client/pagination.ts +337 -0
  16. package/src/client/request.ts +544 -0
  17. package/src/client/retry.ts +169 -0
  18. package/src/client/throttle.ts +105 -0
  19. package/src/core/config.ts +160 -0
  20. package/src/core/dates.ts +63 -0
  21. package/src/core/errors.ts +349 -0
  22. package/src/core/index.ts +50 -0
  23. package/src/core/logger.ts +113 -0
  24. package/src/core/schema.ts +213 -0
  25. package/src/core/transform.ts +295 -0
  26. package/src/core/types.ts +337 -0
  27. package/src/generated/client.ts +1785 -0
  28. package/src/generated/operations.json +672 -0
  29. package/src/generated/types.ts +4884 -0
  30. package/src/index.ts +259 -0
  31. package/src/xml/codepages.ts +119 -0
  32. package/src/xml/dbvars.ts +75 -0
  33. package/src/xml/errors.ts +133 -0
  34. package/src/xml/fields.ts +121 -0
  35. package/src/xml/groups.ts +560 -0
  36. package/src/xml/html.ts +152 -0
  37. package/src/xml/index.ts +1196 -0
  38. package/src/xml/metadata.ts +111 -0
  39. package/src/xml/records.ts +301 -0
  40. package/src/xml/request.ts +238 -0
  41. package/src/xml/roles.ts +321 -0
  42. package/src/xml/schema.ts +436 -0
  43. package/src/xml/transform.ts +381 -0
  44. package/src/xml/types.ts +602 -0
  45. package/src/xml/users.ts +221 -0
  46. package/src/xml/webhooks.ts +260 -0
@@ -0,0 +1,321 @@
1
+ /**
2
+ * XML API Role Management
3
+ *
4
+ * Endpoints for managing roles and user role assignments.
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
+ Role,
13
+ RoleAccess,
14
+ UserRole,
15
+ RoleMember,
16
+ UserWithRoles,
17
+ GetRoleInfoResult,
18
+ UserRolesResult,
19
+ GetUserRoleResult,
20
+ } from './types.js';
21
+ import { checkError } from './errors.js';
22
+ import {
23
+ buildRequest,
24
+ escapeXml,
25
+ parseBaseResponse,
26
+ getTagContent,
27
+ getAttribute,
28
+ getAllElements,
29
+ parseXmlNumber,
30
+ } from './request.js';
31
+
32
+ /**
33
+ * Parse a single role element from XML
34
+ */
35
+ function parseRole(roleXml: string): Role {
36
+ const id = parseXmlNumber(getAttribute(roleXml, 'id'));
37
+ const name = getTagContent(roleXml, 'name');
38
+
39
+ // Parse access element
40
+ const accessMatch = roleXml.match(/<access[^>]*id="(\d+)"[^>]*>([^<]*)<\/access>/);
41
+ const access: RoleAccess = {
42
+ id: accessMatch ? parseXmlNumber(accessMatch[1] ?? '0') : 0,
43
+ description: accessMatch?.[2] ?? '',
44
+ };
45
+
46
+ return { id, name, access };
47
+ }
48
+
49
+ /**
50
+ * Parse a role with member info (from GetUserRole with inclgrps)
51
+ */
52
+ function parseUserRole(roleXml: string): UserRole {
53
+ const role = parseRole(roleXml);
54
+
55
+ // Parse member element if present
56
+ const memberMatch = roleXml.match(/<member[^>]*type="([^"]*)"[^>]*>([^<]*)<\/member>/);
57
+ const member: RoleMember | undefined = memberMatch && memberMatch[1] && memberMatch[2]
58
+ ? { type: memberMatch[1], name: memberMatch[2] }
59
+ : undefined;
60
+
61
+ return { ...role, member };
62
+ }
63
+
64
+ /**
65
+ * Parse a user with roles from UserRoles response
66
+ */
67
+ function parseUserWithRoles(userXml: string): UserWithRoles {
68
+ const id = getAttribute(userXml, 'id');
69
+ const type = getAttribute(userXml, 'type') || 'user';
70
+ const name = getTagContent(userXml, 'name');
71
+ const firstName = getTagContent(userXml, 'firstName') || undefined;
72
+ const lastName = getTagContent(userXml, 'lastName') || undefined;
73
+ const lastAccess = getTagContent(userXml, 'lastAccess') || undefined;
74
+ const lastAccessAppLocal = getTagContent(userXml, 'lastAccessAppLocal') || undefined;
75
+
76
+ // Parse roles
77
+ const roleElements = getAllElements(userXml, 'role');
78
+ const roles = roleElements.map(parseRole);
79
+
80
+ return {
81
+ id,
82
+ type,
83
+ name,
84
+ firstName,
85
+ lastName,
86
+ lastAccess,
87
+ lastAccessAppLocal,
88
+ roles,
89
+ };
90
+ }
91
+
92
+ /**
93
+ * Get all roles defined in an application.
94
+ *
95
+ * @see https://help.quickbase.com/docs/api-getroleinfo
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * const result = await getRoleInfo(caller, 'bqxyz123');
100
+ * for (const role of result.roles) {
101
+ * console.log(`Role ${role.id}: ${role.name} (${role.access.description})`);
102
+ * }
103
+ * ```
104
+ */
105
+ export async function getRoleInfo(
106
+ caller: XmlCaller,
107
+ appId: string
108
+ ): Promise<GetRoleInfoResult> {
109
+ const body = buildRequest('');
110
+ const xml = await caller.doXml(appId, 'API_GetRoleInfo', body);
111
+
112
+ const base = parseBaseResponse(xml);
113
+ checkError(base);
114
+
115
+ // Parse roles
116
+ const roleElements = getAllElements(xml, 'role');
117
+ const roles = roleElements.map(parseRole);
118
+
119
+ return { roles };
120
+ }
121
+
122
+ /**
123
+ * Get all users in an application and their role assignments.
124
+ *
125
+ * Requires Basic Access with Sharing or Full Administration access.
126
+ *
127
+ * @see https://help.quickbase.com/docs/api-userroles
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * const result = await userRoles(caller, 'bqxyz123');
132
+ * for (const user of result.users) {
133
+ * console.log(`${user.name}: ${user.roles.map(r => r.name).join(', ')}`);
134
+ * }
135
+ * ```
136
+ */
137
+ export async function userRoles(
138
+ caller: XmlCaller,
139
+ appId: string
140
+ ): Promise<UserRolesResult> {
141
+ const body = buildRequest('');
142
+ const xml = await caller.doXml(appId, 'API_UserRoles', body);
143
+
144
+ const base = parseBaseResponse(xml);
145
+ checkError(base);
146
+
147
+ // Parse users
148
+ const userElements = getAllElements(xml, 'user');
149
+ const users = userElements.map(parseUserWithRoles);
150
+
151
+ return { users };
152
+ }
153
+
154
+ /**
155
+ * Get roles for a specific user.
156
+ *
157
+ * If userId is omitted, returns your own roles.
158
+ * Set includeGroups to true to include roles assigned via groups.
159
+ *
160
+ * @see https://help.quickbase.com/docs/api-getuserrole
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * const result = await getUserRole(caller, 'bqxyz123', '112149.bhsv', true);
165
+ * console.log(`User: ${result.userName}`);
166
+ * for (const role of result.roles) {
167
+ * if (role.member) {
168
+ * console.log(` ${role.name} (via ${role.member.type}: ${role.member.name})`);
169
+ * } else {
170
+ * console.log(` ${role.name}`);
171
+ * }
172
+ * }
173
+ * ```
174
+ */
175
+ export async function getUserRole(
176
+ caller: XmlCaller,
177
+ appId: string,
178
+ userId?: string,
179
+ includeGroups?: boolean
180
+ ): Promise<GetUserRoleResult> {
181
+ let inner = '';
182
+ if (userId) {
183
+ inner += `<userid>${escapeXml(userId)}</userid>`;
184
+ }
185
+ if (includeGroups) {
186
+ inner += '<inclgrps>1</inclgrps>';
187
+ }
188
+ const body = buildRequest(inner);
189
+ const xml = await caller.doXml(appId, 'API_GetUserRole', body);
190
+
191
+ const base = parseBaseResponse(xml);
192
+ checkError(base);
193
+
194
+ // Parse user element
195
+ const userMatch = xml.match(/<user[^>]*id="([^"]*)"[^>]*>([\s\S]*?)<\/user>/);
196
+ if (!userMatch || !userMatch[1]) {
197
+ throw new Error('Invalid API_GetUserRole response: no user element');
198
+ }
199
+
200
+ const userIdResult = userMatch[1];
201
+ const userXml = userMatch[0];
202
+ const userName = getTagContent(userXml, 'name');
203
+
204
+ // Parse roles (with member info if inclgrps was used)
205
+ const roleElements = getAllElements(userXml, 'role');
206
+ const roles = roleElements.map(parseUserRole);
207
+
208
+ return {
209
+ userId: userIdResult,
210
+ userName,
211
+ roles,
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Assign a user to a role.
217
+ *
218
+ * You can call this multiple times to give a user multiple roles.
219
+ * After assigning, use sendInvitation to invite the user.
220
+ *
221
+ * Requires Basic Access with Sharing or Full Administration access.
222
+ * Users with Basic Access cannot add users to admin roles.
223
+ *
224
+ * @see https://help.quickbase.com/docs/api-addusertorole
225
+ *
226
+ * @example
227
+ * ```typescript
228
+ * await addUserToRole(caller, 'bqxyz123', '112149.bhsv', 10);
229
+ * ```
230
+ */
231
+ export async function addUserToRole(
232
+ caller: XmlCaller,
233
+ appId: string,
234
+ userId: string,
235
+ roleId: number
236
+ ): Promise<void> {
237
+ const inner =
238
+ `<userid>${escapeXml(userId)}</userid>` +
239
+ `<roleid>${roleId}</roleid>`;
240
+ const body = buildRequest(inner);
241
+ const xml = await caller.doXml(appId, 'API_AddUserToRole', body);
242
+
243
+ const base = parseBaseResponse(xml);
244
+ checkError(base);
245
+ }
246
+
247
+ /**
248
+ * Remove a user from a specific role.
249
+ *
250
+ * If this is the user's only role, they lose all access to the app
251
+ * and are removed from the app's user list.
252
+ *
253
+ * To temporarily disable access while keeping the user in the app,
254
+ * use changeUserRole with newRoleId=0 instead.
255
+ *
256
+ * @see https://help.quickbase.com/docs/api-removeuserfromrole
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * await removeUserFromRole(caller, 'bqxyz123', '112149.bhsv', 10);
261
+ * ```
262
+ */
263
+ export async function removeUserFromRole(
264
+ caller: XmlCaller,
265
+ appId: string,
266
+ userId: string,
267
+ roleId: number
268
+ ): Promise<void> {
269
+ const inner =
270
+ `<userid>${escapeXml(userId)}</userid>` +
271
+ `<roleid>${roleId}</roleid>`;
272
+ const body = buildRequest(inner);
273
+ const xml = await caller.doXml(appId, 'API_RemoveUserFromRole', body);
274
+
275
+ const base = parseBaseResponse(xml);
276
+ checkError(base);
277
+ }
278
+
279
+ /**
280
+ * Change a user's role or disable their access.
281
+ *
282
+ * This is preferred over removeUserFromRole when you want to keep the
283
+ * user in the app's user list but change/disable their access.
284
+ *
285
+ * Pass newRoleId=0 (or omit it) to set the role to "None" (role ID 9),
286
+ * which disables access while keeping the user on the app's user list.
287
+ *
288
+ * @see https://help.quickbase.com/docs/api-changeuserrole
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * // Change from role 10 to role 11
293
+ * await changeUserRole(caller, 'bqxyz123', '112149.bhsv', 10, 11);
294
+ *
295
+ * // Disable access (set to None role)
296
+ * await changeUserRole(caller, 'bqxyz123', '112149.bhsv', 10, 0);
297
+ * ```
298
+ */
299
+ export async function changeUserRole(
300
+ caller: XmlCaller,
301
+ appId: string,
302
+ userId: string,
303
+ currentRoleId: number,
304
+ newRoleId?: number
305
+ ): Promise<void> {
306
+ let inner =
307
+ `<userid>${escapeXml(userId)}</userid>` +
308
+ `<roleid>${currentRoleId}</roleid>`;
309
+
310
+ // If newRoleId is provided and > 0, include it
311
+ // If omitted or 0, QuickBase sets role to None (9)
312
+ if (newRoleId !== undefined && newRoleId > 0) {
313
+ inner += `<newRoleid>${newRoleId}</newRoleid>`;
314
+ }
315
+
316
+ const body = buildRequest(inner);
317
+ const xml = await caller.doXml(appId, 'API_ChangeUserRole', body);
318
+
319
+ const base = parseBaseResponse(xml);
320
+ checkError(base);
321
+ }