quickbase-js 0.1.0-beta.9 → 1.0.0

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 (146) hide show
  1. package/README.md +270 -60
  2. package/dist/esm/quickbase.d.ts +2553 -3220
  3. package/dist/esm/quickbase.js +1545 -3443
  4. package/dist/esm/quickbase.js.map +1 -1
  5. package/dist/esm/quickbase.min.js +1 -1
  6. package/dist/esm/quickbase.min.js.map +1 -1
  7. package/dist/umd/quickbase.umd.js +1544 -3625
  8. package/dist/umd/quickbase.umd.js.map +1 -1
  9. package/dist/umd/quickbase.umd.min.js +1 -1
  10. package/dist/umd/quickbase.umd.min.js.map +1 -1
  11. package/package.json +25 -12
  12. package/CHANGELOG.md +0 -184
  13. package/build-common.js +0 -131
  14. package/build-esm.js +0 -71
  15. package/build-umd.js +0 -69
  16. package/examples/quicbase-jsCDN.html +0 -36
  17. package/examples/react.js +0 -48
  18. package/examples/vanillajs.html +0 -47
  19. package/open-api/fix-spec-main.ts +0 -97
  20. package/open-api/generate-override-report.ts +0 -214
  21. package/open-api/generate-unified-interface.ts +0 -336
  22. package/open-api/output/override-report.html +0 -11
  23. package/open-api/output/override-report.json +0 -14395
  24. package/open-api/output/quickbase-fixed.json +0 -11191
  25. package/open-api/regenerate-client.ts +0 -116
  26. package/open-api/schema/enhance-general.ts +0 -100
  27. package/open-api/schema/fix-arrays.ts +0 -69
  28. package/open-api/schema/tags/apps.ts +0 -90
  29. package/open-api/schema/tags/fields.ts +0 -471
  30. package/open-api/schema/tags/groups.ts +0 -51
  31. package/open-api/schema/tags/index.ts +0 -66
  32. package/open-api/schema/tags/records.ts +0 -115
  33. package/open-api/schema/tags/tables.ts +0 -211
  34. package/open-api/schema/tags/users.ts +0 -47
  35. package/open-api/types/spec.ts +0 -42
  36. package/open-api/utils/generateJsDoc.ts +0 -96
  37. package/open-api/utils/infer-schema.ts +0 -40
  38. package/open-api/utils/naming.ts +0 -10
  39. package/playwright.config.ts +0 -37
  40. package/rollup.config.js +0 -114
  41. package/specs/QuickBase_RESTful_API_2025-03-04T06_22_39.725Z.json +0 -46878
  42. package/specs/split/apps.json +0 -1315
  43. package/specs/split/auth.json +0 -191
  44. package/specs/split/fields.json +0 -3869
  45. package/specs/split/records.json +0 -754
  46. package/specs/split/reports.json +0 -619
  47. package/specs/split/tables.json +0 -1605
  48. package/src/RateLimitError.ts +0 -12
  49. package/src/ThrottleBucket.ts +0 -41
  50. package/src/authorizationStrategy.ts +0 -246
  51. package/src/generated-unified/QuickbaseClient.ts +0 -1049
  52. package/src/generated-unified/missing-types-report.json +0 -3
  53. package/src/index.ts +0 -1
  54. package/src/invokeMethod.ts +0 -242
  55. package/src/quickbaseClient.ts +0 -271
  56. package/src/rateLimiter.ts +0 -25
  57. package/src/tokenCache.ts +0 -35
  58. package/src/utils.ts +0 -7
  59. package/test-esm.js +0 -1
  60. package/test-results.json +0 -2050
  61. package/test-umd.js +0 -1
  62. package/test.ts +0 -1
  63. package/tests/playwright/qb/auth/cacheSwitching.test.ts +0 -159
  64. package/tests/playwright/qb/auth/fetchTempToken401.test.ts +0 -219
  65. package/tests/playwright/qb/auth/getAppWithTempToken.test.ts +0 -162
  66. package/tests/playwright/qb/auth/getAppWithUserToken.test.ts +0 -153
  67. package/tests/playwright/qb/auth/getTempToken.test.ts +0 -152
  68. package/tests/playwright/qb/auth/tempTokenPrefetch.test.ts +0 -179
  69. package/tests/playwright/qb/auth/tempTokenRenewal.test.ts +0 -133
  70. package/tests/setup.ts +0 -53
  71. package/tests/vitest/qb/apps/copyApp.test.ts +0 -76
  72. package/tests/vitest/qb/apps/createApp.test.ts +0 -64
  73. package/tests/vitest/qb/apps/deleteApp.test.ts +0 -76
  74. package/tests/vitest/qb/apps/getApp.test.ts +0 -44
  75. package/tests/vitest/qb/apps/getAppEvents.test.ts +0 -67
  76. package/tests/vitest/qb/apps/updateApp.test.ts +0 -58
  77. package/tests/vitest/qb/auth/mockQuickbaseServer.ts +0 -60
  78. package/tests/vitest/qb/auth/retryUserToken401.test.ts +0 -73
  79. package/tests/vitest/qb/auth/ssoTokenIntegrationWithServer.test.ts +0 -65
  80. package/tests/vitest/qb/fields/createField.test.ts +0 -77
  81. package/tests/vitest/qb/fields/deleteFields.test.ts +0 -83
  82. package/tests/vitest/qb/fields/getField.test.ts +0 -85
  83. package/tests/vitest/qb/fields/getFieldUsage.test.ts +0 -82
  84. package/tests/vitest/qb/fields/getFields.test.ts +0 -232
  85. package/tests/vitest/qb/fields/getFieldsUsage.test.ts +0 -77
  86. package/tests/vitest/qb/fields/updateField.test.ts +0 -93
  87. package/tests/vitest/qb/formulas/runFormula.test.ts +0 -96
  88. package/tests/vitest/qb/index.ts +0 -29
  89. package/tests/vitest/qb/records/deleteRecords.test.ts +0 -110
  90. package/tests/vitest/qb/records/runQuery.test.ts +0 -146
  91. package/tests/vitest/qb/records/upsert.test.ts +0 -102
  92. package/tests/vitest/qb/tables/createRelationship.test.ts +0 -102
  93. package/tests/vitest/qb/tables/createTable.test.ts +0 -55
  94. package/tests/vitest/qb/tables/deleteRelationship.test.ts +0 -143
  95. package/tests/vitest/qb/tables/deleteTable.test.ts +0 -50
  96. package/tests/vitest/qb/tables/getAppTables.test.ts +0 -46
  97. package/tests/vitest/qb/tables/getRelationships.test.ts +0 -80
  98. package/tests/vitest/qb/tables/getTable.test.ts +0 -26
  99. package/tests/vitest/qb/tables/updateRelationship.test.ts +0 -250
  100. package/tests/vitest/qb/tables/updateTable.test.ts +0 -48
  101. package/tests/vitest/unit/ThrottleBucket.test.ts +0 -95
  102. package/tests/vitest/unit/apps/copyApp.test.ts +0 -581
  103. package/tests/vitest/unit/apps/createApp.test.ts +0 -186
  104. package/tests/vitest/unit/apps/deleteApp.test.ts +0 -216
  105. package/tests/vitest/unit/apps/getApp.test.ts +0 -128
  106. package/tests/vitest/unit/apps/getAppEvents.test.ts +0 -193
  107. package/tests/vitest/unit/apps/updateApp.test.ts +0 -412
  108. package/tests/vitest/unit/auth/fetchTempToken401.test.ts +0 -63
  109. package/tests/vitest/unit/auth/getTempToken.test.ts +0 -119
  110. package/tests/vitest/unit/auth/retryTempToken401.test.ts +0 -95
  111. package/tests/vitest/unit/auth/retryTempTokenMaxRetries.test.ts +0 -235
  112. package/tests/vitest/unit/auth/retryUserToken401.test.ts +0 -69
  113. package/tests/vitest/unit/auth/ssoTokenRefresh.test.ts +0 -325
  114. package/tests/vitest/unit/fields/createField.test.ts +0 -451
  115. package/tests/vitest/unit/fields/deleteFields.test.ts +0 -141
  116. package/tests/vitest/unit/fields/getField.test.ts +0 -189
  117. package/tests/vitest/unit/fields/getFieldUsage.test.ts +0 -180
  118. package/tests/vitest/unit/fields/getFields.test.ts +0 -122
  119. package/tests/vitest/unit/fields/getFieldsUsage.test.ts +0 -160
  120. package/tests/vitest/unit/fields/updateField.test.ts +0 -285
  121. package/tests/vitest/unit/formulas/runFormula.test.ts +0 -205
  122. package/tests/vitest/unit/index.ts +0 -34
  123. package/tests/vitest/unit/inferHttpMethod.test.ts +0 -131
  124. package/tests/vitest/unit/rateLimit.test.ts +0 -191
  125. package/tests/vitest/unit/records/deleteRecords.test.ts +0 -112
  126. package/tests/vitest/unit/records/runQuery.test.ts +0 -102
  127. package/tests/vitest/unit/records/upsert.test.ts +0 -234
  128. package/tests/vitest/unit/tables/createRelationship.test.ts +0 -212
  129. package/tests/vitest/unit/tables/createTable.test.ts +0 -70
  130. package/tests/vitest/unit/tables/deleteRelationship.test.ts +0 -97
  131. package/tests/vitest/unit/tables/deleteTable.test.ts +0 -77
  132. package/tests/vitest/unit/tables/getAppTables.test.ts +0 -85
  133. package/tests/vitest/unit/tables/getRelationships.test.ts +0 -259
  134. package/tests/vitest/unit/tables/getTable.test.ts +0 -233
  135. package/tests/vitest/unit/tables/updateRelationship.test.ts +0 -307
  136. package/tests/vitest/unit/tables/updateTable.test.ts +0 -80
  137. package/tests/vitest/unit/tokenLifespan.test.ts +0 -204
  138. package/tests/vitest/unit/umd.test.ts +0 -8
  139. package/text.txt +0 -104
  140. package/tools/log-gen.ts +0 -244
  141. package/tools/log-gen.yaml +0 -5424
  142. package/tools/openapi-jars/openapi-generator-cli-7.12.0.jar +0 -0
  143. package/tsconfig.build.json +0 -17
  144. package/tsconfig.json +0 -32
  145. package/versionrc.json +0 -9
  146. package/vitest.config.ts +0 -27
