quickbase-js 1.0.1-beta.0 → 1.1.0-beta.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 (53) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/{quickbaseClient.d.ts → quickbase.d.ts} +344 -339
  3. package/dist/{quickbaseClient.js → quickbase.js} +350 -266
  4. package/dist/quickbase.js.map +1 -0
  5. package/examples/react.js +42 -16
  6. package/examples/vanillajs.html +32 -8
  7. package/log-gen.yaml +3513 -0
  8. package/package.json +13 -9
  9. package/rollup.config.js +2 -2
  10. package/src/code-generation/fix-spec-definitions.ts +473 -66
  11. package/src/code-generation/fix-spec-paths.ts +210 -18
  12. package/src/code-generation/generate-unified-interface.ts +1 -8
  13. package/src/code-generation/output/quickbase-fixed.json +783 -1138
  14. package/src/generated-unified/QuickbaseClient.ts +10 -9
  15. package/src/log-gen.ts +82 -35
  16. package/src/quickbaseClient.ts +39 -42
  17. package/test-artifacts/test-results.json +173 -1145
  18. package/tests/playwright/qb/auth/cacheSwitching.test.ts +4 -4
  19. package/tests/playwright/qb/auth/fetchTempToken401.test.ts +2 -2
  20. package/tests/playwright/qb/auth/getAppWithUserToken.test.ts +2 -2
  21. package/tests/playwright/qb/auth/getTempToken.test.ts +2 -2
  22. package/tests/playwright/qb/auth/tokenPrefetch.test.ts +2 -2
  23. package/tests/playwright/qb/auth/tokenRenewal.test.ts +2 -2
  24. package/tests/setup.ts +37 -9
  25. package/tests/vitest/qb/apps/getApp.test.ts +37 -43
  26. package/tests/vitest/qb/fields/getFields.test.ts +3 -5
  27. package/tests/vitest/qb/records/deleteRecords.test.ts +78 -0
  28. package/tests/vitest/qb/records/runQuery.test.ts +82 -0
  29. package/tests/vitest/qb/records/upsert.test.ts +72 -0
  30. package/tests/vitest/qb/tables/createTable.test.ts +55 -0
  31. package/tests/vitest/qb/tables/deleteTable.test.ts +50 -0
  32. package/tests/vitest/qb/tables/getAppTables.test.ts +43 -64
  33. package/tests/vitest/qb/tables/getTable.test.ts +26 -0
  34. package/tests/vitest/qb/tables/updateTable.test.ts +48 -0
  35. package/tests/vitest/unit/apps/getApp.test.ts +17 -12
  36. package/tests/vitest/unit/auth/fetchTempToken401.test.ts +32 -6
  37. package/tests/vitest/unit/auth/getTempToken.test.ts +36 -24
  38. package/tests/vitest/unit/auth/retryOn401.test.ts +39 -5
  39. package/tests/vitest/unit/auth/two401s.test.ts +1 -1
  40. package/tests/vitest/unit/fields/getFields.test.ts +14 -7
  41. package/tests/vitest/unit/records/deleteRecords.test.ts +112 -0
  42. package/tests/vitest/unit/records/runQuery.test.ts +102 -0
  43. package/tests/vitest/unit/records/upsert.test.ts +218 -0
  44. package/tests/vitest/unit/tables/createTable.test.ts +70 -0
  45. package/tests/vitest/unit/tables/deleteTable.test.ts +77 -0
  46. package/tests/vitest/unit/tables/getAppTables.test.ts +41 -28
  47. package/tests/vitest/unit/tables/getTable.test.ts +233 -0
  48. package/tests/vitest/unit/tables/updateTable.test.ts +80 -0
  49. package/tsconfig.json +3 -2
  50. package/vitest.config.ts +8 -2
  51. package/dist/quickbaseClient.js.map +0 -1
  52. package/logGen.yaml +0 -1820
  53. package/src/utils.ts +0 -5
