quickbase-js 1.1.0-beta.0 → 1.1.0-beta.2

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 (31) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/quickbase.d.ts +356 -6
  3. package/dist/quickbase.js +363 -20
  4. package/dist/quickbase.js.map +1 -1
  5. package/examples/react.js +42 -16
  6. package/examples/vanillajs.html +32 -8
  7. package/log-gen.yaml +146 -198
  8. package/package.json +4 -4
  9. package/src/code-generation/fix-spec-definitions.ts +99 -41
  10. package/src/code-generation/fix-spec-paths.ts +6 -19
  11. package/src/code-generation/generate-unified-interface.ts +1 -8
  12. package/src/code-generation/output/quickbase-fixed.json +142 -21
  13. package/src/generated-unified/QuickbaseClient.ts +3 -3
  14. package/tests/playwright/qb/auth/cacheSwitching.test.ts +2 -2
  15. package/tests/setup.ts +29 -9
  16. package/tests/vitest/qb/fields/getFields.test.ts +3 -5
  17. package/tests/vitest/qb/records/runQuery.test.ts +82 -0
  18. package/tests/vitest/unit/apps/getApp.test.ts +17 -12
  19. package/tests/vitest/unit/auth/fetchTempToken401.test.ts +29 -4
  20. package/tests/vitest/unit/auth/getTempToken.test.ts +30 -17
  21. package/tests/vitest/unit/auth/retryOn401.test.ts +39 -5
  22. package/tests/vitest/unit/fields/getFields.test.ts +14 -7
  23. package/tests/vitest/unit/records/deleteRecords.test.ts +28 -34
  24. package/tests/vitest/unit/records/runQuery.test.ts +102 -0
  25. package/tests/vitest/unit/records/upsert.test.ts +31 -41
  26. package/tests/vitest/unit/tables/createTable.test.ts +18 -10
  27. package/tests/vitest/unit/tables/deleteTable.test.ts +28 -19
  28. package/tests/vitest/unit/tables/getAppTables.test.ts +41 -28
  29. package/tests/vitest/unit/tables/getTable.test.ts +53 -32
  30. package/tests/vitest/unit/tables/updateTable.test.ts +17 -11
  31. package/vitest.config.ts +5 -0
package/examples/react.js CHANGED
@@ -1,22 +1,48 @@
1
- import { quickbaseClient } from "quickbase-js";
2
- import { useEffect, useState } from "react";
1
+ import React, { useState, useEffect } from "react";
2
+ import { quickbase } from "quickbase-js";
3
3
 
4
- const client = quickbaseClient({
5
- realm: "myrealm",
6
- userToken: "my-user-token",
7
- });
8
-
9
- function App() {
10
- const [app, setApp] = useState < any > null;
4
+ const App = () => {
5
+ const [appName, setAppName] = useState < string > "Loading...";
6
+ const [error, setError] = (useState < string) | (null > null);
11
7
 
12
8
  useEffect(() => {
13
- client
14
- .getApp({ appId: "my-app-id" })
15
- .then((data) => setApp(data))
16
- .catch((err) => console.error(err));
17
- }, []);
9
+ // Initialize the QuickBase client
10
+ const qb = quickbase({
11
+ realm: "your-realm", // Replace with actual QuickBase realm
12
+ // ------------------------------
13
+ // Authentication Options
14
+ // ------------------------------
15
+ // OPTION 1: User Token Authentication
16
+ // - Use this if you have a QuickBase user token (get it from "My Profile" > "Manage User Tokens")
17
+ // - Works in Node.js or browsers, ideal for standalone apps or testing outside QuickBase
18
+ // - Use the line below and replace with your token; comment out 'useTempTokens'
19
+ // userToken: "your-user-token",
20
+
21
+ // ------------------------------
22
+ // OPTION 2: Temporary Token Authentication
23
+ // - Use this for QuickBase code pages, leveraging the browser’s authenticated session
24
+ // - No user token needed; requires running in a QuickBase browser context
25
+ // - Uncomment the line below and comment out 'userToken' if using this option
26
+ // useTempTokens: true,
27
+ });
28
+
29
+ // Fetch the app
30
+ qb.getApp({ appId: "your-app-id" }) // Replace with actual app ID
31
+ .then((app) => {
32
+ setAppName(app.name);
33
+ })
34
+ .catch((err) => {
35
+ console.error("Error fetching app:", err);
36
+ setError("Failed to load app");
37
+ });
38
+ }, []); // Empty dependency array to run once on mount
18
39
 
