quickbase-js 0.1.0-beta.7 → 0.1.0-beta.9

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 (82) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +46 -130
  3. package/dist/esm/quickbase.d.ts +1292 -125
  4. package/dist/esm/quickbase.js +666 -190
  5. package/dist/esm/quickbase.js.map +1 -1
  6. package/dist/esm/quickbase.min.js +1 -1
  7. package/dist/esm/quickbase.min.js.map +1 -1
  8. package/dist/umd/quickbase.umd.js +674 -189
  9. package/dist/umd/quickbase.umd.js.map +1 -1
  10. package/dist/umd/quickbase.umd.min.js +1 -1
  11. package/dist/umd/quickbase.umd.min.js.map +1 -1
  12. package/open-api/fix-spec-main.ts +69 -68
  13. package/open-api/generate-override-report.ts +214 -0
  14. package/open-api/generate-unified-interface.ts +162 -103
  15. package/open-api/output/override-report.html +11 -0
  16. package/open-api/output/override-report.json +14395 -58
  17. package/open-api/output/quickbase-fixed.json +583 -2
  18. package/open-api/schema/tags/fields.ts +331 -16
  19. package/open-api/schema/tags/index.ts +2 -4
  20. package/open-api/types/spec.ts +2 -1
  21. package/open-api/utils/generateJsDoc.ts +96 -0
  22. package/package.json +33 -33
  23. package/src/RateLimitError.ts +12 -0
  24. package/src/ThrottleBucket.ts +41 -0
  25. package/src/authorizationStrategy.ts +246 -0
  26. package/src/generated-unified/QuickbaseClient.ts +809 -119
  27. package/src/invokeMethod.ts +242 -0
  28. package/src/quickbaseClient.ts +117 -248
  29. package/src/rateLimiter.ts +25 -0
  30. package/src/tokenCache.ts +10 -26
  31. package/tests/setup.ts +2 -0
  32. package/tests/vitest/qb/apps/getApp.test.ts +6 -2
  33. package/tests/vitest/qb/apps/getAppEvents.test.ts +67 -0
  34. package/tests/vitest/qb/apps/updateApp.test.ts +58 -0
  35. package/tests/vitest/qb/auth/mockQuickbaseServer.ts +60 -0
  36. package/tests/vitest/qb/auth/retryUserToken401.test.ts +73 -0
  37. package/tests/vitest/qb/auth/ssoTokenIntegrationWithServer.test.ts +65 -0
  38. package/tests/vitest/qb/fields/createField.test.ts +1 -2
  39. package/tests/vitest/qb/fields/deleteFields.test.ts +10 -16
  40. package/tests/vitest/qb/fields/getFieldUsage.test.ts +58 -150
  41. package/tests/vitest/qb/fields/updateField.test.ts +93 -0
  42. package/tests/vitest/qb/formulas/runFormula.test.ts +96 -0
  43. package/tests/vitest/qb/index.ts +1 -0
  44. package/tests/vitest/qb/tables/createRelationship.test.ts +102 -0
  45. package/tests/vitest/qb/tables/deleteRelationship.test.ts +143 -0
  46. package/tests/vitest/qb/tables/updateRelationship.test.ts +250 -0
  47. package/tests/vitest/unit/ThrottleBucket.test.ts +95 -0
  48. package/tests/vitest/unit/apps/copyApp.test.ts +133 -40
  49. package/tests/vitest/unit/apps/getAppEvents.test.ts +193 -0
  50. package/tests/vitest/unit/apps/updateApp.test.ts +412 -0
  51. package/tests/vitest/unit/auth/fetchTempToken401.test.ts +7 -26
  52. package/tests/vitest/unit/auth/getTempToken.test.ts +42 -18
  53. package/tests/vitest/unit/auth/retryTempToken401.test.ts +95 -0
  54. package/tests/vitest/unit/auth/retryTempTokenMaxRetries.test.ts +235 -0
  55. package/tests/vitest/unit/auth/retryUserToken401.test.ts +69 -0
  56. package/tests/vitest/unit/auth/ssoTokenRefresh.test.ts +325 -0
  57. package/tests/vitest/unit/fields/createField.test.ts +180 -120
  58. package/tests/vitest/unit/fields/getFieldUsage.test.ts +47 -14
  59. package/tests/vitest/unit/fields/updateField.test.ts +285 -0
  60. package/tests/vitest/unit/formulas/runFormula.test.ts +205 -0
  61. package/tests/vitest/unit/index.ts +2 -1
  62. package/tests/vitest/unit/inferHttpMethod.test.ts +131 -0
  63. package/tests/vitest/unit/rateLimit.test.ts +191 -0
  64. package/tests/vitest/unit/tables/createRelationship.test.ts +212 -0
  65. package/tests/vitest/unit/tables/deleteRelationship.test.ts +97 -0
  66. package/tests/vitest/unit/tables/updateRelationship.test.ts +307 -0
  67. package/tests/vitest/unit/tokenLifespan.test.ts +204 -0
  68. package/tools/log-gen.ts +20 -7
  69. package/tools/log-gen.yaml +3446 -1848
  70. package/tsconfig.json +5 -2
  71. package/vitest.config.ts +2 -2
  72. package/notes.txt +0 -158
  73. package/tests/vitest/unit/auth/retryOn401.test.ts +0 -116
  74. package/tests/vitest/unit/auth/two401s.test.ts +0 -86
  75. package/tools/generate-types.ts +0 -29
  76. package/tools/openapi-schema-validator.ts +0 -38
  77. package/tools/spec-analyzer.ts +0 -163
  78. package/tools/split-spec.ts +0 -148
  79. package/tools/test-import.ts +0 -3
  80. package/tools/validate-spec.ts +0 -40
  81. /package/tests/playwright/qb/auth/{tokenPrefetch.test.ts → tempTokenPrefetch.test.ts} +0 -0
  82. /package/tests/playwright/qb/auth/{tokenRenewal.test.ts → tempTokenRenewal.test.ts} +0 -0