@@ -0,0 +1,233 @@
1
+ // tests/vitest/unit/tables/getTable.test.ts
2
+ import { describe, it, expect, beforeEach } from "vitest";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_APP_ID,
7
+ QB_TABLE_ID_1,
8
+ QB_REALM,
9
+ QB_USER_TOKEN,
10
+ } from "@tests/setup.ts";
11
+
12
+ describe("QuickbaseClient Unit - getTable", () => {
13
+ let client: ReturnType<typeof createClient>;
14
+
15
+ beforeEach(() => {
16
+ mockFetch.mockClear();
17
+ });
18
+
19
+ it("calls getTable successfully with user token", async () => {
20
+ client = createClient(mockFetch, { debug: true });
21
+
22
+ const mockResponse = {
23
+ id: QB_TABLE_ID_1,
24
+ name: "Root",
25
+ alias: "_DBID_ROOT",
26
+ description: "",
27
+ created: new Date("2025-02-13T18:22:33.000Z"),
28
+ updated: new Date("2025-02-13T18:22:34.000Z"),
29
+ nextRecordId: 1,
30
+ nextFieldId: 6,
31
+ defaultSortFieldId: 2,
32
+ defaultSortOrder: "DESC",
33
+ keyFieldId: 3,
34
+ singleRecordName: "Root",
35
+ pluralRecordName: "Roots",
36
+ sizeLimit: "500 MB",
37
+ spaceUsed: "0 KB",
38
+ spaceRemaining: "500 MB",
39
+ };
40
+
41
+ mockFetch.mockResolvedValueOnce({
42
+ ok: true,
43
+ status: 200,
44
+ json: () => Promise.resolve(mockResponse),
45
+ });
46
+
47
+ const response = await client.getTable({
48
+ tableId: QB_TABLE_ID_1,
49
+ appId: QB_APP_ID,
50
+ });
51
+ expect(response).toEqual(mockResponse);
52
+ expect(mockFetch).toHaveBeenCalledWith(
53
+ `https://api.quickbase.com/v1/tables/${QB_TABLE_ID_1}?appId=${QB_APP_ID}`,
54
+ expect.objectContaining({
55
+ method: "GET",
56
+ headers: expect.objectContaining({
57
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
58
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
59
+ }),
60
+ })
61
+ );
62
+ });
63
+
64
+ it("calls getTable successfully with temp token", async () => {
65
+ client = createClient(mockFetch, { debug: true, useTempTokens: true });
66
+
67
+ const mockResponse = {
68
+ id: QB_TABLE_ID_1,
69
+ name: "Root",
70
+ alias: "_DBID_ROOT",
71
+ description: "",
72
+ created: new Date("2025-02-13T18:22:33.000Z"),
73
+ updated: new Date("2025-02-13T18:22:34.000Z"),
74
+ nextRecordId: 1,
75
+ nextFieldId: 6,
76
+ defaultSortFieldId: 2,
77
+ defaultSortOrder: "DESC",
78
+ keyFieldId: 3,
79
+ singleRecordName: "Root",
80
+ pluralRecordName: "Roots",
81
+ sizeLimit: "500 MB",
82
+ spaceUsed: "0 KB",
83
+ spaceRemaining: "500 MB",
84
+ };
85
+
86
+ mockFetch
87
+ .mockResolvedValueOnce({
88
+ ok: true,
89
+ status: 200,
90
+ json: () => Promise.resolve({ temporaryAuthorization: "temp_token" }),
91
+ })
92
+ .mockResolvedValueOnce({
93
+ ok: true,
94
+ status: 200,
95
+ json: () => Promise.resolve(mockResponse),
96
+ });
97
+
98
+ const response = await client.getTable({
99
+ tableId: QB_TABLE_ID_1,
100
+ appId: QB_APP_ID,
101
+ });
102
+ expect(response).toEqual(mockResponse);
103
+ expect(mockFetch).toHaveBeenCalledTimes(2);
104
+ expect(mockFetch).toHaveBeenCalledWith(
105
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
106
+ expect.any(Object)
107
+ );
108
+ expect(mockFetch).toHaveBeenCalledWith(
109
+ `https://api.quickbase.com/v1/tables/${QB_TABLE_ID_1}?appId=${QB_APP_ID}`,
110
+ expect.objectContaining({
111
+ headers: expect.objectContaining({
112
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
113
+ Authorization: "QB-TEMP-TOKEN temp_token",
114
+ }),
115
+ })
116
+ );
117
+ });
118
+
119
+ it("retries successfully after 401 with temp token", async () => {
120
+ client = createClient(mockFetch, { debug: true, useTempTokens: true });
121
+
122
+ const mockResponse = {
123
+ id: QB_TABLE_ID_1,
124
+ name: "Root",
125
+ alias: "_DBID_ROOT",
126
+ description: "",
127
+ created: new Date("2025-02-13T18:22:33.000Z"),
128
+ updated: new Date("2025-02-13T18:22:34.000Z"),
129
+ nextRecordId: 1,
130
+ nextFieldId: 6,
131
+ defaultSortFieldId: 2,
132
+ defaultSortOrder: "DESC",
133
+ keyFieldId: 3,
134
+ singleRecordName: "Root",
135
+ pluralRecordName: "Roots",
136
+ sizeLimit: "500 MB",
137
+ spaceUsed: "0 KB",
138
+ spaceRemaining: "500 MB",
139
+ };
140
+
141
+ mockFetch
142
+ .mockResolvedValueOnce({
143
+ ok: true,
144
+ status: 200,
145
+ json: () =>
146
+ Promise.resolve({ temporaryAuthorization: "initial_token" }),
147
+ })
148
+ .mockResolvedValueOnce({
149
+ ok: false,
150
+ status: 401,
151
+ json: () => Promise.resolve({ message: "Unauthorized" }),
152
+ })
153
+ .mockResolvedValueOnce({
154
+ ok: true,
155
+ status: 200,
156
+ json: () => Promise.resolve({ temporaryAuthorization: "new_token" }),
157
+ })
158
+ .mockResolvedValueOnce({
159
+ ok: true,
160
+ status: 200,
161
+ json: () => Promise.resolve(mockResponse),
162
+ });
163
+
164
+ const response = await client.getTable({
165
+ tableId: QB_TABLE_ID_1,
166
+ appId: QB_APP_ID,
167
+ });
168
+ expect(response).toEqual(mockResponse);
169
+ expect(mockFetch).toHaveBeenCalledTimes(4);
170
+ expect(mockFetch).toHaveBeenCalledWith(
171
+ `https://api.quickbase.com/v1/tables/${QB_TABLE_ID_1}?appId=${QB_APP_ID}`,
172
+ expect.objectContaining({
173
+ headers: expect.objectContaining({
174
+ Authorization: "QB-TEMP-TOKEN new_token",
175
+ }),
176
+ })
177
+ );
178
+ });
179
+
180
+ it("handles 401 with failed temp token retry", async () => {
181
+ client = createClient(mockFetch, { debug: true, useTempTokens: true });
182
+
183
+ mockFetch
184
+ .mockResolvedValueOnce({
185
+ ok: true,
186
+ status: 200,
187
+ json: () =>
188
+ Promise.resolve({ temporaryAuthorization: "initial_token" }),
189
+ })
190
+ .mockResolvedValueOnce({
191
+ ok: false,
192
+ status: 401,
193
+ json: () => Promise.resolve({ message: "Unauthorized" }),
194
+ })
195
+ .mockResolvedValueOnce({
196
+ ok: false,
197
+ status: 401,
198
+ json: () =>
199
+ Promise.resolve({ message: "Unauthorized in fetchTempToken" }),
200
+ });
201
+
202
+ await expect(
203
+ client.getTable({ tableId: QB_TABLE_ID_1, appId: QB_APP_ID })
204
+ ).rejects.toThrow(
205
+ "API Error: Unauthorized in fetchTempToken (Status: 401)"
206
+ );
207
+ expect(mockFetch).toHaveBeenCalledTimes(3);
208
+ });
209
+
210
+ it("handles 404 Not Found", async () => {
211
+ client = createClient(mockFetch, { debug: true });
212
+
213
+ mockFetch.mockResolvedValueOnce({
214
+ ok: false,
215
+ status: 404,
216
+ json: () => Promise.resolve({ message: "Table not found" }),
217
+ });
218
+
219
+ await expect(
220
+ client.getTable({ tableId: QB_TABLE_ID_1, appId: QB_APP_ID })
221
+ ).rejects.toThrow("API Error: Table not found (Status: 404)");
222
+ expect(mockFetch).toHaveBeenCalledWith(
223
+ `https://api.quickbase.com/v1/tables/${QB_TABLE_ID_1}?appId=${QB_APP_ID}`,
224
+ expect.objectContaining({
225
+ method: "GET",
226
+ headers: expect.objectContaining({
227
+ "QB-Realm-Hostname": `${QB_REALM}.quickbase.com`,
228
+ Authorization: `QB-USER-TOKEN ${QB_USER_TOKEN}`,
229
+ }),
230
+ })
231
+ );
232
+ });
233
+ });
@@ -0,0 +1,80 @@
1
+ // tests/vitest/unit/records/updateTable.test.ts
2
+ import { describe, it, expect, beforeEach } from "vitest";
3
+ import {
4
+ createClient,
5
+ mockFetch,
6
+ QB_APP_ID,
7
+ QB_TABLE_ID_1,
8
+ } from "@tests/setup.ts";
9
+
10
+ describe("QuickbaseClient Unit - updateTable", () => {
11
+ let client: ReturnType<typeof createClient>;
12
+
13
+ beforeEach(() => {
14
+ mockFetch.mockClear();
15
+ client = createClient(mockFetch, { debug: true });
16
+ });
17
+
18
+ it("calls updateTable successfully with temp token", async () => {
19
+ client = createClient(mockFetch, { debug: true, useTempTokens: true });
20
+
21
+ const mockBody = {
22
+ name: "Updated Root",
23
+ description: "Updated description",
24
+ };
25
+ const mockResponse = {
26
+ id: QB_TABLE_ID_1,
27
+ name: "Updated Root",
28
+ alias: "_DBID_ROOT",
29
+ description: "Updated description",
30
+ created: new Date("2025-02-13T18:22:33.000Z"),
31
+ updated: new Date("2025-03-10T12:00:00.000Z"),
32
+ nextRecordId: 1,
33
+ nextFieldId: 6,
34
+ defaultSortFieldId: 2,
35
+ defaultSortOrder: "DESC",
36
+ keyFieldId: 3,
37
+ singleRecordName: "Root",
38
+ pluralRecordName: "Roots",
39
+ sizeLimit: "500 MB",
40
+ spaceUsed: "0 KB",
41
+ spaceRemaining: "500 MB",
42
+ };
43
+
44
+ mockFetch
45
+ .mockResolvedValueOnce({
46
+ ok: true,
47
+ status: 200,
48
+ json: () => Promise.resolve({ temporaryAuthorization: "temp_token" }),
49
+ })
50
+ .mockResolvedValueOnce({
51
+ ok: true,
52
+ status: 200,
53
+ json: () => Promise.resolve(mockResponse),
54
+ });
55
+
56
+ const response = await client.updateTable({
57
+ tableId: QB_TABLE_ID_1,
58
+ appId: QB_APP_ID,
59
+ body: mockBody,
60
+ });
61
+ expect(response).toEqual(mockResponse);
62
+ expect(mockFetch).toHaveBeenCalledTimes(2);
63
+ expect(mockFetch).toHaveBeenCalledWith(
64
+ `https://api.quickbase.com/v1/auth/temporary/${QB_TABLE_ID_1}`,
65
+ expect.any(Object)
66
+ );
67
+ expect(mockFetch).toHaveBeenCalledWith(
68
+ `https://api.quickbase.com/v1/tables/${QB_TABLE_ID_1}?appId=${QB_APP_ID}`,
69
+ expect.objectContaining({
70
+ method: "POST",
71
+ headers: expect.objectContaining({
72
+ "QB-Realm-Hostname": `${process.env.QB_REALM}.quickbase.com`,
73
+ Authorization: "QB-TEMP-TOKEN temp_token",
74
+ "Content-Type": "application/json",
75
+ }),
76
+ body: JSON.stringify(mockBody),
77
+ })
78
+ );
79
+ });
80
+ });
package/tsconfig.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "module": "ESNext",
5
5
  "moduleResolution": "bundler",
