quickbase-js 1.2.0 → 2.0.0-alpha.3

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 (95) hide show
  1. package/README.md +351 -227
  2. package/dist/auth/index.d.ts +15 -0
  3. package/dist/auth/index.d.ts.map +1 -0
  4. package/dist/auth/index.js +29 -0
  5. package/dist/auth/index.js.map +1 -0
  6. package/dist/auth/sso-token.d.ts +28 -0
  7. package/dist/auth/sso-token.d.ts.map +1 -0
  8. package/dist/auth/sso-token.js +108 -0
  9. package/dist/auth/sso-token.js.map +1 -0
  10. package/dist/auth/temp-token.d.ts +31 -0
  11. package/dist/auth/temp-token.d.ts.map +1 -0
  12. package/dist/auth/temp-token.js +121 -0
  13. package/dist/auth/temp-token.js.map +1 -0
  14. package/dist/auth/token-cache.d.ts +44 -0
  15. package/dist/auth/token-cache.d.ts.map +1 -0
  16. package/dist/auth/token-cache.js +84 -0
  17. package/dist/auth/token-cache.js.map +1 -0
  18. package/dist/auth/types.d.ts +44 -0
  19. package/dist/auth/types.d.ts.map +1 -0
  20. package/dist/auth/types.js +5 -0
  21. package/dist/auth/types.js.map +1 -0
  22. package/dist/auth/user-token.d.ts +17 -0
  23. package/dist/auth/user-token.d.ts.map +1 -0
  24. package/dist/auth/user-token.js +30 -0
  25. package/dist/auth/user-token.js.map +1 -0
  26. package/dist/client/index.d.ts +12 -0
  27. package/dist/client/index.d.ts.map +1 -0
  28. package/dist/client/index.js +8 -0
  29. package/dist/client/index.js.map +1 -0
  30. package/dist/client/pagination.d.ts +131 -0
  31. package/dist/client/pagination.d.ts.map +1 -0
  32. package/dist/client/pagination.js +232 -0
  33. package/dist/client/pagination.js.map +1 -0
  34. package/dist/client/request.d.ts +45 -0
  35. package/dist/client/request.d.ts.map +1 -0
  36. package/dist/client/request.js +232 -0
  37. package/dist/client/request.js.map +1 -0
  38. package/dist/client/retry.d.ts +41 -0
  39. package/dist/client/retry.d.ts.map +1 -0
  40. package/dist/client/retry.js +122 -0
  41. package/dist/client/retry.js.map +1 -0
  42. package/dist/client/throttle.d.ts +46 -0
  43. package/dist/client/throttle.d.ts.map +1 -0
  44. package/dist/client/throttle.js +85 -0
  45. package/dist/client/throttle.js.map +1 -0
  46. package/dist/core/config.d.ts +13 -0
  47. package/dist/core/config.d.ts.map +1 -0
  48. package/dist/core/config.js +120 -0
  49. package/dist/core/config.js.map +1 -0
  50. package/dist/core/dates.d.ts +18 -0
  51. package/dist/core/dates.d.ts.map +1 -0
  52. package/dist/core/dates.js +58 -0
  53. package/dist/core/dates.js.map +1 -0
  54. package/dist/core/errors.d.ts +134 -0
  55. package/dist/core/errors.d.ts.map +1 -0
  56. package/dist/core/errors.js +185 -0
  57. package/dist/core/errors.js.map +1 -0
  58. package/dist/core/index.d.ts +10 -0
  59. package/dist/core/index.d.ts.map +1 -0
  60. package/dist/core/index.js +9 -0
  61. package/dist/core/index.js.map +1 -0
  62. package/dist/core/logger.d.ts +41 -0
  63. package/dist/core/logger.d.ts.map +1 -0
  64. package/dist/core/logger.js +96 -0
  65. package/dist/core/logger.js.map +1 -0
  66. package/dist/core/types.d.ts +154 -0
  67. package/dist/core/types.d.ts.map +1 -0
  68. package/dist/core/types.js +23 -0
  69. package/dist/core/types.js.map +1 -0
  70. package/dist/generated/client.d.ts +18 -0
  71. package/dist/generated/client.d.ts.map +1 -0
  72. package/dist/generated/client.js +1390 -0
  73. package/dist/generated/client.js.map +1 -0
  74. package/dist/generated/types.d.ts +3827 -0
  75. package/dist/generated/types.d.ts.map +1 -0
  76. package/dist/generated/types.js +8 -0
  77. package/dist/generated/types.js.map +1 -0
  78. package/dist/index.d.ts +89 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +99 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/quickbase.esm.js +7 -0
  83. package/dist/quickbase.esm.js.map +7 -0
  84. package/dist/quickbase.min.js +7 -0
  85. package/dist/quickbase.min.js.map +7 -0
  86. package/package.json +60 -86
  87. package/dist/esm/quickbase.d.ts +0 -8094
  88. package/dist/esm/quickbase.js +0 -8333
  89. package/dist/esm/quickbase.js.map +0 -1
  90. package/dist/esm/quickbase.min.js +0 -2
  91. package/dist/esm/quickbase.min.js.map +0 -1
  92. package/dist/umd/quickbase.umd.js +0 -8909
  93. package/dist/umd/quickbase.umd.js.map +0 -1
  94. package/dist/umd/quickbase.umd.min.js +0 -2
  95. package/dist/umd/quickbase.umd.min.js.map +0 -1