@@ -0,0 +1,307 @@
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import {
3
+ createClient,
4
+ mockFetch,
5
+ QB_REALM,
6
+ QB_USER_TOKEN,
7
+ QB_TABLE_ID_1,
8
+ } from "@tests/setup.ts";
9
+ import {
10
+ UpdateRelationshipRequest,
11
+ UpdateRelationship200Response,
12
+ } from "@/generated/models";
13
+
14
+ describe("QuickbaseClient Unit - updateRelationship", () => {
15
+ let client: ReturnType<typeof createClient>;
16
+
17
+ beforeEach(() => {
18
+ mockFetch.mockClear();
19
+ });
20
+
21
+ it("initializes without errors and has updateRelationship method", () => {
22
+ client = createClient(mockFetch, { debug: true });
23
+ expect(client).toBeDefined();
24
+ expect(typeof client.updateRelationship).toBe("function");
25
+ });
26
+
27
+ it("updates relationship successfully with user token", async () => {
28
+ client = createClient(mockFetch, { debug: true });
29
+
30
+ const tableId = QB_TABLE_ID_1;
31
+ const relationshipId = 6;
32
+
33
+ const request: UpdateRelationshipRequest = {
34
+ lookupFieldIds: [4, 5, 6],
35
+ summaryFields: [
36
+ {
37
+ summaryFid: 3,
38
+ label: "my summary field",
39
+ accumulationType: "COUNT",
40
+ where: "{'3'.EX.'1'}",
41
+ },
42
+ ],
43
+ };
44
+
45
+ const mockResponse: UpdateRelationship200Response = {
46
+ id: relationshipId,
47
+ parentTableId: "bck7gp3q2",
48
+ childTableId: tableId,
49
+ foreignKeyField: {
50
+ id: relationshipId,
51
+ label: "Related record",
52
+ type: "numeric",
53
+ },
54
+ isCrossApp: false,
55
+ lookupFields: [
56
+ { id: 4, label: "Field 4", type: "text" },
57
+ { id: 5, label: "Field 5", type: "numeric" },
58
+ { id: 6, label: "Field 6", type: "date" },
59
+ ],
60
+ summaryFields: [{ id: 8, label: "my summary field", type: "numeric" }],
61
+ };
62
+
63
+ mockFetch.mockResolvedValueOnce({
64
+ ok: true,
65
+ status: 200,
66
+ json: () => Promise.resolve(mockResponse),
67
+ });
68
+
69
+ const result = await client.updateRelationship({
70
+ tableId,
71
+ relationshipId,
72
+ body: request,
73
+ });
74
+
75
+ expect(result).toEqual(mockResponse);
76
+ expect(mockFetch).toHaveBeenCalledWith(
77
+ `https://api.quickbase.com/v1/tables/${tableId}/relationship/${relationshipId}`,
78
+ expect.objectContaining({
79
+ method: "POST",
80
+ headers: expect.objectContaining({
81
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
82
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
83
+ "Content-Type": "application/json",
84
+ }),
85
+ body: JSON.stringify(request),
86
+ credentials: "omit",
87
+ })
88
+ );
89
+ });
90
+
91
+ it("updates relationship successfully with temp token", async () => {
92
+ client = createClient(mockFetch, { useTempTokens: true, debug: true });
93
+
94
+ const tableId = QB_TABLE_ID_1;
95
+ const relationshipId = 6;
96
+
97
+ const request: UpdateRelationshipRequest = {
98
+ lookupFieldIds: [7],
99
+ summaryFields: [
100
+ {
101
+ summaryFid: 0,
102
+ label: "Count of Records",
103
+ accumulationType: "COUNT",
104
+ where: "{'3'.GT.0}",
105
+ },
106
+ ],
107
+ };
108
+
109
+ const mockResponse: UpdateRelationship200Response = {
110
+ id: relationshipId,
111
+ parentTableId: "bck7gp3q2",
112
+ childTableId: tableId,
113
+ foreignKeyField: {
114
+ id: relationshipId,
115
+ label: "Related record",
116
+ type: "numeric",
117
+ },
118
+ isCrossApp: false,
119
+ lookupFields: [{ id: 7, label: "record - text field", type: "text" }],
120
+ summaryFields: [{ id: 9, label: "Count of Records", type: "numeric" }],
121
+ };
122
+
123
+ mockFetch
124
+ .mockResolvedValueOnce({
125
+ ok: true,
126
+ status: 200,
127
+ json: () => Promise.resolve({ temporaryAuthorization: "temp_token" }),
128
+ })
129
+ .mockResolvedValueOnce({
130
+ ok: true,
131
+ status: 200,
132
+ json: () => Promise.resolve(mockResponse),
133
+ });
134
+
135
+ const result = await client.updateRelationship({
136
+ tableId,
137
+ relationshipId,
138
+ body: request,
139
+ });
140
+
141
+ expect(result).toEqual(mockResponse);
142
+ expect(mockFetch).toHaveBeenCalledTimes(2);
143
+ expect(mockFetch).toHaveBeenNthCalledWith(
144
+ 1,
145
+ `https://api.quickbase.com/v1/auth/temporary/${tableId}`,
146
+ expect.objectContaining({
147
+ method: "GET",
148
+ headers: expect.objectContaining({
149
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
150
+ "Content-Type": "application/json",
151
+ }),
152
+ credentials: "include",
153
+ })
154
+ );
155
+ expect(mockFetch).toHaveBeenNthCalledWith(
156
+ 2,
157
+ `https://api.quickbase.com/v1/tables/${tableId}/relationship/${relationshipId}`,
158
+ expect.objectContaining({
159
+ method: "POST",
160
+ headers: expect.objectContaining({
161
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
162
+ Authorization: "QB-TEMP-TOKEN temp_token",
163
+ "Content-Type": "application/json",
164
+ }),
165
+ body: JSON.stringify(request),
166
+ credentials: "omit",
167
+ })
168
+ );
169
+ });
170
+
171
+ it("retries successfully after 401 with temp token", async () => {
172
+ client = createClient(mockFetch, { useTempTokens: true, debug: true });
173
+
174
+ const tableId = QB_TABLE_ID_1;
175
+ const relationshipId = 6;
176
+
177
+ const request: UpdateRelationshipRequest = {
178
+ lookupFieldIds: [4],
179
+ };
180
+
181
+ const mockResponse: UpdateRelationship200Response = {
182
+ id: relationshipId,
183
+ parentTableId: "bck7gp3q2",
184
+ childTableId: tableId,
185
+ foreignKeyField: {
186
+ id: relationshipId,
187
+ label: "Related record",
188
+ type: "numeric",
189
+ },
190
+ isCrossApp: false,
191
+ lookupFields: [{ id: 4, label: "Field 4", type: "text" }],
192
+ summaryFields: [],
193
+ };
194
+
195
+ mockFetch
196
+ .mockResolvedValueOnce({
197
+ ok: true,
198
+ status: 200,
199
+ json: () =>
200
+ Promise.resolve({ temporaryAuthorization: "initial_token" }),
201
+ })
202
+ .mockResolvedValueOnce({
203
+ ok: false,
204
+ status: 401,
205
+ json: () => Promise.resolve({ message: "Unauthorized" }),
206
+ })
207
+ .mockResolvedValueOnce({
208
+ ok: true,
209
+ status: 200,
210
+ json: () => Promise.resolve({ temporaryAuthorization: "new_token" }),
211
+ })
212
+ .mockResolvedValueOnce({
213
+ ok: true,
214
+ status: 200,
215
+ json: () => Promise.resolve(mockResponse),
216
+ });
217
+
218
+ const consoleSpy = vi.spyOn(console, "log");
219
+ const result = await client.updateRelationship({
220
+ tableId,
221
+ relationshipId,
222
+ body: request,
223
+ });
224
+
225
+ expect(result).toEqual(mockResponse);
226
+ expect(mockFetch).toHaveBeenCalledTimes(4);
227
+ expect(mockFetch).toHaveBeenNthCalledWith(
228
+ 1,
229
+ `https://api.quickbase.com/v1/auth/temporary/${tableId}`,
230
+ expect.any(Object)
231
+ );
232
+ expect(mockFetch).toHaveBeenNthCalledWith(
233
+ 2,
234
+ `https://api.quickbase.com/v1/tables/${tableId}/relationship/${relationshipId}`,
235
+ expect.objectContaining({
236
+ headers: expect.objectContaining({
237
+ Authorization: "QB-TEMP-TOKEN initial_token",
238
+ }),
239
+ })
240
+ );
241
+ expect(mockFetch).toHaveBeenNthCalledWith(
242
+ 3,
243
+ `https://api.quickbase.com/v1/auth/temporary/${tableId}`,
244
+ expect.any(Object)
245
+ );
246
+ expect(mockFetch).toHaveBeenNthCalledWith(
247
+ 4,
248
+ `https://api.quickbase.com/v1/tables/${tableId}/relationship/${relationshipId}`,
249
+ expect.objectContaining({
250
+ headers: expect.objectContaining({
251
+ Authorization: "QB-TEMP-TOKEN new_token",
252
+ }),
253
+ })
254
+ );
255
+
256
+ // Updated log expectations
257
+ expect(consoleSpy).toHaveBeenCalledWith(
258
+ "Authorization error for updateRelationship (temp token), refreshing token:"
259
+ );
260
+ expect(consoleSpy).toHaveBeenCalledWith(
261
+ expect.stringContaining(
262
+ "[updateRelationship] Retrying with token: new_tok"
263
+ )
264
+ );
265
+
266
+ consoleSpy.mockRestore();
267
+ });
268
+
269
+ it("handles 400 error for invalid request", async () => {
270
+ client = createClient(mockFetch, { debug: true });
271
+
272
+ const tableId = QB_TABLE_ID_1;
273
+ const relationshipId = 6;
274
+
275
+ const request: UpdateRelationshipRequest = {
276
+ lookupFieldIds: [-1],
277
+ };
278
+
279
+ mockFetch.mockResolvedValueOnce({
280
+ ok: false,
281
+ status: 400,
282
+ json: () => Promise.resolve({ message: "Invalid field ID" }),
283
+ });
284
+
285
+ await expect(
286
+ client.updateRelationship({
287
+ tableId,
288
+ relationshipId,
289
+ body: request,
290
+ })
291
+ ).rejects.toThrow("API Error: Invalid field ID (Status: 400)");
292
+
293
+ expect(mockFetch).toHaveBeenCalledWith(
294
+ `https://api.quickbase.com/v1/tables/${tableId}/relationship/${relationshipId}`,
295
+ expect.objectContaining({
296
+ method: "POST",
297
+ headers: expect.objectContaining({
298
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
299
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
300
+ "Content-Type": "application/json",
301
+ }),
302
+ body: JSON.stringify(request),
303
+ credentials: "omit",
304
+ })
305
+ );
306
+ });
307
+ });
@@ -0,0 +1,204 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { createClient, mockFetch, QB_APP_ID, QB_REALM } from "@tests/setup.ts";
3
+ import { UpdateAppRequest, UpdateApp200Response } from "@/generated/models";
4
+
5
+ describe("QuickbaseClient Unit - Token Lifespan", () => {
6
+ let client: ReturnType<typeof createClient>;
7
+ const request: UpdateAppRequest = { name: "Test App" };
8
+ const mockResponse: UpdateApp200Response = {
9
+ id: QB_APP_ID,
10
+ name: "Test App",
11
+ description: "",
12
+ created: new Date("2020-01-01T00:00:00Z"), // Match deserialized Date object
13
+ updated: new Date("2020-01-01T00:00:00Z"),
14
+ dateFormat: "MM-DD-YYYY",
15
+ timeZone: "(UTC-08:00) Pacific Time (US & Canada)",
16
+ hasEveryoneOnTheInternet: false,
17
+ ancestorId: undefined,
18
+ variables: [],
19
+ securityProperties: {},
20
+ memoryInfo: { estMemory: 0, estMemoryInclDependentApps: 0 },
21
+ dataClassification: "None",
22
+ };
23
+
24
+ beforeEach(() => {
25
+ mockFetch.mockClear();
26
+ vi.useFakeTimers();
27
+ console.log("[beforeEach] mockFetch cleared and fake timers enabled");
28
+ });
29
+
30
+ afterEach(() => {
31
+ vi.useRealTimers();
32
+ });
33
+
34
+ const setupMocks = (token: string) => {
35
+ mockFetch
36
+ .mockResolvedValueOnce({
37
+ ok: true,
38
+ status: 200,
39
+ json: () => Promise.resolve({ temporaryAuthorization: token }),
40
+ })
41
+ .mockResolvedValueOnce({
42
+ ok: true,
43
+ status: 200,
44
+ json: () => Promise.resolve(mockResponse),
45
+ });
46
+ };
47
+
48
+ it("reuses token within custom lifespan and refetches after expiration", async () => {
49
+ client = createClient(mockFetch, {
50
+ realm: QB_REALM,
51
+ useTempTokens: true,
52
+ tempTokenLifespan: 500,
53
+ debug: true,
54
+ });
55
+
56
+ setupMocks("token1");
57
+ await client.updateApp({ appId: QB_APP_ID, body: request });
58
+ expect(mockFetch).toHaveBeenCalledTimes(2);
59
+ expect(mockFetch.mock.calls[1][1].headers.Authorization).toBe(
60
+ "QB-TEMP-TOKEN token1"
61
+ );
62
+
63
+ mockFetch.mockResolvedValueOnce({
64
+ ok: true,
65
+ status: 200,
66
+ json: () => Promise.resolve(mockResponse),
67
+ });
68
+ await client.updateApp({ appId: QB_APP_ID, body: request });
69
+ expect(mockFetch).toHaveBeenCalledTimes(3);
70
+ expect(mockFetch.mock.calls[2][1].headers.Authorization).toBe(
71
+ "QB-TEMP-TOKEN token1"
72
+ );
73
+
74
+ vi.advanceTimersByTime(500);
75
+ console.log("[Test 1] Token expired after 500ms");
76
+
77
+ setupMocks("token2");
78
+ await client.updateApp({ appId: QB_APP_ID, body: request });
79
+ expect(mockFetch).toHaveBeenCalledTimes(5);
80
+ expect(mockFetch.mock.calls[4][1].headers.Authorization).toBe(
81
+ "QB-TEMP-TOKEN token2"
82
+ );
83
+ });
84
+
85
+ it("reuses token within default lifespan of 4m50s", async () => {
86
+ client = createClient(mockFetch, {
87
+ realm: QB_REALM,
88
+ useTempTokens: true,
89
+ debug: true,
90
+ });
91
+
92
+ setupMocks("default_token");
93
+ await client.updateApp({ appId: QB_APP_ID, body: request });
94
+ expect(mockFetch).toHaveBeenCalledTimes(2);
95
+ expect(mockFetch.mock.calls[1][1].headers.Authorization).toBe(
96
+ "QB-TEMP-TOKEN default_token"
97
+ );
98
+
99
+ vi.advanceTimersByTime(1000);
100
+ console.log(
101
+ "[Test 2] Advanced time by 1000ms, still within default lifespan"
102
+ );
103
+
104
+ mockFetch.mockResolvedValueOnce({
105
+ ok: true,
106
+ status: 200,
107
+ json: () => Promise.resolve(mockResponse),
108
+ });
109
+ await client.updateApp({ appId: QB_APP_ID, body: request });
110
+ expect(mockFetch).toHaveBeenCalledTimes(3);
111
+ expect(mockFetch.mock.calls[2][1].headers.Authorization).toBe(
112
+ "QB-TEMP-TOKEN default_token"
113
+ );
114
+ });
115
+
116
+ it("handles token fetch failure gracefully", async () => {
117
+ client = createClient(mockFetch, {
118
+ realm: QB_REALM,
119
+ useTempTokens: true,
120
+ tempTokenLifespan: 500,
121
+ });
122
+
123
+ mockFetch.mockResolvedValueOnce({
124
+ ok: false,
125
+ status: 500,
126
+ json: () => Promise.resolve({ message: "Network error" }),
127
+ });
128
+ await expect(
129
+ client.updateApp({ appId: QB_APP_ID, body: request })
130
+ ).rejects.toThrow("API Error: Network error (Status: 500)");
131
+ expect(mockFetch).toHaveBeenCalledTimes(1);
132
+ });
133
+
134
+ it("fetches new token every call with zero lifespan", async () => {
135
+ client = createClient(mockFetch, {
136
+ realm: QB_REALM,
137
+ useTempTokens: true,
138
+ tempTokenLifespan: 0,
139
+ });
140
+
141
+ setupMocks("token1");
142
+ await client.updateApp({ appId: QB_APP_ID, body: request });
143
+ expect(mockFetch).toHaveBeenCalledTimes(2);
144
+
145
+ setupMocks("token2");
146
+ await client.updateApp({ appId: QB_APP_ID, body: request });
147
+ expect(mockFetch).toHaveBeenCalledTimes(4);
148
+ expect(mockFetch.mock.calls[3][1].headers.Authorization).toBe(
149
+ "QB-TEMP-TOKEN token2"
150
+ );
151
+ });
152
+
153
+ it("reuses token across concurrent calls within lifespan", async () => {
154
+ client = createClient(mockFetch, {
155
+ realm: QB_REALM,
156
+ useTempTokens: true,
157
+ tempTokenLifespan: 500,
158
+ debug: true,
159
+ });
160
+
161
+ // Pre-fetch token to ensure it’s cached
162
+ mockFetch.mockResolvedValueOnce({
163
+ ok: true,
164
+ status: 200,
165
+ json: () => Promise.resolve({ temporaryAuthorization: "token1" }),
166
+ });
167
+ mockFetch.mockResolvedValueOnce({
168
+ ok: true,
169
+ status: 200,
170
+ json: () => Promise.resolve(mockResponse),
171
+ });
172
+ await client.updateApp({ appId: QB_APP_ID, body: request }); // Cache token1
173
+ vi.advanceTimersByTime(1);
174
+
175
+ // Reset mocks and set up API responses
176
+ mockFetch.mockClear();
177
+ mockFetch
178
+ .mockResolvedValueOnce({
179
+ ok: true,
180
+ status: 200,
181
+ json: () => Promise.resolve(mockResponse),
182
+ })
183
+ .mockResolvedValueOnce({
184
+ ok: true,
185
+ status: 200,
186
+ json: () => Promise.resolve(mockResponse),
187
+ });
188
+
189
+ const [call1, call2] = await Promise.all([
190
+ client.updateApp({ appId: QB_APP_ID, body: request }),
191
+ client.updateApp({ appId: QB_APP_ID, body: request }),
192
+ ]);
193
+
194
+ expect(mockFetch).toHaveBeenCalledTimes(2);
195
+ expect(mockFetch.mock.calls[0][1].headers.Authorization).toBe(
196
+ "QB-TEMP-TOKEN token1"
197
+ );
198
+ expect(mockFetch.mock.calls[1][1].headers.Authorization).toBe(
199
+ "QB-TEMP-TOKEN token1"
200
+ );
201
+ expect(call1).toEqual(mockResponse);
202
+ expect(call2).toEqual(mockResponse);
203
+ });
204
+ });
package/tools/log-gen.ts CHANGED
@@ -18,32 +18,45 @@ const excludeDirs: string[] = [
18
18
  // prettier-ignore
19
19
  const includeFolders: string[] = [
20
20
  // "open-api",
21
- // "open-api/definitions",
22
- // "open-api/paths",
23
21
  ];
24
22
 
25
23
  // prettier-ignore
26
24
  const includeRecursiveFolders: string[] = [
27
- "open-api"
25
+ // "open-api"
28
26
  // "tests",
29
27
  // "tests/vitest/unit",
30
- // "tests/vitest/qb"
28
+ "tests/vitest/qb"
31
29
  ];
32
30
 
33
31
  // prettier-ignore
34
32
  const includeFiles: string[] = [
33
+ // "tests/setup.ts",
34
+ // "vitest.config.ts",
35
+
35
36
  // "package.json",
36
37
  // "tsconfig.json",
37
38
  // "tsconfig.build.json",
38
39
  // "rollup.config.js",
39
- // "vitest.config.ts",
40
40
  // "build-common.js",
41
41
  // "build-umd.js",
42
42
  // "build-esm.js",
43
- // "src/tokenCache.ts",
44
- // "src/generated/runtime.ts",
43
+
45
44
  // "src/quickbaseClient.ts",
45
+ // "src/invokeMethod.ts",
46
46
  // "src/generated-unified/QuickbaseClient.ts",
47
+ // "src/authorizationStrategy.ts",
48
+ // "src/rateLimiter.ts",
49
+ // "src/RateLimitError.ts",
50
+ // "src/ThrottleBucket.ts",
51
+ // "src/tokenCache.ts",
52
+ // "src/utils.ts",
53
+
54
+ // "src/generated/runtime.ts",
55
+ // "src/generated/apis/AuthApi.ts",
56
+ // "src/generated/apis/FieldsApi.ts",
57
+ // "src/generated/apis/AppsApi.ts",
58
+
59
+ "test/vitest/unit/fields/createField.test.ts",
47
60
  ];
48
61
 
49
62
  const projectGoals: string[] = [