@tapstack/db 1.0.7 → 3.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.
- package/README.md +655 -0
- package/dist/adapters/index.d.ts +6 -0
- package/dist/adapters/index.js +22 -0
- package/dist/adapters/nodejs.adapter.d.ts +63 -0
- package/dist/adapters/nodejs.adapter.js +204 -0
- package/dist/adapters/types.d.ts +77 -0
- package/dist/adapters/types.js +19 -0
- package/dist/index.d.ts +101 -21
- package/dist/index.js +114 -41
- package/dist/modules/automations.d.ts +109 -0
- package/dist/modules/automations.js +59 -0
- package/dist/modules/conversations.d.ts +82 -0
- package/dist/modules/conversations.js +54 -0
- package/dist/modules/fields.d.ts +30 -9
- package/dist/modules/fields.js +31 -13
- package/dist/modules/files.d.ts +68 -0
- package/dist/modules/files.js +115 -0
- package/dist/modules/index.d.ts +12 -0
- package/dist/modules/index.js +28 -0
- package/dist/modules/objects.d.ts +30 -9
- package/dist/modules/objects.js +35 -13
- package/dist/modules/organizations.d.ts +69 -0
- package/dist/modules/organizations.js +83 -0
- package/dist/modules/records.d.ts +47 -5
- package/dist/modules/records.js +70 -5
- package/dist/modules/workspaces.d.ts +44 -0
- package/dist/modules/workspaces.js +57 -0
- package/dist/types.d.ts +159 -10
- package/dist/types.js +19 -0
- package/package.json +16 -7
- package/src/__tests__/client.test.ts +305 -49
- package/src/adapters/index.ts +13 -0
- package/src/adapters/nodejs.adapter.ts +298 -0
- package/src/adapters/types.ts +108 -0
- package/src/index.ts +132 -44
- package/src/modules/automations.ts +157 -0
- package/src/modules/conversations.ts +134 -0
- package/src/modules/fields.ts +64 -14
- package/src/modules/files.ts +144 -0
- package/src/modules/index.ts +19 -0
- package/src/modules/objects.ts +46 -14
- package/src/modules/organizations.ts +137 -0
- package/src/modules/records.ts +119 -6
- package/src/modules/workspaces.ts +95 -0
- package/src/types.ts +229 -9
- package/dist/request.d.ts +0 -2
- package/dist/request.js +0 -20
- package/src/request.ts +0 -14
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tapstack API Adapter
|
|
3
|
+
* Implements IInstanceAdapter for the Tapstack API at api.tapstack.com
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
IInstanceAdapter,
|
|
8
|
+
AdapterConfig,
|
|
9
|
+
HttpMethod,
|
|
10
|
+
RequestOptions,
|
|
11
|
+
ApiResponse,
|
|
12
|
+
AdapterError,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Default Tapstack API URL
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_API_URL = 'https://api.tapstack.com';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Configuration for the Tapstack API adapter
|
|
22
|
+
*/
|
|
23
|
+
export interface NodeJSAdapterConfig extends AdapterConfig {
|
|
24
|
+
/**
|
|
25
|
+
* Base URL of the Tapstack API
|
|
26
|
+
* @default 'https://api.tapstack.com'
|
|
27
|
+
*/
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* API key for authentication (for programmatic access)
|
|
32
|
+
*/
|
|
33
|
+
apiKey?: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Service token for service-to-service calls
|
|
37
|
+
*/
|
|
38
|
+
serviceToken?: string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* User token for frontend calls (static)
|
|
42
|
+
*/
|
|
43
|
+
userToken?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Function to get dynamic user token (alternative to static userToken)
|
|
47
|
+
* Use this in frontend apps where the token may change
|
|
48
|
+
*/
|
|
49
|
+
getUserToken?: () => Promise<string | null>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class NodeJSAdapter implements IInstanceAdapter {
|
|
53
|
+
private workspaceId: string | null;
|
|
54
|
+
private baseUrl: string;
|
|
55
|
+
|
|
56
|
+
constructor(private config: NodeJSAdapterConfig) {
|
|
57
|
+
this.workspaceId = config.workspaceId ?? null;
|
|
58
|
+
this.baseUrl = config.baseUrl ?? DEFAULT_API_URL;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Map SDK paths to REST API paths
|
|
63
|
+
* Converts paths like 'records/contacts' to '/api/v1/objects/contacts/records'
|
|
64
|
+
*/
|
|
65
|
+
private mapPath(path: string): string {
|
|
66
|
+
// Already a full path
|
|
67
|
+
if (path.startsWith('/api/')) {
|
|
68
|
+
return path;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Schema operations
|
|
72
|
+
if (path.startsWith('schema/objects')) {
|
|
73
|
+
return `/api/v1/objects${path.replace('schema/objects', '')}`;
|
|
74
|
+
}
|
|
75
|
+
if (path.startsWith('schema/fields/')) {
|
|
76
|
+
const parts = path.split('/');
|
|
77
|
+
const objectSlug = parts[2];
|
|
78
|
+
const rest = parts.slice(3).join('/');
|
|
79
|
+
return `/api/v1/objects/${objectSlug}/fields${rest ? `/${rest}` : ''}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Record operations: records/{objectSlug}/... -> /api/v1/objects/{objectSlug}/records/...
|
|
83
|
+
if (path.startsWith('records/')) {
|
|
84
|
+
const parts = path.split('/');
|
|
85
|
+
const objectSlug = parts[1];
|
|
86
|
+
const rest = parts.slice(2).join('/');
|
|
87
|
+
return `/api/v1/objects/${objectSlug}/records${rest ? `/${rest}` : ''}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// File operations
|
|
91
|
+
if (path.startsWith('files')) {
|
|
92
|
+
return `/api/v1${path.startsWith('/') ? path : `/${path}`}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Automation operations
|
|
96
|
+
if (path.startsWith('automations')) {
|
|
97
|
+
return `/api/v1${path.startsWith('/') ? path : `/${path}`}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Conversation operations
|
|
101
|
+
if (path.startsWith('conversations')) {
|
|
102
|
+
return `/api/v1${path.startsWith('/') ? path : `/${path}`}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// AI operations
|
|
106
|
+
if (path.startsWith('ai')) {
|
|
107
|
+
return `/api/v1${path.startsWith('/') ? path : `/${path}`}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Organization operations
|
|
111
|
+
if (path.startsWith('organizations')) {
|
|
112
|
+
return `/api${path.startsWith('/') ? path : `/${path}`}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Workspace operations
|
|
116
|
+
if (path.startsWith('workspaces')) {
|
|
117
|
+
return `/api${path.startsWith('/') ? path : `/${path}`}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Activity operations
|
|
121
|
+
if (path.startsWith('activity')) {
|
|
122
|
+
return `/api/v1${path.startsWith('/') ? path : `/${path}`}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Default: add /api prefix
|
|
126
|
+
return `/api/${path}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Make a request to the Tapstack API
|
|
131
|
+
*/
|
|
132
|
+
async request<T>(
|
|
133
|
+
method: HttpMethod,
|
|
134
|
+
path: string,
|
|
135
|
+
options?: RequestOptions
|
|
136
|
+
): Promise<T> {
|
|
137
|
+
// Build the URL - API uses /api/v1 prefix for data operations
|
|
138
|
+
const apiPath = this.mapPath(path);
|
|
139
|
+
let url = `${this.baseUrl}${apiPath}`;
|
|
140
|
+
|
|
141
|
+
// Add query parameters
|
|
142
|
+
if (options?.params) {
|
|
143
|
+
const params = new URLSearchParams(options.params);
|
|
144
|
+
if (this.workspaceId && !options.params.workspaceId) {
|
|
145
|
+
params.set('workspaceId', this.workspaceId);
|
|
146
|
+
}
|
|
147
|
+
url += `?${params.toString()}`;
|
|
148
|
+
} else if (this.workspaceId) {
|
|
149
|
+
url += `?workspaceId=${this.workspaceId}`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Build headers
|
|
153
|
+
const headers: Record<string, string> = {
|
|
154
|
+
'Content-Type': 'application/json',
|
|
155
|
+
...this.config.defaultHeaders,
|
|
156
|
+
...options?.headers,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Add authentication
|
|
160
|
+
if (this.config.apiKey) {
|
|
161
|
+
headers['X-API-Key'] = this.config.apiKey;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (this.config.serviceToken) {
|
|
165
|
+
headers['Authorization'] = `Bearer ${this.config.serviceToken}`;
|
|
166
|
+
} else if (this.config.userToken) {
|
|
167
|
+
headers['Authorization'] = `Bearer ${this.config.userToken}`;
|
|
168
|
+
} else if (this.config.getUserToken) {
|
|
169
|
+
const token = await this.config.getUserToken();
|
|
170
|
+
if (token) {
|
|
171
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Add workspace header
|
|
176
|
+
if (this.workspaceId) {
|
|
177
|
+
headers['X-Workspace-Id'] = this.workspaceId;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Make the request
|
|
181
|
+
const response = await fetch(url, {
|
|
182
|
+
method,
|
|
183
|
+
headers,
|
|
184
|
+
body: options?.body ? JSON.stringify(options.body) : undefined,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Handle authentication errors
|
|
188
|
+
if (response.status === 401) {
|
|
189
|
+
this.config.onAuthError?.();
|
|
190
|
+
throw new AdapterError('Unauthorized', 'UNAUTHORIZED', 401);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Parse response
|
|
194
|
+
const data = (await response.json()) as ApiResponse<T>;
|
|
195
|
+
|
|
196
|
+
// Handle API errors
|
|
197
|
+
if (!data.success) {
|
|
198
|
+
throw new AdapterError(
|
|
199
|
+
data.error?.message || 'Request failed',
|
|
200
|
+
data.error?.code || 'UNKNOWN_ERROR',
|
|
201
|
+
response.status
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return data.data as T;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Upload a file to the Tapstack API
|
|
210
|
+
*/
|
|
211
|
+
async upload<T>(
|
|
212
|
+
path: string,
|
|
213
|
+
file: File | Blob,
|
|
214
|
+
metadata?: Record<string, string>
|
|
215
|
+
): Promise<T> {
|
|
216
|
+
const apiPath = this.mapPath(path);
|
|
217
|
+
let url = `${this.baseUrl}${apiPath}`;
|
|
218
|
+
|
|
219
|
+
if (this.workspaceId) {
|
|
220
|
+
url += `?workspaceId=${this.workspaceId}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const headers: Record<string, string> = {
|
|
224
|
+
...this.config.defaultHeaders,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if (this.config.apiKey) {
|
|
228
|
+
headers['X-API-Key'] = this.config.apiKey;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (this.config.serviceToken) {
|
|
232
|
+
headers['Authorization'] = `Bearer ${this.config.serviceToken}`;
|
|
233
|
+
} else if (this.config.userToken) {
|
|
234
|
+
headers['Authorization'] = `Bearer ${this.config.userToken}`;
|
|
235
|
+
} else if (this.config.getUserToken) {
|
|
236
|
+
const token = await this.config.getUserToken();
|
|
237
|
+
if (token) {
|
|
238
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (this.workspaceId) {
|
|
243
|
+
headers['X-Workspace-Id'] = this.workspaceId;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const formData = new FormData();
|
|
247
|
+
formData.append('file', file);
|
|
248
|
+
|
|
249
|
+
if (metadata) {
|
|
250
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
251
|
+
formData.append(key, value);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const response = await fetch(url, {
|
|
256
|
+
method: 'POST',
|
|
257
|
+
headers,
|
|
258
|
+
body: formData,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
if (response.status === 401) {
|
|
262
|
+
this.config.onAuthError?.();
|
|
263
|
+
throw new AdapterError('Unauthorized', 'UNAUTHORIZED', 401);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const data = (await response.json()) as ApiResponse<T>;
|
|
267
|
+
|
|
268
|
+
if (!data.success) {
|
|
269
|
+
throw new AdapterError(
|
|
270
|
+
data.error?.message || 'Upload failed',
|
|
271
|
+
data.error?.code || 'UPLOAD_ERROR',
|
|
272
|
+
response.status
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return data.data as T;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Set the workspace context
|
|
281
|
+
*/
|
|
282
|
+
setWorkspaceId(workspaceId: string | null): void {
|
|
283
|
+
this.workspaceId = workspaceId;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get the current workspace ID
|
|
288
|
+
*/
|
|
289
|
+
getWorkspaceId(): string | null {
|
|
290
|
+
return this.workspaceId;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instance Adapter Interface
|
|
3
|
+
* Defines the contract for backend adapters (Edge Functions, Node.js API, etc.)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
7
|
+
|
|
8
|
+
export interface RequestOptions {
|
|
9
|
+
body?: unknown;
|
|
10
|
+
params?: Record<string, string>;
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Core adapter interface that all backend implementations must implement
|
|
16
|
+
*/
|
|
17
|
+
export interface IInstanceAdapter {
|
|
18
|
+
/**
|
|
19
|
+
* Make an HTTP request to the backend
|
|
20
|
+
*/
|
|
21
|
+
request<T>(
|
|
22
|
+
method: HttpMethod,
|
|
23
|
+
path: string,
|
|
24
|
+
options?: RequestOptions
|
|
25
|
+
): Promise<T>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Upload a file to the backend
|
|
29
|
+
*/
|
|
30
|
+
upload<T>(
|
|
31
|
+
path: string,
|
|
32
|
+
file: File | Blob,
|
|
33
|
+
metadata?: Record<string, string>
|
|
34
|
+
): Promise<T>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Set the workspace context for subsequent requests
|
|
38
|
+
*/
|
|
39
|
+
setWorkspaceId(workspaceId: string | null): void;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get the current workspace ID
|
|
43
|
+
*/
|
|
44
|
+
getWorkspaceId(): string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Base configuration shared by all adapters
|
|
49
|
+
*/
|
|
50
|
+
export interface AdapterConfig {
|
|
51
|
+
/**
|
|
52
|
+
* Workspace ID for scoping requests
|
|
53
|
+
*/
|
|
54
|
+
workspaceId?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Callback when authentication fails
|
|
58
|
+
*/
|
|
59
|
+
onAuthError?: () => void;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Custom headers to include in all requests
|
|
63
|
+
*/
|
|
64
|
+
defaultHeaders?: Record<string, string>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Standard API response format from Instance API
|
|
69
|
+
*/
|
|
70
|
+
export interface ApiResponse<T> {
|
|
71
|
+
success: boolean;
|
|
72
|
+
data?: T;
|
|
73
|
+
error?: {
|
|
74
|
+
code: string;
|
|
75
|
+
message: string;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Paginated response format
|
|
81
|
+
*/
|
|
82
|
+
export interface PaginatedResponse<T> {
|
|
83
|
+
items: T[];
|
|
84
|
+
total: number;
|
|
85
|
+
page: number;
|
|
86
|
+
pageSize: number;
|
|
87
|
+
totalPages: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Error thrown by adapters
|
|
92
|
+
*/
|
|
93
|
+
export class AdapterError extends Error {
|
|
94
|
+
constructor(
|
|
95
|
+
message: string,
|
|
96
|
+
public code: string,
|
|
97
|
+
public statusCode?: number
|
|
98
|
+
) {
|
|
99
|
+
super(message);
|
|
100
|
+
this.name = 'AdapterError';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
package/src/index.ts
CHANGED
|
@@ -1,70 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tapstack/db - Tapstack Database Client
|
|
3
|
+
*
|
|
4
|
+
* A client for interacting with the Tapstack API at api.tapstack.com.
|
|
5
|
+
* Provides typed access to objects, fields, records, and more.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Export all types
|
|
1
9
|
export * from './types';
|
|
2
|
-
export * from './modules/objects';
|
|
3
|
-
export * from './modules/fields';
|
|
4
|
-
export * from './modules/records';
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
// Export adapters
|
|
12
|
+
export * from './adapters';
|
|
13
|
+
|
|
14
|
+
// Export modules
|
|
15
|
+
export * from './modules';
|
|
16
|
+
|
|
17
|
+
// Import for client class
|
|
18
|
+
import { IInstanceAdapter } from './adapters/types';
|
|
19
|
+
import { NodeJSAdapter, NodeJSAdapterConfig } from './adapters/nodejs.adapter';
|
|
8
20
|
import { ObjectModule } from './modules/objects';
|
|
9
21
|
import { FieldModule } from './modules/fields';
|
|
10
22
|
import { RecordModule } from './modules/records';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
23
|
+
import { OrganizationModule } from './modules/organizations';
|
|
24
|
+
import { WorkspaceModule } from './modules/workspaces';
|
|
25
|
+
import { FileModule } from './modules/files';
|
|
26
|
+
import { AutomationModule } from './modules/automations';
|
|
27
|
+
import { ConversationModule } from './modules/conversations';
|
|
14
28
|
|
|
15
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Main Tapstack Database Client
|
|
31
|
+
* Uses an adapter to communicate with the Tapstack API
|
|
32
|
+
*/
|
|
33
|
+
export class TapstackDBClient {
|
|
16
34
|
readonly objects: ObjectModule;
|
|
17
35
|
readonly fields: FieldModule;
|
|
18
36
|
readonly records: RecordModule;
|
|
37
|
+
readonly organizations: OrganizationModule;
|
|
38
|
+
readonly workspaces: WorkspaceModule;
|
|
39
|
+
readonly files: FileModule;
|
|
40
|
+
readonly automations: AutomationModule;
|
|
41
|
+
readonly conversations: ConversationModule;
|
|
19
42
|
|
|
20
|
-
|
|
21
|
-
super(config);
|
|
22
|
-
this.objects = new ObjectModule(this.client);
|
|
23
|
-
this.fields = new FieldModule(this.client);
|
|
24
|
-
this.records = new RecordModule(this.client);
|
|
25
|
-
}
|
|
43
|
+
private adapter: IInstanceAdapter;
|
|
26
44
|
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
constructor(adapter: IInstanceAdapter) {
|
|
46
|
+
this.adapter = adapter;
|
|
47
|
+
this.objects = new ObjectModule(adapter);
|
|
48
|
+
this.fields = new FieldModule(adapter);
|
|
49
|
+
this.records = new RecordModule(adapter);
|
|
50
|
+
this.organizations = new OrganizationModule(adapter);
|
|
51
|
+
this.workspaces = new WorkspaceModule(adapter);
|
|
52
|
+
this.files = new FileModule(adapter);
|
|
53
|
+
this.automations = new AutomationModule(adapter);
|
|
54
|
+
this.conversations = new ConversationModule(adapter);
|
|
29
55
|
}
|
|
30
56
|
|
|
31
|
-
|
|
32
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Set the workspace context for all subsequent requests
|
|
59
|
+
*/
|
|
60
|
+
setWorkspaceId(workspaceId: string | null): void {
|
|
61
|
+
this.adapter.setWorkspaceId(workspaceId);
|
|
33
62
|
}
|
|
34
63
|
|
|
35
|
-
|
|
36
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Get the current workspace ID
|
|
66
|
+
*/
|
|
67
|
+
getWorkspaceId(): string | null {
|
|
68
|
+
return this.adapter.getWorkspaceId();
|
|
37
69
|
}
|
|
38
70
|
|
|
39
|
-
|
|
40
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Get the underlying adapter (for advanced use cases)
|
|
73
|
+
*/
|
|
74
|
+
getAdapter(): IInstanceAdapter {
|
|
75
|
+
return this.adapter;
|
|
41
76
|
}
|
|
77
|
+
}
|
|
42
78
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Client configuration options
|
|
81
|
+
*/
|
|
82
|
+
export type TapstackClientConfig = NodeJSAdapterConfig;
|
|
46
83
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Create a Tapstack API client
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* // With API key authentication
|
|
90
|
+
* const client = createClient({
|
|
91
|
+
* apiKey: 'your-api-key',
|
|
92
|
+
* workspaceId: 'ws-123',
|
|
93
|
+
* });
|
|
94
|
+
*
|
|
95
|
+
* // With user token (for frontend apps)
|
|
96
|
+
* const client = createClient({
|
|
97
|
+
* getUserToken: async () => accessToken,
|
|
98
|
+
* workspaceId: 'ws-123',
|
|
99
|
+
* });
|
|
100
|
+
*
|
|
101
|
+
* // With custom base URL
|
|
102
|
+
* const client = createClient({
|
|
103
|
+
* baseUrl: 'https://custom-api.example.com',
|
|
104
|
+
* apiKey: 'your-api-key',
|
|
105
|
+
* });
|
|
106
|
+
*
|
|
107
|
+
* // Usage
|
|
108
|
+
* const objects = await client.objects.list();
|
|
109
|
+
* const records = await client.records.list('contacts');
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function createClient(config: TapstackClientConfig): TapstackDBClient {
|
|
113
|
+
const adapter = new NodeJSAdapter(config);
|
|
114
|
+
return new TapstackDBClient(adapter);
|
|
115
|
+
}
|
|
50
116
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Create a client with a custom adapter
|
|
119
|
+
* Use this for advanced scenarios or custom backends
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* class CustomAdapter implements IInstanceAdapter {
|
|
124
|
+
* // ... implementation
|
|
125
|
+
* }
|
|
126
|
+
*
|
|
127
|
+
* const client = createCustomClient(new CustomAdapter());
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function createCustomClient(adapter: IInstanceAdapter): TapstackDBClient {
|
|
131
|
+
return new TapstackDBClient(adapter);
|
|
132
|
+
}
|
|
54
133
|
|
|
55
|
-
|
|
56
|
-
return this.client.post(`/system/${slug}/fields`, data);
|
|
57
|
-
}
|
|
134
|
+
// ==================== Legacy Exports (for backwards compatibility) ====================
|
|
58
135
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
136
|
+
/**
|
|
137
|
+
* @deprecated Use createClient instead
|
|
138
|
+
*/
|
|
139
|
+
export const createNodeJSClient = createClient;
|
|
62
140
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
141
|
+
/**
|
|
142
|
+
* @deprecated Use TapstackClientConfig instead
|
|
143
|
+
*/
|
|
144
|
+
export interface TapstackDBClientConfig {
|
|
145
|
+
baseURL: string;
|
|
146
|
+
apiKey: string;
|
|
147
|
+
}
|
|
66
148
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
149
|
+
/**
|
|
150
|
+
* @deprecated Use createClient instead
|
|
151
|
+
*/
|
|
152
|
+
export function createLegacyClient(config: TapstackDBClientConfig): TapstackDBClient {
|
|
153
|
+
const adapter = new NodeJSAdapter({
|
|
154
|
+
baseUrl: config.baseURL.replace('/api', ''),
|
|
155
|
+
apiKey: config.apiKey,
|
|
156
|
+
});
|
|
157
|
+
return new TapstackDBClient(adapter);
|
|
70
158
|
}
|