@@ -1,3 +0,0 @@
1
- {
2
- "missingTypes": []
3
- }
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./quickbaseClient.ts";
@@ -1,242 +0,0 @@
1
- // src/invokeMethod.ts
2
-
3
- import { AuthorizationStrategy, extractDbid } from "./authorizationStrategy";
4
- import { RateLimiter } from "./rateLimiter";
5
- import { RateLimitError } from "./RateLimitError";
6
- import { ResponseError } from "./generated/runtime";
7
- import { QuickbaseClient } from "./quickbaseClient";
8
- import { GetTempTokenDBID200Response } from "./generated/models";
9
-
10
- export type ApiMethod<K extends keyof QuickbaseClient> = (
11
- requestParameters: Parameters<QuickbaseClient[K]>[0],
12
- initOverrides?: RequestInit
13
- ) => Promise<ReturnType<QuickbaseClient[K]>>;
14
-
15
- export interface MethodInfo<K extends keyof QuickbaseClient> {
16
- api: any;
17
- method: ApiMethod<K>;
18
- paramMap: string[];
19
- httpMethod: string;
20
- }
21
-
22
- export async function invokeMethod<K extends keyof QuickbaseClient>(
23
- methodName: K,
24
- params: Parameters<QuickbaseClient[K]>[0] & {
25
- dbid?: string;
26
- tableId?: string;
27
- appId?: string;
28
- },
29
- methodMap: { [P in keyof QuickbaseClient]: MethodInfo<P> },
30
- baseHeaders: Record<string, string>,
31
- authStrategy: AuthorizationStrategy,
32
- rateLimiter: RateLimiter,
33
- fetchTempToken: (dbid: string) => Promise<string>,
34
- transformDates: (obj: any, convertStringsToDates: boolean) => any,
35
- debug: boolean | undefined,
36
- convertDates: boolean
37
- ): Promise<ReturnType<QuickbaseClient[K]>> {
38
- console.log("[invokeMethod] Starting for method:", methodName);
39
-
40
- const methodInfo = methodMap[methodName];
41
- if (!methodInfo) throw new Error(`Method ${methodName} not found`);
42
-
43
- const hasBody = "body" in params && params.body !== undefined;
44
- const body = hasBody ? params.body : undefined;
45
- const restParams: any = hasBody
46
- ? Object.fromEntries(
47
- Object.entries(params).filter(([key]) => key !== "body")
48
- )
49
- : { ...params };
50
- const requestParameters: any = {
51
- ...restParams,
52
- ...(hasBody ? { generated: body } : {}),
53
- };
54
-
55
- const requestOptions: RequestInit = {
56
- credentials: methodName === "getTempTokenDBID" ? "include" : "omit",
57
- method: methodInfo.httpMethod,
58
- };
59
-
60
- let dbid: string | undefined = extractDbid(params);
61
- console.log("[invokeMethod] Extracted dbid:", dbid);
62
-
63
- let token = dbid
64
- ? await authStrategy.getToken(dbid)
65
- : await authStrategy.getToken("");
66
- console.log("[invokeMethod] Initial token:", token);
67
-
68
- if (!token && dbid) {
69
- token = await fetchTempToken(dbid);
70
- authStrategy.applyHeaders(baseHeaders, token);
71
- requestOptions.headers = { ...baseHeaders };
72
- console.log("[invokeMethod] Fetched new token:", token);
73
- }
74
-
75
- if (token) {
76
- authStrategy.applyHeaders(baseHeaders, token);
77
- requestOptions.headers = { ...baseHeaders };
78
- console.log(
79
- "[invokeMethod] Token found, headers set:",
80
- requestOptions.headers
81
- );
82
- if (methodName === "getTempTokenDBID") {
83
- console.log("[invokeMethod] Using cached token:", token);
84
- return { temporaryAuthorization: token } as ReturnType<
85
- QuickbaseClient[K]
86
- >;
87
- }
88
- }
89
-
90
- if (debug) {
91
- console.log(`[${methodName}] requestParameters:`, requestParameters);
92
- console.log(`[${methodName}] requestOptions:`, requestOptions);
93
- }
94
-
95
- async function processResponse(
96
- rawResponse: any
97
- ): Promise<ReturnType<QuickbaseClient[K]>> {
98
- if (debug) console.log(`[${methodName}] rawResponse:`, rawResponse);
99
- if (rawResponse instanceof Response) {
100
- const contentType = rawResponse.headers
101
- .get("Content-Type")
102
- ?.toLowerCase();
103
- if (debug) console.log(`[${methodName}] contentType:`, contentType);
104
- if (contentType?.includes("application/json")) {
105
- const jsonResponse = await rawResponse.json();
106
- return transformDates(jsonResponse, convertDates) as ReturnType<
107
- QuickbaseClient[K]
108
- >;
109
- }
110
- return rawResponse as ReturnType<QuickbaseClient[K]>;
111
- }
112
- if (rawResponse && typeof rawResponse.value === "function") {
113
- const response = await rawResponse.value();
114
- if (debug)
115
- console.log(`[${methodName}] Resolved JSONApiResponse:`, response);
116
- return transformDates(response, convertDates) as ReturnType<
117
- QuickbaseClient[K]
118
- >;
119
- }
120
- return transformDates(rawResponse, convertDates) as ReturnType<
121
- QuickbaseClient[K]
122
- >;
123
- }
124
-
125
- async function parseErrorResponse(
126
- response: Response
127
- ): Promise<{ message: string; status: number }> {
128
- let message = "Unknown error";
129
- let status = response.status || 500;
130
- try {
131
- const contentType =
132
- response.headers?.get("Content-Type")?.toLowerCase() ||
133
- "application/json";
134
- if (
135
- contentType.includes("application/json") &&
136
- typeof response.json === "function"
137
- ) {
138
- const errorBody = await response.json();
139
- if (
140
- errorBody &&
141
- typeof errorBody === "object" &&
142
- "message" in errorBody
143
- ) {
144
- message = errorBody.message;
145
- } else {
146
- message = "Invalid error response format";
147
- }
148
- } else if (typeof response.text === "function") {
149
- message = (await response.text()) || message;
150
- }
151
- } catch (e) {
152
- if (debug) console.log(`[${methodName}] Error parsing response body:`, e);
153
- message = "Failed to parse error response";
154
- }
155
- console.log(
156
- "[invokeMethod] Parsed error - status:",
157
- status,
158
- "message:",
159
- message
160
- );
161
- return { message, status };
162
- }
163
-
164
- let attempt = 0;
165
- const maxAttempts = rateLimiter.maxRetries + 1;
166
-
167
- while (attempt < maxAttempts) {
168
- console.log("[invokeMethod] Attempt:", attempt + 1, "of", maxAttempts);
169
- try {
170
- await rateLimiter.throttle();
171
- console.log("[invokeMethod] About to call API for method:", methodName);
172
- const response = await methodInfo.method(
173
- requestParameters,
174
- requestOptions
175
- );
176
- console.log("[invokeMethod] API call completed for method:", methodName);
177
- return await processResponse(response);
178
- } catch (error: unknown) {
179
- let status: number;
180
- let message: string;
181
- let response: Response;
182
-
183
- console.log("[invokeMethod] Caught error:", error);
184
-
185
- if (error instanceof ResponseError && error.response) {
186
- response = error.response;
187
- ({ message, status } = await parseErrorResponse(response));
188
- } else if (error instanceof Response) {
189
- response = error;
190
- ({ message, status } = await parseErrorResponse(response));
191
- } else {
192
- if (debug) console.log(`[${methodName}] Unexpected error:`, error);
193
- throw error; // Rethrow non-response errors
194
- }
195
-
196
- console.log("[invokeMethod] Handling error with status:", status);
197
-
198
- if (status === 429) {
199
- if (!(error instanceof ResponseError)) {
200
- throw new Error("Expected ResponseError for 429 handling"); // Shouldn't happen
201
- }
202
- const delay = await rateLimiter.handle429(error, attempt + 1);
203
- if (debug) console.log(`[${methodName}] 429 delay: ${delay}ms`);
204
- if (attempt + 1 === maxAttempts) {
205
- throw new RateLimitError(
206
- `API Error: ${message} (Status: ${status})`,
207
- status,
208
- response.headers.get("Retry-After")
209
- ? parseInt(response.headers.get("Retry-After")!, 10)
210
- : undefined
211
- );
212
- }
213
- await new Promise((resolve) => setTimeout(resolve, delay));
214
- attempt++;
215
- continue;
216
- }
217
-
218
- const newToken = await authStrategy.handleError(
219
- status,
220
- params,
221
- fetchTempToken,
222
- attempt,
223
- maxAttempts,
224
- debug,
225
- methodName
226
- );
227
- if (newToken) {
228
- token = newToken;
229
- authStrategy.applyHeaders(baseHeaders, token);
230
- requestOptions.headers = { ...baseHeaders };
231
- attempt++;
232
- if (debug)
233
- console.log(
234
- `[${methodName}] Retrying with token: ${token.substring(0, 10)}...`
235
- );
236
- continue;
237
- }
238
- throw new Error(`API Error: ${message} (Status: ${status})`);
239
- }
240
- }
241
- throw new Error(`API Error: Exhausted retries after ${maxAttempts} attempts`);
242
- }
@@ -1,271 +0,0 @@
1
- // src/quickbaseClient.ts
2
-
3
- import { QuickbaseClient as IQuickbaseClient } from "./generated-unified/QuickbaseClient";
4
- import { Configuration, HTTPHeaders } from "./generated/runtime";
5
- import * as apis from "./generated/apis";
6
- import { TokenCache } from "./tokenCache";
7
- import { simplifyName } from "./utils";
8
- import { invokeMethod, MethodInfo } from "./invokeMethod";
9
- import {
10
- TempTokenStrategy,
11
- UserTokenStrategy,
12
- AuthorizationStrategy,
13
- SsoTokenStrategy,
14
- } from "./authorizationStrategy";
15
- import { ThrottleBucket } from "./ThrottleBucket";
16
- import { RateLimiter } from "./rateLimiter";
17
-
18
- export * from "./generated/models/index";
19
-
20
- export interface QuickbaseClient extends IQuickbaseClient {}
21
-
22
- export interface QuickbaseConfig {
23
- realm: string;
24
- userToken?: string;
25
- tempToken?: string;
26
- useTempTokens?: boolean;
27
- useSso?: boolean;
28
- samlToken?: string;
29
- debug?: boolean;
30
- fetchApi?: typeof fetch;
31
- convertDates?: boolean;
32
- tempTokenLifespan?: number;
33
- throttle?: { rate: number; burst: number };
34
- maxRetries?: number;
35
- retryDelay?: number;
36
- tokenCache?: TokenCache;
37
- baseUrl?: string;
38
- }
39
-
40
- type MethodMap = {
41
- [K in keyof QuickbaseClient]: MethodInfo<K>;
42
- };
43
-
44
- const getParamNames = (fn: (...args: any[]) => any): string[] =>
45
- fn
46
- .toString()
47
- .slice(fn.toString().indexOf("(") + 1, fn.toString().indexOf(")"))
48
- .split(",")
49
- .map((p) => p.trim().split("=")[0]?.trim())
50
- .filter((p) => p && !p.match(/^\{/) && p !== "options");
51
-
52
- function transformDates(obj: any, convertStringsToDates: boolean = true): any {
53
- if (obj === null || obj === undefined) return obj;
54
- if (obj instanceof Date) return obj;
55
- if (
56
- convertStringsToDates &&
57
- typeof obj === "string" &&
58
- /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?/.test(
59
- obj
60
- )
61
- ) {
62
- return new Date(obj);
63
- }
64
- if (Array.isArray(obj)) {
65
- return obj.map((item) => transformDates(item, convertStringsToDates));
66
- }
67
- if (typeof obj === "object") {
68
- return Object.fromEntries(
69
- Object.entries(obj).map(([key, value]) => [
70
- key,
71
- transformDates(value, convertStringsToDates),
72
- ])
73
- );
74
- }
75
- return obj;
76
- }
77
-
78
- function inferHttpMethod(methodSource: string, debug?: boolean): string {
79
- const methodMatches = [
80
- ...methodSource.matchAll(/method:\s*['"]?(\w+)['"]?/gi),
81
- ];
82
- const method =
83
- methodMatches.length > 0
84
- ? methodMatches[methodMatches.length - 1][1].toUpperCase()
85
- : "GET";
86
- if (debug) {
87
- console.log(`[inferHttpMethod] Source:`, methodSource);
88
- console.log(
89
- `[inferHttpMethod] All matches:`,
90
- methodMatches.map((m) => m[0])
91
- );
92
- console.log(`[inferHttpMethod] Extracted method:`, method);
93
- }
94
- return method;
95
- }
96
-
97
- export function quickbase(config: QuickbaseConfig): QuickbaseClient {
98
- const {
99
- realm,
100
- userToken,
101
- tempToken,
102
- useTempTokens,
103
- useSso,
104
- samlToken,
105
- fetchApi,
106
- debug,
107
- convertDates = true,
108
- tempTokenLifespan = 290000,
109
- throttle = { rate: 10, burst: 10 },
110
- maxRetries = 3,
111
- retryDelay = 1000,
112
- tokenCache: providedTokenCache,
113
- baseUrl = "https://api.quickbase.com/v1",
114
- } = config;
115
-
116
- const tokenCache = providedTokenCache || new TokenCache(tempTokenLifespan);
117
- const throttleBucket = throttle
118
- ? new ThrottleBucket(throttle.rate, throttle.burst)
119
- : null;
120
- const rateLimiter = new RateLimiter(throttleBucket, maxRetries, retryDelay);
121
-
122
- const defaultFetch: typeof fetch | undefined =
123
- typeof globalThis.window !== "undefined"
124
- ? globalThis.window.fetch.bind(globalThis.window)
125
- : undefined;
126
- const effectiveFetch = fetchApi || defaultFetch;
127
-
128
- if (!effectiveFetch) {
129
- throw new Error("No fetch implementation available");
130
- }
131
-
132
- const authStrategy: AuthorizationStrategy = useSso
133
- ? new SsoTokenStrategy(samlToken || "", realm, effectiveFetch, debug)
134
- : useTempTokens
135
- ? new TempTokenStrategy(tokenCache, tempToken)
136
- : new UserTokenStrategy(userToken || "");
137
-
138
- const baseHeaders: HTTPHeaders = {
139
- "QB-Realm-Hostname": `${realm}.quickbase.com`,
140
- "Content-Type": "application/json",
141
- };
142
-
143
- const configuration = new Configuration({
144
- basePath: baseUrl,
145
- headers: { ...baseHeaders },
146
- fetchApi: effectiveFetch,
147
- credentials: "omit",
148
- });
149
-
150
- // Removed redundant check:
151
- // if (!configuration.fetchApi && typeof globalThis.window === "undefined") {
152
- // throw new Error("fetchApi must be provided in non-browser environments (e.g., Node.js)");
153
- // }
154
-
155
- const apiInstances = Object.fromEntries(
156
- Object.entries(apis)
157
- .filter(([name]) => name.endsWith("Api"))
158
- .map(([name, ApiClass]) => [
159
- name.replace("Api", "").toLowerCase(),
160
- new ApiClass(configuration),
161
- ])
162
- );
163
-
164
- function buildMethodMap(): MethodMap {
165
- const methodMap: Partial<MethodMap> = {};
166
- const isValidMethod = (name: string) =>
167
- !name.startsWith("_") &&
168
- name !== "constructor" &&
169
- !["Middleware", "Pre", "Post", "Raw"].some((s) => name.includes(s));
170
-
171
- for (const [apiName, api] of Object.entries(apiInstances)) {
172
- Object.getOwnPropertyNames(Object.getPrototypeOf(api))
173
- .filter(
174
- (name) =>
175
- isValidMethod(name) &&
176
- typeof api[name as keyof typeof api] === "function"
177
- )
178
- .forEach((rawMethodName) => {
179
- const simplifiedName = simplifyName(
180
- rawMethodName
181
- ) as keyof QuickbaseClient;
182
- const rawMethodKey = `${rawMethodName}Raw` as keyof typeof api;
183
- const method =
184
- api[rawMethodKey] || api[rawMethodName as keyof typeof api];
185
- const boundMethod = method.bind(api as any) as unknown;
186
- if (typeof boundMethod === "function" && boundMethod.length <= 2) {
187
- const methodSource = method.toString();
188
- methodMap[simplifiedName] = {
189
- api,
190
- method: boundMethod as any,
191
- paramMap: getParamNames(method),
192
- httpMethod: inferHttpMethod(methodSource, debug),
193
- };
194
- }
195
- });
196
- }
197
- if (debug) {
198
- console.log("[buildMethodMap] Methods:", Object.keys(methodMap));
199
- }
200
- return methodMap as MethodMap;
201
- }
202
-
203
- const methodMap = buildMethodMap();
204
-
205
- const fetchTempToken = async (dbid: string): Promise<string> => {
206
- const response = await effectiveFetch(`${baseUrl}/auth/temporary/${dbid}`, {
207
- method: "GET",
208
- headers: { ...baseHeaders },
209
- credentials: "include",
210
- });
211
-
212
- if (!response.ok) {
213
- const errorBody: { message?: string } = await response.json();
214
- throw new Error(
215
- `API Error: ${errorBody.message || "Unknown error"} (Status: ${
216
- response.status
217
- })`
218
- );
219
- }
220
-
221
- const tokenResult = await response.json();
222
- console.log(`[fetchTempToken] Response:`, tokenResult);
223
- const token = tokenResult.temporaryAuthorization;
224
- if (!token) {
225
- throw new Error("No temporary token returned from API");
226
- }
227
- tokenCache.set(dbid, token, tempTokenLifespan);
228
- if (debug) {
229
- console.log(`Fetched and cached new token for dbid: ${dbid}`, token);
230
- }
231
- return token;
232
- };
233
-
234
- const proxyHandler: ProxyHandler<QuickbaseClient> = {
235
- get: (_, prop: string) => {
236
- console.log(
237
- "[proxy] Accessing:",
238
- prop,
239
- "in methodMap:",
240
- prop in methodMap
241
- );
242
- if (prop in methodMap) {
243
- const methodName = prop as keyof QuickbaseClient;
244
- return (params: Parameters<QuickbaseClient[typeof methodName]>[0]) =>
245
- invokeMethod(
246
- methodName,
247
- params,
248
- methodMap,
249
- baseHeaders,
250
- authStrategy,
251
- rateLimiter,
252
- fetchTempToken,
253
- transformDates,
254
- debug,
255
- convertDates
256
- );
257
- }
258
- console.log("[proxy] Method not found:", prop);
259
- return undefined;
260
- },
261
- };
262
-
263
- const proxy = new Proxy<QuickbaseClient>({} as QuickbaseClient, proxyHandler);
264
-
265
- if (debug) {
266
- console.log("[createClient] Config:", config);
267
- console.log("[createClient] Proxy created:", proxy);
268
- }
269
-
270
- return proxy;
271
- }
@@ -1,25 +0,0 @@
1
- // src/rateLimiter.ts
2
- import { ThrottleBucket } from "./ThrottleBucket";
3
- import { ResponseError } from "./generated/runtime";
4
-
5
- export class RateLimiter {
6
- constructor(
7
- private throttleBucket: ThrottleBucket | null,
8
- public maxRetries: number = 3,
9
- private retryDelay: number = 1000
10
- ) {}
11
-
12
- async throttle(): Promise<void> {
13
- if (this.throttleBucket) {
14
- await this.throttleBucket.acquire();
15
- }
16
- }
17
-
18
- async handle429(error: ResponseError, attempt: number): Promise<number> {
19
- // Remove the throw here; let invokeMethod handle exhaustion
20
- const retryAfter = error.response.headers.get("Retry-After");
21
- return retryAfter
22
- ? parseInt(retryAfter, 10) * 1000
23
- : this.retryDelay * Math.pow(2, attempt - 1);
24
- }
25
- }
package/src/tokenCache.ts DELETED
@@ -1,35 +0,0 @@
1
- // src/tokenCache.ts
2
- interface CachedToken {
3
- token: string;
4
- expiresAt: number;
5
- }
6
-
7
- export class TokenCache {
8
- private cache: Map<string, CachedToken>;
9
- private readonly tempTokenLifespan: number;
10
-
11
- constructor(tempTokenLifespan: number = 4 * 60 * 1000 + 50 * 1000) {
12
- this.cache = new Map<string, CachedToken>();
13
- this.tempTokenLifespan = tempTokenLifespan;
14
- }
15
-
16
- get(dbid: string): string | undefined {
17
- const entry = this.cache.get(dbid);
18
- const now = Date.now();
19
- if (entry && entry.expiresAt > now) return entry.token;
20
- if (entry) this.cache.delete(dbid); // Clean up expired temp tokens
21
- return undefined;
22
- }
23
-
24
- set(dbid: string, token: string, lifespan?: number): void {
25
- const now = Date.now();
26
- this.cache.set(dbid, {
27
- token,
28
- expiresAt: now + (lifespan || this.tempTokenLifespan),
29
- });
30
- }
31
-
32
- clear(): void {
33
- this.cache.clear();
34
- }
35
- }
package/src/utils.ts DELETED
@@ -1,7 +0,0 @@
1
- // src/utils.ts
2
- export function simplifyName(name: string): string {
3
- return name
4
- .replace(/ById$/, "")
5
- .replace(/Api$/, "")
6
- .replace(/^(\w)/, (_, c) => c.toLowerCase());
7
- }
package/test-esm.js DELETED
@@ -1 +0,0 @@
1
- import { quickbase } from './dist/esm/quickbase.js'; const qb = quickbase({ realm: 'example', userToken: 'your-token' }); console.log(qb);