6
6
  "strict": true,
7
- "lib": ["ES2015", "ESNext", "DOM"], // Explicitly include ES2015 for Record
7
+ "lib": ["ES2015", "ESNext", "DOM"],
8
8
  "types": ["node", "playwright/test"],
9
9
  "esModuleInterop": true,
10
10
  "resolveJsonModule": true,
@@ -16,7 +16,8 @@
16
16
  "sourceMap": true,
17
17
  "baseUrl": ".",
18
18
  "paths": {
19
- "@/*": ["./*"]
19
+ "@/*": ["src/*"], // Matches Vite's @ -> src/
20
+ "@tests/*": ["tests/*"] // Matches Vite's @tests -> tests/
20
21
  }
21
22
  },
22
23
  "include": ["src/**/*", "tests/**/*"],
package/vitest.config.ts CHANGED
@@ -1,11 +1,16 @@
1
+ // vitest.config.ts
1
2
  import { defineConfig } from "vitest/config";
2
3
  import path from "path";
4
+ import dotenv from "dotenv"; // Add this import
5
+
6
+ // Load .env variables before tests run
7
+ dotenv.config({ path: path.resolve(__dirname, ".env") });
3
8
 
4
9
  export default defineConfig({
5
10
  test: {
6
11
  environment: "jsdom",
7
12
  include: ["tests/vitest/**/**/*.test.ts"],
8
- setupFiles: ["tests/setup.ts"],
13
+ setupFiles: ["tests/setup.ts"], // Relative path from root
9
14
  pool: "forks",
10
15
  poolOptions: {
11
16
  forks: {
@@ -15,7 +20,8 @@ export default defineConfig({
15
20
  },
16
21
  resolve: {
17
22
  alias: {
18
- "@": path.resolve(__dirname, "./"),
23
+ "@": path.resolve(__dirname, "./src"), // For src/ imports
24
+ "@tests": path.resolve(__dirname, "./tests"), // For tests/ imports
19
25
  },
20
26
  },
21
27
  });