19
- return <div>{app ? app.name : "Loading..."}</div>;
20
- }
40
+ return (
41
+ <div>
42
+ <h1>Quickbase Test</h1>
43
+ {error ? <p>{error}</p> : <p>App Name: {appName}</p>}
44
+ </div>
45
+ );
46
+ };
21
47
 
22
48
  export default App;
@@ -1,23 +1,47 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
+
3
4
  <head>
4
5
  <title>Quickbase Test</title>
5
6
  </head>
7
+
6
8
  <body>
7
- <div id="app-name"></div>
9
+ <div>
10
+ <h1>Quickbase Test</h1>
11
+ <p id="result">Loading...</p>
12
+ </div>
8
13
  <script type="module">
9
- import { quickbaseClient } from './dist/quickbaseClient.js';
14
+ import { quickbase } from 'quickbase-js';
15
+ // Initalize the QuickBase client
16
+ const qb = quickbase({
17
+ realm: 'your-realm', // Replace with actual QuickBase realm
18
+ // ------------------------------
19
+ // Authentication Options
20
+ // ----------------------------
21
+ // OPTION 1: User Token Authentication
22
+ // - Use this if you have a QuickBase user token (get it from "My Profile" > "Manage User Tokens")
23
+ // - Works in Node.js or browsers, ideal for standalone apps or testing outside QuickBase
24
+ // - Uncomment the line below and replace with your token; comment out 'useTempTokens'
25
+ // userToken: "your-user-token",
10
26
 
11
- const client = quickbaseClient({
12
- realm: 'myrealm',
13
- userToken: 'my-user-token',
27
+ // ----------------------------
28
+ // OPTION 2: Temporary Token Authentication
29
+ // - Use this for QuickBase code pages, leveraging the browser’s authenticated session
30
+ // - No user token needed; requires running in a QuickBase browser context
31
+ // - Uncomment the line below and comment out 'userToken' if using this option
32
+ // useTempTokens: true,
14
33
  });
15
34
 
16
- client.getApp({ appId: 'my-app-id' })
35
+ // Fetch the app
36
+ qb.getApp({ appId: 'your-app-id' }) // Replace with actual app ID
17
37
  .then((app) => {
18
- document.getElementById('app-name').textContent = app.name;
38
+ document.getElementById('result').textContent = `App Name: ${app.name}`;
19
39
  })
20
- .catch((err) => console.error(err));
40
+ .catch((err) => {
41
+ console.error('Error fetching app:', err);
42
+ document.getElementById('result').textContent = err.message || 'Failed to load app';
43
+ });
21
44
  </script>
22
45
  </body>
46
+
23
47
  </html>
package/log-gen.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  project: quickbase-js
2
- date: 3/10/2025
2
+ date: 3/11/2025
3
3
  root: /home/drew/Projects/quickbase-js
4
4
  goals:
5
5
  - A library for interacting with the QuickBase RESTful API.
@@ -291,184 +291,6 @@ tree:
291
291
  type: file
292
292
  - name: runtime.ts
293
293
  type: file
294
- - name: generated-old
295
- type: directory
296
- children:
297
- - name: .openapi-generator
298
- type: directory
299
- children:
300
- - name: FILES
301
- type: file
302
- - name: VERSION
303
- type: file
304
- - name: .openapi-generator-ignore
305
- type: file
306
- - name: apis
307
- type: directory
308
- children:
309
- - name: AppsApi.ts
310
- type: file
311
- - name: AuditApi.ts
312
- type: file
313
- - name: AuthApi.ts
314
- type: file
315
- - name: DocumentTemplatesApi.ts
316
- type: file
317
- - name: FieldsApi.ts
318
- type: file
319
- - name: FilesApi.ts
320
- type: file
321
- - name: FormulasApi.ts
322
- type: file
323
- - name: PlatformAnalyticsApi.ts
324
- type: file
325
- - name: RecordsApi.ts
326
- type: file
327
- - name: ReportsApi.ts
328
- type: file
329
- - name: SolutionsApi.ts
330
- type: file
331
- - name: TablesApi.ts
332
- type: file
333
- - name: UserTokenApi.ts
334
- type: file
335
- - name: UsersApi.ts
336
- type: file
337
- - name: index.ts
338
- type: file
339
- - name: index.ts
340
- type: file
341
- - name: models
342
- type: directory
343
- children:
344
- - name: AddMembersToGroup200Response.ts
345
- type: file
346
- - name: AddSubgroupsToGroup200Response.ts
347
- type: file
348
- - name: App.ts
349
- type: file
350
- - name: AppMemoryInfo.ts
351
- type: file
352
- - name: AppSecurityProperties.ts
353
- type: file
354
- - name: Audit200Response.ts
355
- type: file
356
- - name: Audit202Response.ts
357
- type: file
358
- - name: AuditRequest.ts
359
- type: file
360
- - name: CloneUserToken200Response.ts
361
- type: file
362
- - name: CloneUserTokenRequest.ts
363
- type: file
364
- - name: CopyApp200Response.ts
365
- type: file
366
- - name: CopyAppRequest.ts
367
- type: file
368
- - name: CreateApp200Response.ts
369
- type: file
370
- - name: CreateAppRequest.ts
371
- type: file
372
- - name: CreateField200Response.ts
373
- type: file
374
- - name: CreateRelationship200Response.ts
375
- type: file
376
- - name: CreateRelationshipRequest.ts
377
- type: file
378
- - name: DeactivateUserToken200Response.ts
379
- type: file
380
- - name: DeleteApp200Response.ts
381
- type: file
382
- - name: DeleteAppRequest.ts
383
- type: file
384
- - name: DeleteFields200Response.ts
385
- type: file
386
- - name: DeleteFile200Response.ts
387
- type: file
388
- - name: DeleteRelationship200Response.ts
389
- type: file
390
- - name: DenyUsers200Response.ts
391
- type: file
392
- - name: ExchangeSsoToken200Response.ts
393
- type: file
394
- - name: ExchangeSsoTokenRequest.ts
395
- type: file
396
- - name: Field.ts
397
- type: file
398
- - name: FieldPermissionsInner.ts
399
- type: file
400
- - name: FieldProperties.ts
401
- type: file
402
- - name: GenerateDocument200Response.ts
403
- type: file
404
- - name: GetField200Response.ts
405
- type: file
406
- - name: GetRelationships200Response.ts
407
- type: file
408
- - name: GetReport200Response.ts
409
- type: file
410
- - name: GetTempTokenDBID200Response.ts
411
- type: file
412
- - name: GetUsers200Response.ts
413
- type: file
414
- - name: GetUsersRequest.ts
415
- type: file
416
- - name: PlatformAnalyticEventSummaries200Response.ts
417
- type: file
418
- - name: PlatformAnalyticEventSummaries200ResponseMetadata.ts
419
- type: file
420
- - name: PlatformAnalyticEventSummaries200ResponseResultsInner.ts
421
- type: file
422
- - name: PlatformAnalyticEventSummaries200ResponseResultsInnerEventTypesInner.ts
423
- type: file
424
- - name: PlatformAnalyticEventSummaries200ResponseResultsInnerTotals.ts
425
- type: file
426
- - name: PlatformAnalyticEventSummaries200ResponseTotals.ts
427
- type: file
428
- - name: PlatformAnalyticEventSummaries200ResponseWhereInner.ts
429
- type: file
430
- - name: PlatformAnalyticEventSummariesRequest.ts
431
- type: file
432
- - name: PlatformAnalyticEventSummariesRequestWhereInner.ts
433
- type: file
434
- - name: PlatformAnalyticReads200Response.ts
435
- type: file
436
- - name: RemoveMembersFromGroup200Response.ts
437
- type: file
438
- - name: RemoveSubgroupsFromGroup200Response.ts
439
- type: file
440
- - name: RunFormula200Response.ts
441
- type: file
442
- - name: RunFormulaRequest.ts
443
- type: file
444
- - name: RunQuery200Response.ts
445
- type: file
446
- - name: RunQueryRequest.ts
447
- type: file
448
- - name: RunReport200Response.ts
449
- type: file
450
- - name: Table.ts
451
- type: file
452
- - name: TransferUserToken200Response.ts
453
- type: file
454
- - name: TransferUserTokenRequest.ts
455
- type: file
456
- - name: UndenyUsers200Response.ts
457
- type: file
458
- - name: UpdateApp200Response.ts
459
- type: file
460
- - name: UpdateAppRequest.ts
461
- type: file
462
- - name: UpdateFieldRequest.ts
463
- type: file
464
- - name: UpdateRelationshipRequest.ts
465
- type: file
466
- - name: Upsert200Response.ts
467
- type: file
468
- - name: index.ts
469
- type: file
470
- - name: runtime.ts
471
- type: file
472
294
  - name: generated-unified
473
295
  type: directory
474
296
  children:
@@ -1901,36 +1723,157 @@ tree:
1901
1723
  type: file
1902
1724
  contents: |
1903
1725
  // tests/vitest/qb/records/deleteRecords.test.ts
1904
- import { describe, test, expect } from "vitest";
1726
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
1905
1727
  import { quickbase } from "@/quickbaseClient.ts";
1906
1728
 
1907
- // Temporarily skip this suite due to timeout issues possibly related to upsert
1908
- describe.skip("deleteRecords", () => {
1729
+ const TABLE_ID = "buwai2zws";
1730
+ const UNIQUE_FIELD_ID = 3; // Record ID field
1731
+ const MARKER_FIELD_ID = 6; // Text field for marking test records
1732
+
1733
+ describe("QuickbaseClient - DeleteRecords Integration", () => {
1909
1734
  const qb = quickbase({
1910
1735
  realm: "builderprogram-dbradford6815",
1911
1736
  userToken: process.env.QB_USER_TOKEN,
1912
1737
  debug: true,
1913
1738
  });
1914
1739
 
1915
- test("deletes records matching query", async () => {
1916
- const upsertResponse = await qb.upsert({
1917
- body: { to: "buwai2zws", data: [{}] },
1918
- });
1919
- const recordId = upsertResponse.metadata.createdRecordIds[0];
1740
+ beforeEach(async () => {
1741
+ try {
1742
+ await qb.deleteRecords({
1743
+ body: {
1744
+ from: TABLE_ID,
1745
+ where: `{${MARKER_FIELD_ID}.CT.'test-marker-delete'}`,
1746
+ },
1747
+ });
1748
+ } catch (e) {
1749
+ // Ignore if no records exist
1750
+ }
1751
+ });
1920
1752
 
1921
- const deleteResponse = await qb.deleteRecords({
1922
- body: { from: "buwai2zws", where: `{3.EX.${recordId}}` },
1923
- });
1753
+ afterEach(async () => {
1754
+ try {
1755
+ await qb.deleteRecords({
1756
+ body: {
1757
+ from: TABLE_ID,
1758
+ where: `{${MARKER_FIELD_ID}.CT.'test-marker-delete'}`,
1759
+ },
1760
+ });
1761
+ } catch (e) {}
1762
+ });
1763
+
1764
+ test(
1765
+ "deletes a newly upserted record",
1766
+ async () => {
1767
+ const upsertResponse = await qb.upsert({
1768
+ body: {
1769
+ to: TABLE_ID,
1770
+ data: [{ [MARKER_FIELD_ID]: { value: "test-marker-delete" } }],
1771
+ fieldsToReturn: [UNIQUE_FIELD_ID], // Return record ID
1772
+ },
1773
+ });
1774
+ const recordId = upsertResponse.metadata.createdRecordIds[0];
1775
+ expect(recordId).toBeDefined();
1776
+ expect(upsertResponse.data[0][UNIQUE_FIELD_ID].value).toBe(recordId);
1777
+
1778
+ const deleteResponse = await qb.deleteRecords({
1779
+ body: { from: TABLE_ID, where: `{${UNIQUE_FIELD_ID}.EX.${recordId}}` },
1780
+ });
1781
+
1782
+ expect(deleteResponse).toEqual({ numberDeleted: 1 });
1783
+
1784
+ const checkResponse = await qb.deleteRecords({
1785
+ body: { from: TABLE_ID, where: `{${UNIQUE_FIELD_ID}.EX.${recordId}}` },
1786
+ });
1787
+ expect(checkResponse.numberDeleted).toBe(0);
1788
+ },
1789
+ { timeout: 10000 }
1790
+ );
1791
+
1792
+ test(
1793
+ "handles empty result when no records match",
1794
+ async () => {
1795
+ const response = await qb.deleteRecords({
1796
+ body: { from: TABLE_ID, where: "{3.EX.'999999'}" },
1797
+ });
1798
+ expect(response).toEqual({ numberDeleted: 0 });
1799
+ },
1800
+ { timeout: 10000 }
1801
+ );
1802
+ });
1803
+ - name: upsert.test.ts
1804
+ type: file
1805
+ contents: |
1806
+ // tests/vitest/qb/records/upsert.test.ts
1807
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
1808
+ import { quickbase } from "@/quickbaseClient.ts";
1809
+
1810
+ const TABLE_ID = "buwai2zws";
1811
+ const MARKER_FIELD_ID = 6; // Text field for marking test records
1812
+
1813
+ describe("QuickbaseClient - Upsert Integration", () => {
1814
+ const qb = quickbase({
1815
+ realm: "builderprogram-dbradford6815",
1816
+ userToken: process.env.QB_USER_TOKEN,
1817
+ debug: true,
1818
+ });
1924
1819
 
1925
- expect(deleteResponse).toEqual({ numberDeleted: 1 });
1820
+ beforeEach(async () => {
1821
+ try {
1822
+ await qb.deleteRecords({
1823
+ body: {
1824
+ from: TABLE_ID,
1825
+ where: `{${MARKER_FIELD_ID}.CT.'test-marker-upsert'}`,
1826
+ },
1827
+ });
1828
+ } catch (e) {
1829
+ // Ignore if no records exist
1830
+ }
1926
1831
  });
1927
1832
 
1928
- test("handles empty result", async () => {
1929
- const response = await qb.deleteRecords({
1930
- body: { from: "buwai2zws", where: "{3.EX.'999999'}" },
1931
- });
1932
- expect(response).toEqual({ numberDeleted: 0 });
1833
+ afterEach(async () => {
1834
+ try {
1835
+ await qb.deleteRecords({
1836
+ body: {
1837
+ from: TABLE_ID,
1838
+ where: `{${MARKER_FIELD_ID}.CT.'test-marker-upsert'}`,
1839
+ },
1840
+ });
1841
+ } catch (e) {}
1933
1842
  });
1843
+
1844
+ test(
1845
+ "creates a new record successfully",
1846
+ async () => {
1847
+ const response = await qb.upsert({
1848
+ body: {
1849
+ to: TABLE_ID,
1850
+ data: [{ [MARKER_FIELD_ID]: { value: "test-marker-upsert" } }],
1851
+ fieldsToReturn: [MARKER_FIELD_ID, 3], // Return marker and record ID
1852
+ },
1853
+ });
1854
+
1855
+ expect(response.metadata.createdRecordIds.length).toBe(1);
1856
+ expect(response.data).toHaveLength(1);
1857
+ expect(response.data[0][MARKER_FIELD_ID].value).toBe(
1858
+ "test-marker-upsert"
1859
+ );
1860
+ expect(response.data[0][3].value).toBeDefined(); // Record ID assigned by QuickBase
1861
+ expect(response.metadata.totalNumberOfRecordsProcessed).toBe(1);
1862
+ },
1863
+ { timeout: 10000 }
1864
+ );
1865
+
1866
+ test(
1867
+ "handles empty data gracefully",
1868
+ async () => {
1869
+ await expect(
1870
+ qb.upsert({
1871
+ body: { to: TABLE_ID, data: [] },
1872
+ })
1873
+ ).rejects.toThrow("API Error: Bad Request (Status: 400)");
1874
+ },
1875
+ { timeout: 10000 }
1876
+ );
1934
1877
  });
1935
1878
  - name: tables
1936
1879
  type: directory
@@ -2831,6 +2774,7 @@ tree:
2831
2774
  import { createClient, mockFetch } from "@tests/setup.ts";
2832
2775
  import { vi } from "vitest";
2833
2776
 
2777
+ // Note: Type augmentation moved to src/types.d.ts
2834
2778
  describe("QuickbaseClient - upsert (Unit)", () => {
2835
2779
  beforeEach(() => {
2836
2780
  vi.resetModules(); // Reset module cache
@@ -2961,7 +2905,7 @@ tree:
2961
2905
  const result = await qb.upsert({
2962
2906
  body: { to: "test-table-id", data: [{ "7": { value: "value2" } }] },
2963
2907
  dbid: "test-dbid",
2964
- });
2908
+ } as any); // Temporary type assertion until types.d.ts is applied
2965
2909
 
2966
2910
  expect(mockFetch).toHaveBeenCalledTimes(2);
2967
2911
  expect(mockFetch).toHaveBeenNthCalledWith(
@@ -3046,7 +2990,11 @@ tree:
3046
2990
  })
3047
2991
  );
3048
2992
 
3049
- expect(result.data[0]["6"].value).toBe("value1");
2993
+ if (result.data && result.data.length > 0) {
2994
+ expect((result.data[0]["6"] as { value: any }).value).toBe("value1");
2995
+ } else {
2996
+ throw new Error("Expected data array to have at least one element");
2997
+ }
3050
2998
  });
3051
2999
  });
3052
3000
  - name: tables
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "quickbase-js",
3
3
  "main": "dist/quickbase.js",
4
4
  "types": "dist/quickbase.d.ts",
5
- "version": "1.1.0-beta.0",
5
+ "version": "1.1.0-beta.2",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -22,9 +22,9 @@
22
22
  "release:push": "npm run release:beta && git push --follow-tags origin main",
23
23
  "release:publish": "npm run release:push && npm publish --tag beta",
24
24
  "fix-spec": "node --loader ts-node/esm src/code-generation/fix-spec-main.ts",
25
- "regenerate": "node --loader ts-node/esm src/code-generation/regenerate-client.ts",
26
- "generate-unified": "node --loader ts-node/esm src/code-generation/generate-unified-interface.ts",
27
- "update-client": "npm run fix-spec && npm run regenerate && npm run generate-unified",
25
+ "regenerate": "rimraf src/generated && node --loader ts-node/esm src/code-generation/regenerate-client.ts",
26
+ "regenerate-unified": "node --loader ts-node/esm src/code-generation/generate-unified-interface.ts",
27
+ "regenerate-all": "npm run fix-spec && npm run regenerate && npm run regenerate-unified",
28
28
  "log-gen": "node --loader ts-node/esm src/log-gen.ts",
29
29
  "build": "rimraf dist && rollup -c",
30
30
  "build:prod": "rm -rf dist/* && NODE_ENV=production rollup -c",