package/README.md CHANGED
@@ -1,330 +1,454 @@
1
- # quickbase-js
1
+ # QuickBase JS SDK v2
2
2
 
3
- A Typescript API client for the [Quickbase JSON RESTful API](https://developer.quickbase.com/).
3
+ A TypeScript/JavaScript client for the QuickBase JSON RESTful API.
4
4
 
5
- Support for various authentication types (`user token`, `temporary tokens`, `SSO token`), `concurrent rate limiting strategies`, `auto pagination`, `js date conversion`, `429` (rate limit) and `401` (auth) error handling retries. It uses a Proxy to dynamically invoke API methods derived from the OpenAPI specification.
5
+ ## Features
6
6
 
7
- Browser and Node.js support. ESM and UMD builds are available.
7
+ - **Typed API Methods** - Full TypeScript support with auto-generated types from OpenAPI spec
8
+ - **Multiple Auth Methods** - User token, temporary token, and SSO authentication
9
+ - **Fluent Pagination** - Chain `.all()`, `.paginate()`, or `.noPaginate()` on paginated endpoints
10
+ - **Date Conversion** - Automatic conversion of ISO date strings to JavaScript Date objects
11
+ - **Rate Limit Handling** - Automatic retry with exponential backoff on 429 errors
12
+ - **Proactive Throttling** - Optional client-side request throttling
13
+ - **Tree-Shakeable** - Static method generation for optimal bundle size
8
14
 
9
- Authentication and throttle methods are opinionated. See configuration options for details and available settings.
15
+ ## API Reference
10
16
 
11
- ## API Documentation
17
+ **[View all 59 API methods →](./interfaces/QuickbaseAPI.html)**
12
18
 
13
- <a href="https://quickbase-js.netlify.app/" target="_blank"> Documentation</a> for quickbase-js.
19
+ The SDK provides typed methods for all QuickBase API endpoints including Apps, Tables, Fields, Records, Reports, Users, and more. Each method includes JSDoc documentation with links to the official QuickBase API docs.
14
20
 
15
21
  ## Installation
16
22
 
17
- #### Node.js install
23
+ ### npm / Node.js
18
24
 
19
25
  ```bash
20
- npm install --save quickbase-js
26
+ npm install quickbase-js
21
27
  ```
22
28
 
23
- #### CDN install.
29
+ ### Browser / CDN (QuickBase Code Pages)
24
30
 
25
- Find and select the latest version. UMD is recommended for code pages.
31
+ ```html
32
+ <script src="https://cdn.jsdelivr.net/npm/quickbase-js@2/dist/quickbase.min.js"></script>
33
+ <script>
34
+ const client = QuickBase.createClient({
35
+ realm: 'mycompany',
36
+ auth: { type: 'temp-token' },
37
+ });
38
+
39
+ client.getApp({ appId: 'bpqe82s1' }).then(app => {
40
+ console.log(app.name);
41
+ });
42
+ </script>
43
+ ```
26
44
 
27
- <a href="https://www.jsdelivr.com/package/npm/quickbase-js?tab=files" target="_blank">CDN Files</a> for quickbase-js
45
+ Or with ES modules:
28
46
 
29
47
  ```html
30
- <!DOCTYPE html>
31
- <html>
32
- <head>
33
- <title>Quickbase</title>
34
- <!-- Replace xx.xx.xx with the latest version from CDN Files-->
35
- <script src="https://cdn.jsdelivr.net/npm/quickbase-js@xx.xx.xx/dist/umd/quickbase.umd.min.js"></script>
36
- </head>
37
- <body>
38
- <script>
39
- const realm = ""; // Replace with your realm
40
- const appId = ""; // Replace with your app ID
41
-
42
- const qb = QuickbaseJS.quickbase({
43
- realm,
44
- useTempTokens: true,
45
- });
46
-
47
- qb.getApp({ appId })
48
- .then((app) => console.log(app.name))
49
- .catch((err) => console.log(err.message));
50
- </script>
51
- </body>
52
- </html>
53
- ```
48
+ <script type="module">
49
+ import { createClient } from 'https://cdn.jsdelivr.net/npm/quickbase-js@2/dist/quickbase.esm.js';
54
50
 
55
- ## Authentication Examples
51
+ const client = createClient({
52
+ realm: 'mycompany',
53
+ auth: { type: 'temp-token' },
54
+ });
56
55
 
57
- ### User Token
56
+ const app = await client.getApp({ appId: 'bpqe82s1' });
57
+ console.log(app.name);
58
+ </script>
59
+ ```
58
60
 
59
- ```javascript
60
- import { quickbase } from "quickbase-js"; // Adjust the import path as needed
61
+ ## Quick Start
61
62
 
62
- // QuickBase config variables
63
- const QB_REALM = ""; // Your QuickBase realm (e.g., 'mycompany')
64
- const QB_USER_TOKEN = ""; // Your QuickBase user token (e.g., 'b12345_abcde...')
65
- const QB_APP_ID = ""; // Your app ID (e.g., 'bxyz789')
63
+ ```typescript
64
+ import { createClient } from 'quickbase-js';
66
65
 
67
- const qb = quickbase({
68
- realm: QB_REALM,
69
- userToken: QB_USER_TOKEN,
66
+ const client = createClient({
67
+ realm: 'mycompany',
68
+ auth: {
69
+ type: 'user-token',
70
+ userToken: 'your-user-token',
71
+ },
70
72
  });
71
73
 
72
- const getAppDetails = async () => {
73
- try {
74
- const response = await qb.getApp({
75
- appId: QB_APP_ID,
76
- });
77
- console.log("App Details:", response);
78
- } catch (error) {
79
- console.error("Error fetching app:", error.message);
80
- }
81
- };
74
+ // Use typed API methods
75
+ const app = await client.getApp({ appId: 'bpqe82s1' });
76
+ console.log(app.name);
82
77
 
83
- getAppDetails();
78
+ // Query records
79
+ const records = await client.runQuery({
80
+ from: 'bpqe82s1',
81
+ select: [3, 6, 7],
82
+ where: "{6.EX.'Active'}",
83
+ });
84
+ console.log(records.data);
84
85
  ```
85
86
 
86
- ### Temporary Tokens (Code Pages)
87
-
88
- ```javascript
89
- import { quickbase } from "quickbase-js"; // Adjust the import path as needed
87
+ ## Authentication
90
88
 
91
- // QuickBase config variables
92
- const QB_REALM = ""; // Your QuickBase realm (e.g., 'mycompany')
93
- const QB_APP_ID = ""; // Your app ID (e.g., 'bxyz789')
89
+ ### User Token (Recommended for Server-Side)
94
90
 
95
- const qb = quickbase({
96
- realm: QB_REALM,
97
- useTempTokens: true,
91
+ ```typescript
92
+ const client = createClient({
93
+ realm: 'mycompany',
94
+ auth: {
95
+ type: 'user-token',
96
+ userToken: 'your-user-token',
97
+ },
98
98
  });
99
-
100
- const getAppDetails = async () => {
101
- try {
102
- const response = await qb.getApp({
103
- appId: QB_APP_ID,
104
- });
105
- console.log("App Details:", response);
106
- } catch (error) {
107
- console.error("Error fetching app:", error.message);
108
- }
109
- };
110
-
111
- getAppDetails();
112
99
  ```
113
100
 
114
- ### SSO Token
101
+ ### Temporary Token (Recommended for Browser/Code Pages)
115
102
 
116
- ```javascript
117
- import { quickbase } from "quickbase-js"; // Adjust the import path as needed
103
+ Temporary tokens are automatically fetched and cached per database. They refresh on 401 errors.
118
104
 
119
- // QuickBase config variables
120
- const QB_REALM = ""; // Your QuickBase realm (e.g., 'mycompany')
121
- const QB_SAML_TOKEN = ""; // Your SAML token (e.g., 'saml_xyz789...')
122
- const QB_APP_ID = ""; // Your app ID (e.g., 'bxyz789')
105
+ ```typescript
106
+ // In QuickBase Code Pages - no user token needed (uses browser session)
107
+ const client = createClient({
108
+ realm: 'mycompany',
109
+ auth: {
110
+ type: 'temp-token',
111
+ },
112
+ });
123
113
 
124
- const qb = quickbase({
125
- realm: QB_REALM,
126
- samlToken: QB_SAML_TOKEN,
127
- useSso: true,
114
+ // Outside Code Pages - user token required to fetch temp tokens
115
+ const client = createClient({
116
+ realm: 'mycompany',
117
+ auth: {
118
+ type: 'temp-token',
119
+ userToken: 'your-user-token', // Required outside Code Pages
120
+ appToken: 'optional-app-token', // If app requires it
121
+ },
128
122
  });
123
+ ```
129
124
 
130
- const getAppDetails = async () => {
131
- try {
132
- const response = await qb.getApp({
133
- appId: QB_APP_ID,
134
- });
135
- console.log("App Details:", response);
136
- } catch (error) {
137
- console.error("Error fetching app:", error.message);
138
- }
139
- };
125
+ ### SSO Token
140
126
 
141
- getAppDetails();
127
+ ```typescript
128
+ const client = createClient({
129
+ realm: 'mycompany',
130
+ auth: {
131
+ type: 'sso',
132
+ samlToken: 'your-saml-token',
133
+ },
134
+ });
142
135
  ```
143
136
 
144
- ## Configuration
137
+ ## Pagination
145
138
 
146
- The `quickbase` function accepts a `QuickbaseConfig` object with the following options:
139
+ Paginated endpoints (`runQuery`, `runReport`, `getUsers`, etc.) return a `PaginatedRequest` that supports fluent pagination methods.
147
140
 
148
- ### User Options
141
+ ### Default Behavior (Single Page)
149
142
 
150
- - **`realm`** (`string`): Your QuickBase realm (e.g., "company"). This is required and has no default value.
143
+ ```typescript
144
+ // Returns first page only
145
+ const page = await client.runQuery({ from: 'tableId' });
146
+ console.log(page.data.length); // e.g., 100 records
147
+ console.log(page.metadata.totalRecords); // e.g., 5000 total
148
+ ```
151
149
 
152
- - **`userToken`** (`string`, optional): A QuickBase user token for authentication. No default is provided.
150
+ ### Fetch All Pages
153
151
 
154
- - **`useTempTokens`** (`boolean`, optional): Enables temporary token authentication. Defaults to `false`.
152
+ ```typescript
153
+ // Automatically fetches all pages and combines results
154
+ const all = await client.runQuery({ from: 'tableId' }).all();
155
+ console.log(all.data.length); // 5000 records
156
+ ```
155
157
 
156
- - **`useSso`** (`boolean`, optional): Enables SSO authentication. Defaults to `false`.
158
+ ### Fetch with Record Limit
157
159
 
158
- - **`samlToken`** (`string`, optional): A SAML token for SSO authentication. No default is provided.
160
+ ```typescript
161
+ // Fetch up to 500 records (may span multiple pages)
162
+ const limited = await client.runQuery({ from: 'tableId' }).paginate({ limit: 500 });
163
+ console.log(limited.data.length); // 500 records
164
+ ```
159
165
 
160
- ### Advanced User Options
166
+ ### Explicit Single Page
161
167
 
162
- - **`throttle`** (`{ type?: 'flow' | 'burst-aware';` `rate?: number;` `burst?: number;` `windowSeconds?: number }`, optional): Configures concurrent rate limiting to manage API request throughput. Defaults to `{ type: 'flow', rate: 5, burst: 50 }`.
168
+ ```typescript
169
+ // Explicitly fetch single page (useful when autoPaginate is enabled globally)
170
+ const single = await client.runQuery({ from: 'tableId' }).noPaginate();
171
+ ```
163
172
 
164
- - **`type`** (`string`): Throttle strategy. _Setting type without rate or burst enables default settings for that throttle type._
173
+ ### Global Auto-Pagination
165
174
 
166
- - `'flow'` (default): Uses `FlowThrottleBucket` for a QuickBase-agnostic burst-then-rate flow. Ideal for steady request pacing.
175
+ ```typescript
176
+ const client = createClient({
177
+ realm: 'mycompany',
178
+ auth: { type: 'user-token', userToken: 'token' },
179
+ autoPaginate: true, // Default await now fetches all pages
180
+ });
167
181
 
168
- - `'burst-aware'`: Uses `BurstAwareThrottleBucket` for QuickBase-specific burst throttling with a sliding window (e.g., 100 requests per 10 seconds). Ideal for when you need to use nearly all your allotted API calls immediately, for example on page load.
182
+ // Now direct await fetches all pages
183
+ const all = await client.runQuery({ from: 'tableId' });
169
184
 
170
- _Set rate and burst if changing defaults._
185
+ // Use .noPaginate() to get single page
186
+ const page = await client.runQuery({ from: 'tableId' }).noPaginate();
187
+ ```
171
188
 
172
- - **`rate`** (`number`): Requests per second after the initial burst (for `'flow'` only). Default is `5`. Meaning 5 request tokens get created each second.
189
+ ## Date Conversion
173
190
 
174
- - **`burst`** (`number`): Maximum concurrent requests:
175
- - For `'flow'`: Initial concurrent burst size (default: 50), followed by `rate`/sec.
176
- - For `'burst-aware'`: Concurrent burst cap per window (default: 100), waits for window reset if exceeded.
177
- - **`windowSeconds`** (`number`, `'burst-aware'` only): Sliding window duration in seconds (default: 10). Caps total requests (e.g., 100 requests available every 10s).
191
+ By default, ISO 8601 date strings in API responses are automatically converted to JavaScript `Date` objects:
178
192
 
179
- - **Examples**:
180
- - `{ type: 'flow', rate: 5, burst: 50 }`: **~10s for 100 requests**, (50 instant, and 1 every 200ms. In other words, 50 at 10/sec).
181
- - `{ type: 'burst-aware', burst: 100, windowSeconds: 10 }`: **~10s for 100 requests**, (100 instant, refreshing every 10s for next burst).
193
+ ```typescript
194
+ const app = await client.getApp({ appId: 'bpqe82s1' });
182
195
 
183
- - **`maxRetries`** (`number`, optional): Maximum retries for failed requests. Defaults to `3`.
196
+ // Date fields are now Date objects
197
+ console.log(app.created instanceof Date); // true
198
+ console.log(app.created.toISOString()); // "2024-01-15T10:30:00.000Z"
184
199
 
185
- - **`retryDelay`** (`number`, optional): Base delay (in milliseconds) between retries, increases exponentially. Defaults to `1000`.
200
+ // Works with nested objects and arrays
201
+ const records = await client.runQuery({ from: 'tableId' });
202
+ records.data.forEach(record => {
203
+ // Date field values are converted
204
+ console.log(record['7'].value instanceof Date); // true for date/timestamp fields
205
+ });
206
+ ```
186
207
 
187
- - **`tempTokenLifespan`** (`number`, optional): Lifespan (in milliseconds) of temporary tokens in the cache. Defaults to 4 minutes 50 seconds (290000 ms).
208
+ To disable date conversion and keep dates as strings:
188
209
 
189
- - **`convertDates`** (`boolean`, optional): Converts ISO date strings to `Date` objects in responses. Defaults to `true`.
210
+ ```typescript
211
+ const client = createClient({
212
+ realm: 'mycompany',
213
+ auth: { type: 'user-token', userToken: 'token' },
214
+ convertDates: false, // Keep dates as ISO strings
215
+ });
216
+ ```
190
217
 
191
- - **`autoPaginate`** (`boolean`, optional): Enables automatic pagination of multi-page API responses. Defaults to `true`.
218
+ ## Configuration Options
219
+
220
+ ```typescript
221
+ const client = createClient({
222
+ // Required
223
+ realm: 'mycompany',
224
+ auth: { /* see authentication section */ },
225
+
226
+ // Optional
227
+ debug: false, // Enable debug logging
228
+ timeout: 30000, // Request timeout in ms
229
+ baseUrl: 'https://api.quickbase.com/v1', // API base URL
230
+ autoPaginate: false, // Auto-paginate on direct await
231
+ convertDates: true, // Convert ISO date strings to Date objects
232
+
233
+ // Rate limiting
234
+ rateLimit: {
235
+ // Optional client-side throttling
236
+ // QuickBase allows 100 requests per 10 seconds per user token
237
+ proactiveThrottle: {
238
+ enabled: false,
239
+ requestsPer10Seconds: 100,
240
+ },
241
+
242
+ // Retry configuration for 429 and 5xx errors
243
+ retry: {
244
+ maxAttempts: 3,
245
+ initialDelayMs: 1000,
246
+ maxDelayMs: 30000,
247
+ multiplier: 2,
248
+ },
249
+
250
+ // Callback when rate limited
251
+ onRateLimit: (info) => {
252
+ console.log(`Rate limited! Retry after ${info.retryAfter}s`);
253
+ console.log(`Request: ${info.requestUrl}`);
254
+ console.log(`Ray ID: ${info.qbApiRay}`);
255
+ },
256
+ },
257
+ });
258
+ ```
192
259
 
193
- ### Overrides and Development Options
260
+ ## API Methods
194
261
 
195
- - **`fetchApi`** (`typeof fetch`, optional): Defaults to built-in `fetch` in browsers and Node.js >= 18. In older Node.js versions, node-fetch or another compatible library via fetchApi is required.
262
+ All QuickBase API endpoints are available as typed methods:
196
263
 
197
- - **`baseUrl`** (`string`, optional): Base URL for the QuickBase API. Defaults to `"https://api.quickbase.com/v1"`.
264
+ ```typescript
265
+ // Apps
266
+ const app = await client.getApp({ appId: 'bpqe82s1' });
267
+ const newApp = await client.createApp({ name: 'My App', description: 'Test' });
268
+ await client.updateApp({ appId: 'bpqe82s1' }, { name: 'Updated Name' });
269
+ await client.deleteApp({ appId: 'bpqe82s1' }, { name: 'My App' });
198
270
 
199
- - **`debug`** (`boolean`, optional): Enables debug logging to the console. Defaults to `false`.
271
+ // Tables
272
+ const tables = await client.getAppTables({ appId: 'bpqe82s1' });
273
+ const table = await client.getTable({ appId: 'bpqe82s1', tableId: 'byyy82s1' });
200
274
 
201
- - **`tempToken`** (`string`, optional): Overrides default tempToken behavior by providing your own token.
275
+ // Fields
276
+ const fields = await client.getFields({ tableId: 'byyy82s1' });
202
277
 
203
- - **`tokenCache`** (`TokenCache`, optional): Allows use of a custom token cache instance.
278
+ // Records
279
+ const records = await client.runQuery({
280
+ from: 'byyy82s1',
281
+ select: [3, 6, 7],
282
+ where: "{6.GT.100}",
283
+ sortBy: [{ fieldId: 3, order: 'ASC' }],
284
+ options: { top: 100, skip: 0 },
285
+ });
204
286
 
205
- ---
287
+ // Insert/Update records
288
+ const result = await client.upsert({
289
+ to: 'byyy82s1',
290
+ data: [
291
+ { '6': { value: 'New Record' }, '7': { value: 42 } },
292
+ ],
293
+ });
206
294
 
207
- #### Configuration Notes
295
+ // Delete records
296
+ await client.deleteRecords({
297
+ from: 'byyy82s1',
298
+ where: "{3.EX.123}",
299
+ });
208
300
 
209
- - **Authentication**: Three mutually exclusive methods: `userToken`, `useTempTokens`, and `useSso` with `samlToken`. Only one may be active at a time.
210
- - **`tokenCache`**: Temporary tokens are cached here with their `dbid` and `tempTokenLifespan` when `useTempTokens` is enabled.
301
+ // Reports
302
+ const report = await client.runReport(
303
+ { reportId: 'abc123', tableId: 'byyy82s1' },
304
+ { skip: 0, top: 100 }
305
+ );
306
+
307
+ // Users
308
+ const users = await client.getUsers(
309
+ { accountId: '123456' },
310
+ { appIds: ['bpqe82s1'] }
311
+ );
312
+ ```
211
313
 
212
- ---
314
+ ### Raw Request
213
315
 
214
- ### Pagination Control
316
+ For endpoints not covered by typed methods, use the generic `request` method:
215
317
 
216
- The library supports automatic pagination for methods like `runQuery` when `autoPaginate` is enabled (default: `true`). To temporarily disable or constrain pagination for a specific operation without altering the global configuration, use the `withPaginationDisabled()` or `withPaginationLimit()` methods.
318
+ ```typescript
319
+ const result = await client.request<MyResponseType>({
320
+ method: 'POST',
321
+ path: '/some/endpoint',
322
+ body: { key: 'value' },
323
+ query: { param: 'value' },
324
+ });
325
+ ```
217
326
 
218
- #### `withPaginationDisabled(callback)`
327
+ ## Error Handling
328
+
329
+ ```typescript
330
+ import {
331
+ QuickbaseError,
332
+ RateLimitError,
333
+ AuthenticationError,
334
+ AuthorizationError,
335
+ NotFoundError,
336
+ ValidationError,
337
+ ServerError,
338
+ } from 'quickbase-js';
339
+
340
+ try {
341
+ await client.getApp({ appId: 'invalid' });
342
+ } catch (error) {
343
+ if (error instanceof RateLimitError) {
344
+ console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
345
+ console.log(`Ray ID: ${error.rayId}`);
346
+ } else if (error instanceof AuthenticationError) {
347
+ console.log('Invalid or expired token');
348
+ } else if (error instanceof AuthorizationError) {
349
+ console.log('Permission denied');
350
+ } else if (error instanceof NotFoundError) {
351
+ console.log('Resource not found');
352
+ } else if (error instanceof ValidationError) {
353
+ console.log('Bad request:', error.message);
354
+ } else if (error instanceof ServerError) {
355
+ console.log('Server error:', error.statusCode);
356
+ } else if (error instanceof QuickbaseError) {
357
+ console.log(`API error ${error.statusCode}: ${error.message}`);
358
+ }
359
+ }
360
+ ```
219
361
 
220
- - **Description**: Executes an asynchronous callback with pagination temporarily disabled, restoring the original `autoPaginate` setting afterward. Useful for fetching only the initial page of results without modifying method signatures or global settings.
221
- - **Parameters**:
222
- - `callback`: `() => Promise<T>` - An async function containing the API call(s) to execute without pagination.
223
- - **Returns**: `Promise<T>` - The result of the callback.
224
- - **Example**:
362
+ ## Migration from v1
225
363
 
226
- ```javascript
227
- import { quickbase } from "quickbase-js"; // Adjust the import path as needed
364
+ ### Authentication
228
365
 
229
- const QB_REALM = ""; // Your QuickBase realm (e.g., 'mycompany')
230
- const QB_USER_TOKEN = ""; // Your QuickBase user token (e.g., 'b12345_abcde...')
231
- const QB_TABLE_ID = ""; // Your table ID (e.g., 'bxyz789')
366
+ ```typescript
367
+ // v1 - user token
368
+ const qb = quickbase({ realm: 'company', userToken: 'token' });
232
369
 
233
- const qb = quickbase({
234
- realm: QB_REALM,
235
- userToken: QB_USER_TOKEN,
236
- autoPaginate: true, // Pagination enabled by default
370
+ // v2 - user token (explicit type)
371
+ const client = createClient({
372
+ realm: 'company',
373
+ auth: { type: 'user-token', userToken: 'token' },
237
374
  });
238
375
 
239
- const runLimitedQuery = async () => {
240
- try {
241
- const result = await qb.withPaginationDisabled(async () => {
242
- return qb.runQuery({
243
- body: {
244
- from: QB_TABLE_ID,
245
- select: [3], // Example field ID
246
- options: { top: 2 }, // Fetch only 2 records
247
- },
248
- });
249
- });
250
- console.log("Fetched records:", result.data.length); // Outputs: 2
251
- } catch (error) {
252
- console.error("Error running query:", error.message);
253
- }
254
- };
376
+ // v1 - temp tokens in Code Pages
377
+ const qb = quickbase({ realm: 'company', useTempTokens: true });
255
378
 
256
- runLimitedQuery();
379
+ // v2 - temp tokens in Code Pages
380
+ const client = createClient({
381
+ realm: 'company',
382
+ auth: { type: 'temp-token' },
383
+ });
257
384
  ```
258
385
 
259
- #### `withPaginationLimit(limit, callback)`
260
-
261
- - **Description**: Executes an asynchronous callback with pagination enabled but limited to a specified number of records, restoring the original `autoPaginate` setting afterward. Useful for fetching a precise number of records (e.g., 100) from a larger dataset, stopping pagination once the limit is reached, without modifying method signatures or global settings.
262
- - **Parameters**:
263
- - `limit`: `number` - The maximum number of records to fetch across all pages.
264
- - `callback`: `() => Promise<T>` - An async function containing the API call(s) to execute with the pagination limit.
265
- - **Returns**: `Promise<T>` - The result of the callback, containing up to `limit` records.
266
- - **Example**:
386
+ ### Pagination
267
387
 
268
- ```javascript
269
- import { quickbase } from "quickbase-js"; // Adjust the import path as needed
388
+ ```typescript
389
+ // v1 - callback-based
390
+ await qb.withPaginationDisabled(async () => qb.runQuery({ body: { from: tableId } }));
391
+ await qb.withPaginationLimit(100, async () => qb.runQuery({ body: { from: tableId } }));
270
392
 
271
- const QB_REALM = ""; // Your QuickBase realm (e.g., 'mycompany')
272
- const QB_USER_TOKEN = ""; // Your QuickBase user token (e.g., 'b12345_abcde...')
273
- const QB_TABLE_ID = ""; // Your table ID (e.g., 'bxyz789')
393
+ // v2 - fluent API
394
+ await client.runQuery({ from: tableId }).noPaginate();
395
+ await client.runQuery({ from: tableId }).paginate({ limit: 100 });
396
+ ```
274
397
 
275
- const qb = quickbase({
276
- realm: QB_REALM,
277
- userToken: QB_USER_TOKEN,
278
- autoPaginate: true, // Pagination enabled by default
279
- });
398
+ ### Request Body
280
399
 
281
- const runCappedQuery = async () => {
282
- try {
283
- const result = await qb.withPaginationLimit(100, async () => {
284
- return qb.runQuery({
285
- body: {
286
- from: QB_TABLE_ID,
287
- select: [3], // Example field ID
288
- options: { top: 25 }, // Fetch 25 records per page
289
- },
290
- });
291
- });
292
- console.log("Fetched records:", result.data.length); // Outputs: 100
293
- } catch (error) {
294
- console.error("Error running query:", error.message);
295
- }
296
- };
400
+ ```typescript
401
+ // v1 - body wrapper
402
+ await qb.runQuery({ body: { from: tableId, select: [3, 6] } });
297
403
 
298
- runCappedQuery();
404
+ // v2 - direct parameters
405
+ await client.runQuery({ from: tableId, select: [3, 6] });
299
406
  ```
300
407
 
301
- ---
302
-
303
- ### Development workflow
408
+ ## Development
304
409
 
305
410
  ```bash
306
- npm run gen:all
411
+ # Install dependencies
412
+ npm install
413
+
414
+ # Run tests
415
+ npm test
416
+
417
+ # Build
307
418
  npm run build
308
- npm run test:all
309
- ```
310
419
 
311
- ---
420
+ # Type check
421
+ npm run typecheck
312
422
 
313
- ### Prerequisites
423
+ # Generate types from OpenAPI spec
424
+ npm run spec:generate
425
+ ```
314
426
 
315
- - Node.js version >= 18
316
- - A Quickbase account. [Free tier available](https://www.quickbase.com/builder-program).
427
+ ### Spec Tools
317
428
 
318
- ---
429
+ ```bash
430
+ # Full spec processing pipeline
431
+ npm run spec:build
432
+
433
+ # Individual steps
434
+ npm run spec:convert # Swagger 2.0 → OpenAPI 3.0
435
+ npm run spec:patch # Apply fixes from overrides
436
+ npm run spec:validate # Validate spec
437
+ npm run spec:split # Split by tag (for editing)
438
+ npm run spec:generate # Generate TypeScript types
439
+ ```
319
440
 
320
- ### Contributing
441
+ ### Documentation
321
442
 
322
- If you would like to contribute to this project, please fork the repository and submit a pull request.
443
+ Generate API documentation from source code:
323
444
 
324
- ---
445
+ ```bash
446
+ npm run docs # Generate docs to ./docs
447
+ npm run docs:watch # Watch mode for development
448
+ ```
325
449
 
326
- ### License
450
+ The documentation is generated using [TypeDoc](https://typedoc.org/) and extracts JSDoc comments from the source code. Open `docs/index.html` to view locally.
327
451
 
328
- MIT License - see LICENSE for details.
452
+ ## License
329
453
 
330
- ---
454
+ MIT