quickbase-js 2.3.0 → 2.4.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.
- package/README.md +145 -1107
- package/dist/auth/ticket.d.ts.map +1 -1
- package/dist/auth/ticket.js +4 -3
- package/dist/auth/ticket.js.map +1 -1
- package/dist/client/request.d.ts +4 -0
- package/dist/client/request.d.ts.map +1 -1
- package/dist/client/request.js +15 -3
- package/dist/client/request.js.map +1 -1
- package/dist/generated/client.d.ts +2 -0
- package/dist/generated/client.d.ts.map +1 -1
- package/dist/generated/client.js +134 -113
- package/dist/generated/client.js.map +1 -1
- package/dist/generated/types.d.ts +2700 -2256
- package/dist/generated/types.d.ts.map +1 -1
- package/dist/generated/types.js +0 -2
- package/dist/generated/types.js.map +1 -1
- package/dist/quickbase.esm.js +3 -3
- package/dist/quickbase.esm.js.map +3 -3
- package/dist/quickbase.min.js +3 -3
- package/dist/quickbase.min.js.map +3 -3
- package/package.json +16 -13
- package/src/auth/index.ts +55 -0
- package/src/auth/sso-token.ts +143 -0
- package/src/auth/temp-token.ts +160 -0
- package/src/auth/ticket.ts +329 -0
- package/src/auth/token-cache.ts +97 -0
- package/src/auth/types.ts +50 -0
- package/src/auth/user-token.ts +38 -0
- package/src/cli/schema.ts +512 -0
- package/src/client/index.ts +36 -0
- package/src/client/pagination.ts +337 -0
- package/src/client/request.ts +544 -0
- package/src/client/retry.ts +169 -0
- package/src/client/throttle.ts +105 -0
- package/src/core/config.ts +160 -0
- package/src/core/dates.ts +63 -0
- package/src/core/errors.ts +349 -0
- package/src/core/index.ts +50 -0
- package/src/core/logger.ts +113 -0
- package/src/core/schema.ts +213 -0
- package/src/core/transform.ts +295 -0
- package/src/core/types.ts +337 -0
- package/src/generated/client.ts +1785 -0
- package/src/generated/operations.json +672 -0
- package/src/generated/types.ts +4884 -0
- package/src/index.ts +259 -0
- package/src/xml/codepages.ts +119 -0
- package/src/xml/dbvars.ts +75 -0
- package/src/xml/errors.ts +133 -0
- package/src/xml/fields.ts +121 -0
- package/src/xml/groups.ts +560 -0
- package/src/xml/html.ts +152 -0
- package/src/xml/index.ts +1196 -0
- package/src/xml/metadata.ts +111 -0
- package/src/xml/records.ts +301 -0
- package/src/xml/request.ts +238 -0
- package/src/xml/roles.ts +321 -0
- package/src/xml/schema.ts +436 -0
- package/src/xml/transform.ts +381 -0
- package/src/xml/types.ts +602 -0
- package/src/xml/users.ts +221 -0
- package/src/xml/webhooks.ts +260 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickBase SDK v2
|
|
3
|
+
*
|
|
4
|
+
* A TypeScript/JavaScript client for the QuickBase JSON RESTful API.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { createClient } from 'quickbase-js';
|
|
9
|
+
*
|
|
10
|
+
* const client = createClient({
|
|
11
|
+
* realm: 'mycompany',
|
|
12
|
+
* auth: {
|
|
13
|
+
* type: 'user-token',
|
|
14
|
+
* userToken: 'your-user-token',
|
|
15
|
+
* },
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const app = await client.getApp({ appId: 'bpqe82s1' });
|
|
19
|
+
* console.log(app.name);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Core exports
|
|
24
|
+
export type {
|
|
25
|
+
QuickbaseConfig,
|
|
26
|
+
AuthConfig,
|
|
27
|
+
UserTokenAuthConfig,
|
|
28
|
+
TempTokenAuthConfig,
|
|
29
|
+
SsoTokenAuthConfig,
|
|
30
|
+
TicketAuthConfig, // XML-API-TICKET: Remove if XML API discontinued
|
|
31
|
+
RateLimitConfig,
|
|
32
|
+
RetryConfig,
|
|
33
|
+
RateLimitInfo,
|
|
34
|
+
PaginationMetadata,
|
|
35
|
+
PaginatedResponse,
|
|
36
|
+
FieldInfo,
|
|
37
|
+
// Schema types
|
|
38
|
+
Schema,
|
|
39
|
+
TableSchema,
|
|
40
|
+
FieldSchema,
|
|
41
|
+
ResolvedSchema,
|
|
42
|
+
} from './core/index.js';
|
|
43
|
+
|
|
44
|
+
// Schema utilities
|
|
45
|
+
export { SchemaError } from './core/schema.js';
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
QuickbaseError,
|
|
49
|
+
RateLimitError,
|
|
50
|
+
AuthenticationError,
|
|
51
|
+
AuthorizationError,
|
|
52
|
+
NotFoundError,
|
|
53
|
+
ValidationError,
|
|
54
|
+
TimeoutError,
|
|
55
|
+
ServerError,
|
|
56
|
+
QuickbaseTicketError,
|
|
57
|
+
QuickbaseAppTokenError,
|
|
58
|
+
QuickbaseXmlError,
|
|
59
|
+
ReadOnlyError,
|
|
60
|
+
} from './core/index.js';
|
|
61
|
+
|
|
62
|
+
// Auth exports (for advanced usage)
|
|
63
|
+
export type { AuthStrategy } from './auth/index.js';
|
|
64
|
+
export {
|
|
65
|
+
UserTokenStrategy,
|
|
66
|
+
TempTokenStrategy,
|
|
67
|
+
SsoTokenStrategy,
|
|
68
|
+
TicketStrategy, // XML-API-TICKET: Remove if XML API discontinued
|
|
69
|
+
createAuthStrategy,
|
|
70
|
+
} from './auth/index.js';
|
|
71
|
+
import type { AuthStrategy } from './auth/index.js';
|
|
72
|
+
|
|
73
|
+
// Client exports
|
|
74
|
+
export type { RequestOptions } from './client/index.js';
|
|
75
|
+
export { SlidingWindowThrottle, NoOpThrottle } from './client/index.js';
|
|
76
|
+
|
|
77
|
+
// Generated types and client
|
|
78
|
+
export type { QuickbaseAPI } from './generated/types.js';
|
|
79
|
+
export * from './generated/types.js';
|
|
80
|
+
export { createApiMethods } from './generated/client.js';
|
|
81
|
+
|
|
82
|
+
// Main client factory
|
|
83
|
+
import type { QuickbaseConfig, ResolvedConfig } from './core/types.js';
|
|
84
|
+
import { resolveConfig } from './core/config.js';
|
|
85
|
+
import { createLogger } from './core/logger.js';
|
|
86
|
+
import { createAuthStrategy } from './auth/index.js';
|
|
87
|
+
import { createThrottle } from './client/throttle.js';
|
|
88
|
+
import { createRequestExecutor } from './client/request.js';
|
|
89
|
+
import type { QuickbaseAPI } from './generated/types.js';
|
|
90
|
+
import { createApiMethods } from './generated/client.js';
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* QuickBase client with typed API methods
|
|
94
|
+
*/
|
|
95
|
+
export interface QuickbaseClient extends QuickbaseAPI {
|
|
96
|
+
/** Execute a raw request (for custom API calls) */
|
|
97
|
+
request: <T = unknown>(options: {
|
|
98
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
99
|
+
path: string;
|
|
100
|
+
body?: unknown;
|
|
101
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
102
|
+
dbid?: string;
|
|
103
|
+
}) => Promise<T>;
|
|
104
|
+
|
|
105
|
+
/** Get the resolved configuration */
|
|
106
|
+
getConfig: () => ResolvedConfig;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get the auth strategy for advanced usage (e.g., XML API client).
|
|
110
|
+
* XML-API: Used by createXmlClient() to access authentication.
|
|
111
|
+
*/
|
|
112
|
+
getAuthStrategy: () => AuthStrategy;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create a QuickBase client
|
|
117
|
+
*
|
|
118
|
+
* @example User token authentication
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const client = createClient({
|
|
121
|
+
* realm: 'mycompany',
|
|
122
|
+
* auth: {
|
|
123
|
+
* type: 'user-token',
|
|
124
|
+
* userToken: 'your-user-token',
|
|
125
|
+
* },
|
|
126
|
+
* });
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* @example Temporary token authentication
|
|
130
|
+
* ```typescript
|
|
131
|
+
* const client = createClient({
|
|
132
|
+
* realm: 'mycompany',
|
|
133
|
+
* auth: {
|
|
134
|
+
* type: 'temp-token',
|
|
135
|
+
* userToken: 'your-user-token',
|
|
136
|
+
* appToken: 'optional-app-token',
|
|
137
|
+
* },
|
|
138
|
+
* });
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* @example With rate limiting callback
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const client = createClient({
|
|
144
|
+
* realm: 'mycompany',
|
|
145
|
+
* auth: { type: 'user-token', userToken: 'token' },
|
|
146
|
+
* rateLimit: {
|
|
147
|
+
* onRateLimit: (info) => {
|
|
148
|
+
* console.log(`Rate limited! Retry after ${info.retryAfter}s`);
|
|
149
|
+
* },
|
|
150
|
+
* },
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export function createClient(config: QuickbaseConfig): QuickbaseClient {
|
|
155
|
+
const resolvedConfig = resolveConfig(config);
|
|
156
|
+
const logger = createLogger(resolvedConfig.debug);
|
|
157
|
+
|
|
158
|
+
const authContext = {
|
|
159
|
+
realm: resolvedConfig.realm,
|
|
160
|
+
baseUrl: resolvedConfig.baseUrl,
|
|
161
|
+
fetchApi: resolvedConfig.fetchApi,
|
|
162
|
+
logger,
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const auth = createAuthStrategy(resolvedConfig.auth, authContext);
|
|
166
|
+
const throttle = createThrottle(resolvedConfig.proactiveThrottle);
|
|
167
|
+
|
|
168
|
+
const executor = createRequestExecutor({
|
|
169
|
+
config: resolvedConfig,
|
|
170
|
+
auth,
|
|
171
|
+
throttle,
|
|
172
|
+
logger,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Create typed API methods
|
|
176
|
+
const apiMethods = createApiMethods(executor.execute, resolvedConfig.autoPaginate);
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
...apiMethods,
|
|
180
|
+
request: executor.execute,
|
|
181
|
+
getConfig: () => resolvedConfig,
|
|
182
|
+
// XML-API: Expose auth strategy for XML client
|
|
183
|
+
getAuthStrategy: () => auth,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// XML-API: XML API exports - remove when QuickBase discontinues XML API
|
|
188
|
+
export {
|
|
189
|
+
createXmlClient,
|
|
190
|
+
XmlClient,
|
|
191
|
+
XmlError,
|
|
192
|
+
XmlErrorCode,
|
|
193
|
+
checkError,
|
|
194
|
+
isUnauthorized as isXmlUnauthorized,
|
|
195
|
+
isNotFound as isXmlNotFound,
|
|
196
|
+
isInvalidTicket as isXmlInvalidTicket,
|
|
197
|
+
isXmlWriteAction,
|
|
198
|
+
} from './xml/index.js';
|
|
199
|
+
export type {
|
|
200
|
+
XmlCaller,
|
|
201
|
+
XmlClientOptions,
|
|
202
|
+
XmlExecutor,
|
|
203
|
+
// Role types
|
|
204
|
+
Role,
|
|
205
|
+
RoleAccess,
|
|
206
|
+
UserRole,
|
|
207
|
+
RoleMember,
|
|
208
|
+
UserWithRoles,
|
|
209
|
+
// Group types
|
|
210
|
+
Group,
|
|
211
|
+
GroupUser,
|
|
212
|
+
GroupManager,
|
|
213
|
+
Subgroup,
|
|
214
|
+
// User types
|
|
215
|
+
UserInfo,
|
|
216
|
+
// Schema types (XML)
|
|
217
|
+
SchemaField,
|
|
218
|
+
SchemaQuery,
|
|
219
|
+
SchemaVariable,
|
|
220
|
+
SchemaChildTable,
|
|
221
|
+
SchemaOriginal,
|
|
222
|
+
SchemaTable,
|
|
223
|
+
// App discovery types
|
|
224
|
+
DatabaseInfo,
|
|
225
|
+
DBInfo,
|
|
226
|
+
// Record types (XML)
|
|
227
|
+
RecordField,
|
|
228
|
+
// Code page types
|
|
229
|
+
PageType,
|
|
230
|
+
// Webhook types
|
|
231
|
+
WebhookTrigger,
|
|
232
|
+
WebhookOptions,
|
|
233
|
+
// Result types
|
|
234
|
+
GetRoleInfoResult,
|
|
235
|
+
UserRolesResult,
|
|
236
|
+
GetUserRoleResult,
|
|
237
|
+
GetSchemaResult,
|
|
238
|
+
GrantedDBsResult,
|
|
239
|
+
FindDBByNameResult,
|
|
240
|
+
GetUsersInGroupResult,
|
|
241
|
+
CreateGroupResult,
|
|
242
|
+
GetGroupRoleResult,
|
|
243
|
+
ProvisionUserResult,
|
|
244
|
+
AddReplaceDBPageResult,
|
|
245
|
+
FieldAddChoicesResult,
|
|
246
|
+
FieldRemoveChoicesResult,
|
|
247
|
+
DoQueryCountResult,
|
|
248
|
+
GetRecordInfoResult,
|
|
249
|
+
GrantedGroupsResult,
|
|
250
|
+
GrantedDBsForGroupResult,
|
|
251
|
+
GetAppDTMInfoResult,
|
|
252
|
+
GetAncestorInfoResult,
|
|
253
|
+
ImportFromCSVResult,
|
|
254
|
+
CopyMasterDetailResult,
|
|
255
|
+
WebhookResult,
|
|
256
|
+
} from './xml/index.js';
|
|
257
|
+
|
|
258
|
+
// Default export
|
|
259
|
+
export default createClient;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML API Code Pages
|
|
3
|
+
*
|
|
4
|
+
* Endpoints for managing stored code pages (HTML, XSL, etc.).
|
|
5
|
+
*
|
|
6
|
+
* XML-API: Remove this file when QuickBase discontinues the XML API.
|
|
7
|
+
* To find all XML API code, search for: XML-API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
XmlCaller,
|
|
12
|
+
PageType,
|
|
13
|
+
AddReplaceDBPageResult,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
import { checkError } from './errors.js';
|
|
16
|
+
import {
|
|
17
|
+
buildRequest,
|
|
18
|
+
escapeXml,
|
|
19
|
+
parseBaseResponse,
|
|
20
|
+
getTagContent,
|
|
21
|
+
xmlElementCDATA,
|
|
22
|
+
parseXmlNumber,
|
|
23
|
+
} from './request.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get stored code page content.
|
|
27
|
+
*
|
|
28
|
+
* Returns the raw page content (HTML, XSL, etc.).
|
|
29
|
+
*
|
|
30
|
+
* @see https://help.quickbase.com/docs/api-getdbpage
|
|
31
|
+
*
|
|
32
|
+
* @param pageIdOrName - Page ID (number) or page name (string)
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* // By page ID
|
|
37
|
+
* const content = await getDBPage(caller, 'bqapp123', 3);
|
|
38
|
+
*
|
|
39
|
+
* // By page name
|
|
40
|
+
* const content = await getDBPage(caller, 'bqapp123', 'mystylesheet.xsl');
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export async function getDBPage(
|
|
44
|
+
caller: XmlCaller,
|
|
45
|
+
appId: string,
|
|
46
|
+
pageIdOrName: string | number
|
|
47
|
+
): Promise<string> {
|
|
48
|
+
const inner = `<pageID>${escapeXml(String(pageIdOrName))}</pageID>`;
|
|
49
|
+
const body = buildRequest(inner);
|
|
50
|
+
const xml = await caller.doXml(appId, 'API_GetDBPage', body);
|
|
51
|
+
|
|
52
|
+
// Note: GetDBPage returns raw HTML, not XML
|
|
53
|
+
// Check if it's an error response
|
|
54
|
+
if (xml.includes('<errcode>') && !xml.includes('<errcode>0</errcode>')) {
|
|
55
|
+
const base = parseBaseResponse(xml);
|
|
56
|
+
checkError(base);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// If not an error, return the raw content
|
|
60
|
+
// The response is the page content itself, not wrapped in XML
|
|
61
|
+
return xml;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create or update a code page.
|
|
66
|
+
*
|
|
67
|
+
* Page types:
|
|
68
|
+
* - 1: XSL stylesheets or HTML pages
|
|
69
|
+
* - 3: Exact Forms (Word templates)
|
|
70
|
+
*
|
|
71
|
+
* @see https://help.quickbase.com/docs/api-addreplacedbpage
|
|
72
|
+
*
|
|
73
|
+
* @param pageId - Existing page ID to replace (undefined to create new)
|
|
74
|
+
* @param pageName - Name for the page (required when creating new)
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* // Create a new page
|
|
79
|
+
* const result = await addReplaceDBPage(
|
|
80
|
+
* caller, 'bqapp123',
|
|
81
|
+
* 'mypage.html', undefined, 1,
|
|
82
|
+
* '<html><body>Hello World</body></html>'
|
|
83
|
+
* );
|
|
84
|
+
* console.log(`Created page ID: ${result.pageId}`);
|
|
85
|
+
*
|
|
86
|
+
* // Update existing page
|
|
87
|
+
* await addReplaceDBPage(
|
|
88
|
+
* caller, 'bqapp123',
|
|
89
|
+
* 'mypage.html', 6, 1,
|
|
90
|
+
* '<html><body>Updated content</body></html>'
|
|
91
|
+
* );
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export async function addReplaceDBPage(
|
|
95
|
+
caller: XmlCaller,
|
|
96
|
+
appId: string,
|
|
97
|
+
pageName: string,
|
|
98
|
+
pageId: number | undefined,
|
|
99
|
+
pageType: PageType,
|
|
100
|
+
pageBody: string
|
|
101
|
+
): Promise<AddReplaceDBPageResult> {
|
|
102
|
+
let inner = '';
|
|
103
|
+
|
|
104
|
+
if (pageId !== undefined) {
|
|
105
|
+
inner += `<pageid>${pageId}</pageid>`;
|
|
106
|
+
}
|
|
107
|
+
inner += `<pagename>${escapeXml(pageName)}</pagename>`;
|
|
108
|
+
inner += `<pagetype>${pageType}</pagetype>`;
|
|
109
|
+
inner += xmlElementCDATA('pagebody', pageBody);
|
|
110
|
+
|
|
111
|
+
const body = buildRequest(inner);
|
|
112
|
+
const xml = await caller.doXml(appId, 'API_AddReplaceDBPage', body);
|
|
113
|
+
|
|
114
|
+
const base = parseBaseResponse(xml);
|
|
115
|
+
checkError(base);
|
|
116
|
+
|
|
117
|
+
const resultPageId = parseXmlNumber(getTagContent(xml, 'pageID'));
|
|
118
|
+
return { pageId: resultPageId };
|
|
119
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML API Application Variables (DBVars)
|
|
3
|
+
*
|
|
4
|
+
* Endpoints for managing application variables.
|
|
5
|
+
*
|
|
6
|
+
* XML-API: Remove this file when QuickBase discontinues the XML API.
|
|
7
|
+
* To find all XML API code, search for: XML-API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { XmlCaller } from './types.js';
|
|
11
|
+
import { checkError } from './errors.js';
|
|
12
|
+
import {
|
|
13
|
+
buildRequest,
|
|
14
|
+
escapeXml,
|
|
15
|
+
parseBaseResponse,
|
|
16
|
+
getTagContent,
|
|
17
|
+
} from './request.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get an application variable value.
|
|
21
|
+
*
|
|
22
|
+
* DBVars are application-level variables that can be used in formulas
|
|
23
|
+
* and code pages.
|
|
24
|
+
*
|
|
25
|
+
* @see https://help.quickbase.com/docs/api-getdbvar
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const value = await getDBVar(caller, 'bqapp123', 'myVariable');
|
|
30
|
+
* console.log(`Variable value: ${value}`);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export async function getDBVar(
|
|
34
|
+
caller: XmlCaller,
|
|
35
|
+
appId: string,
|
|
36
|
+
varName: string
|
|
37
|
+
): Promise<string> {
|
|
38
|
+
const inner = `<varname>${escapeXml(varName)}</varname>`;
|
|
39
|
+
const body = buildRequest(inner);
|
|
40
|
+
const xml = await caller.doXml(appId, 'API_GetDBVar', body);
|
|
41
|
+
|
|
42
|
+
const base = parseBaseResponse(xml);
|
|
43
|
+
checkError(base);
|
|
44
|
+
|
|
45
|
+
return getTagContent(xml, 'value');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Set an application variable value.
|
|
50
|
+
*
|
|
51
|
+
* Creates the variable if it doesn't exist, or overwrites if it does.
|
|
52
|
+
* Requires Full Administration rights on the application.
|
|
53
|
+
*
|
|
54
|
+
* @see https://help.quickbase.com/docs/api-setdbvar
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* await setDBVar(caller, 'bqapp123', 'myVariable', '42');
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export async function setDBVar(
|
|
62
|
+
caller: XmlCaller,
|
|
63
|
+
appId: string,
|
|
64
|
+
varName: string,
|
|
65
|
+
value: string
|
|
66
|
+
): Promise<void> {
|
|
67
|
+
const inner =
|
|
68
|
+
`<varname>${escapeXml(varName)}</varname>` +
|
|
69
|
+
`<value>${escapeXml(value)}</value>`;
|
|
70
|
+
const body = buildRequest(inner);
|
|
71
|
+
const xml = await caller.doXml(appId, 'API_SetDBVar', body);
|
|
72
|
+
|
|
73
|
+
const base = parseBaseResponse(xml);
|
|
74
|
+
checkError(base);
|
|
75
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML API Errors
|
|
3
|
+
*
|
|
4
|
+
* Error handling for the legacy QuickBase XML API.
|
|
5
|
+
*
|
|
6
|
+
* XML-API: Remove this file when QuickBase discontinues the XML API.
|
|
7
|
+
* To find all XML API code, search for: XML-API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { BaseResponse } from './types.js';
|
|
11
|
+
import { QuickbaseTicketError, QuickbaseAppTokenError, QuickbaseXmlError } from '../core/errors.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Common QuickBase XML API error codes
|
|
15
|
+
*/
|
|
16
|
+
export const XmlErrorCode = {
|
|
17
|
+
/** No error (success) */
|
|
18
|
+
Success: 0,
|
|
19
|
+
/** Invalid input parameters */
|
|
20
|
+
InvalidInput: 2,
|
|
21
|
+
/** User is not authorized for this action */
|
|
22
|
+
Unauthorized: 3,
|
|
23
|
+
/** Authentication ticket is invalid or expired (Bad Ticket) */
|
|
24
|
+
InvalidTicket: 4,
|
|
25
|
+
/** Database/table does not exist */
|
|
26
|
+
NoSuchDatabase: 6,
|
|
27
|
+
/** SSL is required for this application/table */
|
|
28
|
+
SSLRequired: 8,
|
|
29
|
+
/** Realm IP filtering is in place */
|
|
30
|
+
UnauthorizedIP: 19,
|
|
31
|
+
/** Application token provided is invalid or not assigned */
|
|
32
|
+
InvalidAppToken: 24,
|
|
33
|
+
/** Record does not exist */
|
|
34
|
+
NoSuchRecord: 30,
|
|
35
|
+
/** Field does not exist */
|
|
36
|
+
NoSuchField: 31,
|
|
37
|
+
/** Application does not exist or was deleted */
|
|
38
|
+
NoSuchApp: 32,
|
|
39
|
+
/** User does not exist */
|
|
40
|
+
NoSuchUser: 33,
|
|
41
|
+
/** Access denied */
|
|
42
|
+
AccessDenied: 83,
|
|
43
|
+
} as const;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Error returned by the QuickBase XML API.
|
|
47
|
+
*
|
|
48
|
+
* XML-API: This class is a legacy alias for QuickbaseXmlError.
|
|
49
|
+
*/
|
|
50
|
+
export class XmlError extends QuickbaseXmlError {
|
|
51
|
+
constructor(code: number, text: string, detail?: string, action?: string) {
|
|
52
|
+
super(code, text, { description: detail, action });
|
|
53
|
+
this.name = 'XmlError';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if the response contains an error and throw if so.
|
|
59
|
+
* Returns void if successful (errcode === 0).
|
|
60
|
+
*/
|
|
61
|
+
export function checkError(resp: BaseResponse): void {
|
|
62
|
+
if (resp.errcode === 0) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Map to specialized error types
|
|
67
|
+
if (resp.errcode === XmlErrorCode.InvalidTicket) {
|
|
68
|
+
throw new QuickbaseTicketError(resp.errtext, resp.errcode, {
|
|
69
|
+
description: resp.errdetail,
|
|
70
|
+
action: resp.action,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
resp.errcode === XmlErrorCode.InvalidAppToken
|
|
76
|
+
) {
|
|
77
|
+
throw new QuickbaseAppTokenError(resp.errtext, resp.errcode, {
|
|
78
|
+
description: resp.errdetail,
|
|
79
|
+
action: resp.action,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
throw new XmlError(resp.errcode, resp.errtext, resp.errdetail, resp.action);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if the error is an authorization error (code 3 or 83)
|
|
88
|
+
*/
|
|
89
|
+
export function isUnauthorized(err: unknown): boolean {
|
|
90
|
+
if (err instanceof XmlError) {
|
|
91
|
+
return (
|
|
92
|
+
err.code === XmlErrorCode.Unauthorized ||
|
|
93
|
+
err.code === XmlErrorCode.AccessDenied
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if the error indicates a resource was not found
|
|
101
|
+
*/
|
|
102
|
+
export function isNotFound(err: unknown): boolean {
|
|
103
|
+
if (err instanceof XmlError) {
|
|
104
|
+
return (
|
|
105
|
+
err.code === XmlErrorCode.NoSuchDatabase ||
|
|
106
|
+
err.code === XmlErrorCode.NoSuchApp ||
|
|
107
|
+
err.code === XmlErrorCode.NoSuchRecord ||
|
|
108
|
+
err.code === XmlErrorCode.NoSuchField ||
|
|
109
|
+
err.code === XmlErrorCode.NoSuchUser
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Check if the error indicates an invalid or expired authentication ticket
|
|
117
|
+
*/
|
|
118
|
+
export function isInvalidTicket(err: unknown): boolean {
|
|
119
|
+
if (err instanceof XmlError) {
|
|
120
|
+
return err.code === XmlErrorCode.InvalidTicket;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Check if the error indicates invalid input parameters
|
|
127
|
+
*/
|
|
128
|
+
export function isInvalidInput(err: unknown): boolean {
|
|
129
|
+
if (err instanceof XmlError) {
|
|
130
|
+
return err.code === XmlErrorCode.InvalidInput;
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML API Field Management
|
|
3
|
+
*
|
|
4
|
+
* Endpoints for managing field properties.
|
|
5
|
+
*
|
|
6
|
+
* XML-API: Remove this file when QuickBase discontinues the XML API.
|
|
7
|
+
* To find all XML API code, search for: XML-API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
XmlCaller,
|
|
12
|
+
FieldAddChoicesResult,
|
|
13
|
+
FieldRemoveChoicesResult,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
import { checkError } from './errors.js';
|
|
16
|
+
import {
|
|
17
|
+
buildRequest,
|
|
18
|
+
escapeXml,
|
|
19
|
+
parseBaseResponse,
|
|
20
|
+
getTagContent,
|
|
21
|
+
parseXmlNumber,
|
|
22
|
+
} from './request.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Add choices to a multiple-choice field.
|
|
26
|
+
*
|
|
27
|
+
* @see https://help.quickbase.com/docs/api-fieldaddchoices
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const result = await fieldAddChoices(caller, 'bqtable123', 6, ['Option A', 'Option B']);
|
|
32
|
+
* console.log(`Added ${result.numAdded} choices`);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export async function fieldAddChoices(
|
|
36
|
+
caller: XmlCaller,
|
|
37
|
+
tableId: string,
|
|
38
|
+
fieldId: number,
|
|
39
|
+
choices: string[]
|
|
40
|
+
): Promise<FieldAddChoicesResult> {
|
|
41
|
+
if (choices.length === 0) {
|
|
42
|
+
throw new Error('choices array cannot be empty');
|
|
43
|
+
}
|
|
44
|
+
let inner = `<fid>${fieldId}</fid>`;
|
|
45
|
+
for (const choice of choices) {
|
|
46
|
+
inner += `<choice>${escapeXml(choice)}</choice>`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const body = buildRequest(inner);
|
|
50
|
+
const xml = await caller.doXml(tableId, 'API_FieldAddChoices', body);
|
|
51
|
+
|
|
52
|
+
const base = parseBaseResponse(xml);
|
|
53
|
+
checkError(base);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
fieldId,
|
|
57
|
+
fieldName: getTagContent(xml, 'fname') || '',
|
|
58
|
+
numAdded: parseXmlNumber(getTagContent(xml, 'numadded')),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Remove choices from a multiple-choice field.
|
|
64
|
+
*
|
|
65
|
+
* @see https://help.quickbase.com/docs/api-fieldremovechoices
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const result = await fieldRemoveChoices(caller, 'bqtable123', 6, ['Option A']);
|
|
70
|
+
* console.log(`Removed ${result.numRemoved} choices`);
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export async function fieldRemoveChoices(
|
|
74
|
+
caller: XmlCaller,
|
|
75
|
+
tableId: string,
|
|
76
|
+
fieldId: number,
|
|
77
|
+
choices: string[]
|
|
78
|
+
): Promise<FieldRemoveChoicesResult> {
|
|
79
|
+
if (choices.length === 0) {
|
|
80
|
+
throw new Error('choices array cannot be empty');
|
|
81
|
+
}
|
|
82
|
+
let inner = `<fid>${fieldId}</fid>`;
|
|
83
|
+
for (const choice of choices) {
|
|
84
|
+
inner += `<choice>${escapeXml(choice)}</choice>`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const body = buildRequest(inner);
|
|
88
|
+
const xml = await caller.doXml(tableId, 'API_FieldRemoveChoices', body);
|
|
89
|
+
|
|
90
|
+
const base = parseBaseResponse(xml);
|
|
91
|
+
checkError(base);
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
fieldId,
|
|
95
|
+
fieldName: getTagContent(xml, 'fname') || '',
|
|
96
|
+
numRemoved: parseXmlNumber(getTagContent(xml, 'numremoved')),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Set the key field for a table.
|
|
102
|
+
*
|
|
103
|
+
* @see https://help.quickbase.com/docs/api-setkeyfield
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* await setKeyField(caller, 'bqtable123', 6);
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export async function setKeyField(
|
|
111
|
+
caller: XmlCaller,
|
|
112
|
+
tableId: string,
|
|
113
|
+
fieldId: number
|
|
114
|
+
): Promise<void> {
|
|
115
|
+
const inner = `<fid>${fieldId}</fid>`;
|
|
116
|
+
const body = buildRequest(inner);
|
|
117
|
+
const xml = await caller.doXml(tableId, 'API_SetKeyField', body);
|
|
118
|
+
|
|
119
|
+
const base = parseBaseResponse(xml);
|
|
120
|
+
checkError(base);
|
|
121
|
+
}
|