@stagware/nocodb-sdk 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1640 @@
1
+ // src/index.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { ofetch, FetchError } from "ofetch";
5
+
6
+ // src/errors.ts
7
+ var NocoDBError = class extends Error {
8
+ /**
9
+ * Creates a new NocoDBError instance.
10
+ *
11
+ * @param message - Human-readable error message
12
+ * @param code - Machine-readable error code for programmatic handling
13
+ * @param statusCode - HTTP status code if applicable
14
+ * @param data - Additional error data (e.g., response body, validation details)
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * throw new NocoDBError('Operation failed', 'OPERATION_FAILED', 500, { details: 'Server error' });
19
+ * ```
20
+ */
21
+ constructor(message, code, statusCode, data) {
22
+ super(message);
23
+ this.code = code;
24
+ this.statusCode = statusCode;
25
+ this.data = data;
26
+ this.name = "NocoDBError";
27
+ }
28
+ };
29
+ var NetworkError = class extends NocoDBError {
30
+ /**
31
+ * Creates a new NetworkError instance.
32
+ *
33
+ * @param message - Human-readable error message
34
+ * @param cause - The underlying error that caused this network error
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * try {
39
+ * await fetch('https://api.example.com');
40
+ * } catch (err) {
41
+ * throw new NetworkError('Failed to connect to server', err);
42
+ * }
43
+ * ```
44
+ */
45
+ constructor(message, cause) {
46
+ super(message, "NETWORK_ERROR");
47
+ this.cause = cause;
48
+ }
49
+ };
50
+ var AuthenticationError = class extends NocoDBError {
51
+ /**
52
+ * Creates a new AuthenticationError instance.
53
+ *
54
+ * @param message - Human-readable error message
55
+ * @param statusCode - HTTP status code (typically 401 or 403)
56
+ * @param data - Additional error data from the server response
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * throw new AuthenticationError('Invalid API token', 401, { error: 'Token expired' });
61
+ * ```
62
+ */
63
+ constructor(message, statusCode, data) {
64
+ super(message, "AUTH_ERROR", statusCode, data);
65
+ }
66
+ };
67
+ var ValidationError = class extends NocoDBError {
68
+ /**
69
+ * Creates a new ValidationError instance.
70
+ *
71
+ * @param message - Human-readable error message
72
+ * @param fieldErrors - Optional map of field names to validation error messages
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * throw new ValidationError('Invalid request data', {
77
+ * email: ['Must be a valid email address'],
78
+ * age: ['Must be a positive number']
79
+ * });
80
+ * ```
81
+ */
82
+ constructor(message, fieldErrors) {
83
+ super(message, "VALIDATION_ERROR", 400);
84
+ this.fieldErrors = fieldErrors;
85
+ }
86
+ };
87
+ var NotFoundError = class extends NocoDBError {
88
+ /**
89
+ * Creates a new NotFoundError instance.
90
+ *
91
+ * @param resource - The type of resource that was not found (e.g., 'Base', 'Table', 'Row')
92
+ * @param id - The identifier of the resource that was not found
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * throw new NotFoundError('Table', 'tbl_abc123');
97
+ * // Error message: "Table not found: tbl_abc123"
98
+ * ```
99
+ */
100
+ constructor(resource, id) {
101
+ super(`${resource} not found: ${id}`, "NOT_FOUND", 404);
102
+ }
103
+ };
104
+ var ConflictError = class extends NocoDBError {
105
+ /**
106
+ * Creates a new ConflictError instance.
107
+ *
108
+ * @param message - Human-readable error message
109
+ * @param data - Additional error data from the server response
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * throw new ConflictError('Row already exists with this unique key', { key: 'email', value: 'user@example.com' });
114
+ * ```
115
+ */
116
+ constructor(message, data) {
117
+ super(message, "CONFLICT", 409, data);
118
+ }
119
+ };
120
+
121
+ // src/index.ts
122
+ var NocoClient = class {
123
+ baseUrl;
124
+ headers;
125
+ timeoutMs;
126
+ retryOptions;
127
+ /**
128
+ * Creates a new NocoClient instance.
129
+ *
130
+ * @param options - Client configuration options
131
+ */
132
+ constructor(options) {
133
+ this.baseUrl = normalizeBaseUrl(options.baseUrl);
134
+ this.headers = { ...options.headers ?? {} };
135
+ this.timeoutMs = options.timeoutMs;
136
+ this.retryOptions = options.retry;
137
+ }
138
+ /**
139
+ * Sets a default header that will be included in all requests.
140
+ *
141
+ * @param name - Header name
142
+ * @param value - Header value
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * client.setHeader('xc-token', 'new-api-token');
147
+ * ```
148
+ */
149
+ setHeader(name, value) {
150
+ this.headers[name] = value;
151
+ }
152
+ /**
153
+ * Removes a default header.
154
+ *
155
+ * @param name - Header name to remove
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * client.removeHeader('xc-token');
160
+ * ```
161
+ */
162
+ removeHeader(name) {
163
+ delete this.headers[name];
164
+ }
165
+ /**
166
+ * Makes an HTTP request to the NocoDB API.
167
+ *
168
+ * Automatically handles error mapping, retry logic, and timeout handling.
169
+ * Throws typed errors (AuthenticationError, NotFoundError, etc.) based on
170
+ * HTTP status codes.
171
+ *
172
+ * @template T - Expected response type
173
+ * @param method - HTTP method (GET, POST, PATCH, DELETE, etc.)
174
+ * @param path - API endpoint path (e.g., '/api/v2/meta/bases')
175
+ * @param options - Request options (headers, query params, body, etc.)
176
+ * @returns Promise resolving to the typed response
177
+ * @throws {AuthenticationError} When authentication fails (401, 403)
178
+ * @throws {NotFoundError} When resource is not found (404)
179
+ * @throws {ConflictError} When a conflict occurs (409)
180
+ * @throws {ValidationError} When request validation fails (400)
181
+ * @throws {NetworkError} For network-level errors or other HTTP errors
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const bases = await client.request<ListResponse<Base>>(
186
+ * 'GET',
187
+ * '/api/v2/meta/bases'
188
+ * );
189
+ *
190
+ * const newBase = await client.request<Base>(
191
+ * 'POST',
192
+ * '/api/v2/meta/bases',
193
+ * { body: { title: 'My Base' } }
194
+ * );
195
+ * ```
196
+ */
197
+ async request(method, path2, options = {}) {
198
+ const urlPath = path2.startsWith("/") ? path2 : `/${path2}`;
199
+ const headers = { ...this.headers, ...options.headers ?? {} };
200
+ const retry = options.retry ?? this.retryOptions;
201
+ const isVerbose = process.argv.includes("--verbose");
202
+ let attemptCount = 0;
203
+ const startTime = Date.now();
204
+ try {
205
+ const result = await ofetch(urlPath, {
206
+ baseURL: this.baseUrl,
207
+ method,
208
+ headers,
209
+ query: options.query,
210
+ body: options.body,
211
+ timeout: options.timeoutMs ?? this.timeoutMs,
212
+ retry: retry?.retry,
213
+ retryDelay: retry?.retryDelay,
214
+ retryStatusCodes: retry?.retryStatusCodes,
215
+ onRequest: () => {
216
+ attemptCount++;
217
+ if (isVerbose && attemptCount > 1) {
218
+ console.error(`[Retry] Attempt ${attemptCount} for ${method} ${urlPath}`);
219
+ }
220
+ }
221
+ });
222
+ if (isVerbose) {
223
+ const duration = Date.now() - startTime;
224
+ console.error(`[Timing] ${method} ${urlPath} completed in ${duration}ms`);
225
+ }
226
+ return result;
227
+ } catch (error) {
228
+ if (isVerbose) {
229
+ const duration = Date.now() - startTime;
230
+ console.error(`[Timing] ${method} ${urlPath} failed after ${duration}ms`);
231
+ if (attemptCount > 1) {
232
+ console.error(`[Retry] All ${attemptCount} attempts failed for ${method} ${urlPath}`);
233
+ }
234
+ }
235
+ if (error instanceof FetchError) {
236
+ const statusCode = error.response?.status;
237
+ const responseData = error.data;
238
+ const errorMessage = responseData?.msg || responseData?.message || responseData?.error || error.message || "Request failed";
239
+ if (statusCode === 401 || statusCode === 403) {
240
+ throw new AuthenticationError(errorMessage, statusCode, responseData);
241
+ }
242
+ if (statusCode === 404) {
243
+ throw new NotFoundError("Resource", errorMessage);
244
+ }
245
+ if (statusCode === 409) {
246
+ throw new ConflictError(errorMessage, responseData);
247
+ }
248
+ if (statusCode === 400) {
249
+ throw new ValidationError(errorMessage);
250
+ }
251
+ throw new NetworkError(
252
+ `HTTP ${statusCode}: ${errorMessage}`,
253
+ error
254
+ );
255
+ }
256
+ if (error instanceof Error) {
257
+ throw new NetworkError(error.message, error);
258
+ }
259
+ throw new NetworkError("Unknown error occurred", error);
260
+ }
261
+ }
262
+ /**
263
+ * Fetches all pages of a paginated list endpoint and returns the combined results.
264
+ *
265
+ * Automatically handles offset-based pagination by making sequential requests
266
+ * until all rows are retrieved. Useful for large datasets where a single request
267
+ * would only return a partial result.
268
+ *
269
+ * @template T - The type of items in the list
270
+ * @param method - HTTP method (typically 'GET')
271
+ * @param path - API endpoint path
272
+ * @param options - Request options (query params, headers, etc.)
273
+ * @param pageSize - Number of items per page (default: 1000)
274
+ * @returns Promise resolving to a ListResponse containing all items
275
+ *
276
+ * @example
277
+ * ```typescript
278
+ * // Fetch all rows from a table
279
+ * const allRows = await client.fetchAllPages<Row>(
280
+ * 'GET',
281
+ * '/api/v2/tables/tbl123/records'
282
+ * );
283
+ * console.log(`Total: ${allRows.list.length} rows`);
284
+ *
285
+ * // Fetch all with a filter
286
+ * const filtered = await client.fetchAllPages<Row>(
287
+ * 'GET',
288
+ * '/api/v2/tables/tbl123/records',
289
+ * { query: { where: '(Status,eq,Active)' } }
290
+ * );
291
+ * ```
292
+ */
293
+ async fetchAllPages(method, path2, options = {}, pageSize = 1e3) {
294
+ const first = await this.request(method, path2, {
295
+ ...options,
296
+ query: { ...options.query, limit: pageSize, offset: 0 }
297
+ });
298
+ const totalRows = first.pageInfo?.totalRows ?? 0;
299
+ if (first.list.length === 0 || first.list.length >= totalRows || first.list.length < pageSize) {
300
+ return first;
301
+ }
302
+ const allItems = [...first.list];
303
+ let offset = first.list.length;
304
+ while (offset < totalRows) {
305
+ const page = await this.request(method, path2, {
306
+ ...options,
307
+ query: { ...options.query, limit: pageSize, offset }
308
+ });
309
+ if (page.list.length === 0) break;
310
+ allItems.push(...page.list);
311
+ offset += page.list.length;
312
+ }
313
+ return {
314
+ list: allItems,
315
+ pageInfo: {
316
+ totalRows: allItems.length,
317
+ page: 1,
318
+ pageSize: allItems.length,
319
+ isFirstPage: true,
320
+ isLastPage: true
321
+ }
322
+ };
323
+ }
324
+ };
325
+ var MetaApi = class {
326
+ /**
327
+ * Creates a new MetaApi instance.
328
+ *
329
+ * @param client - NocoClient instance for making HTTP requests
330
+ */
331
+ constructor(client) {
332
+ this.client = client;
333
+ }
334
+ /**
335
+ * Lists all bases accessible to the authenticated user.
336
+ *
337
+ * @returns Promise resolving to paginated list of bases
338
+ * @throws {AuthenticationError} If authentication fails
339
+ * @throws {NetworkError} If the request fails
340
+ *
341
+ * @example
342
+ * ```typescript
343
+ * const response = await metaApi.listBases();
344
+ * console.log(`Found ${response.pageInfo.totalRows} bases`);
345
+ * ```
346
+ */
347
+ listBases() {
348
+ return this.client.request("GET", "/api/v2/meta/bases");
349
+ }
350
+ /**
351
+ * Creates a new base.
352
+ *
353
+ * @param body - Base properties (title is required)
354
+ * @returns Promise resolving to the created base
355
+ * @throws {ValidationError} If the request data is invalid
356
+ * @throws {AuthenticationError} If authentication fails
357
+ *
358
+ * @example
359
+ * ```typescript
360
+ * const base = await metaApi.createBase({ title: 'My Project' });
361
+ * console.log(`Created base: ${base.id}`);
362
+ * ```
363
+ */
364
+ createBase(body) {
365
+ return this.client.request("POST", "/api/v2/meta/bases", { body });
366
+ }
367
+ /**
368
+ * Gets detailed information about a specific base.
369
+ *
370
+ * @param baseId - ID of the base to retrieve
371
+ * @returns Promise resolving to the base details
372
+ * @throws {NotFoundError} If the base doesn't exist
373
+ * @throws {AuthenticationError} If authentication fails
374
+ *
375
+ * @example
376
+ * ```typescript
377
+ * const base = await metaApi.getBase('base_abc123');
378
+ * console.log(`Base title: ${base.title}`);
379
+ * ```
380
+ */
381
+ getBase(baseId) {
382
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}`);
383
+ }
384
+ /**
385
+ * Gets base information including metadata.
386
+ *
387
+ * @param baseId - ID of the base
388
+ * @returns Promise resolving to the base info
389
+ * @throws {NotFoundError} If the base doesn't exist
390
+ *
391
+ * @example
392
+ * ```typescript
393
+ * const info = await metaApi.getBaseInfo('base_abc123');
394
+ * ```
395
+ */
396
+ getBaseInfo(baseId) {
397
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/info`);
398
+ }
399
+ /**
400
+ * Updates a base's properties.
401
+ *
402
+ * @param baseId - ID of the base to update
403
+ * @param body - Properties to update
404
+ * @returns Promise resolving to the updated base
405
+ * @throws {NotFoundError} If the base doesn't exist
406
+ * @throws {ValidationError} If the update data is invalid
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * const updated = await metaApi.updateBase('base_abc123', { title: 'New Title' });
411
+ * ```
412
+ */
413
+ updateBase(baseId, body) {
414
+ return this.client.request("PATCH", `/api/v2/meta/bases/${baseId}`, { body });
415
+ }
416
+ /**
417
+ * Deletes a base permanently.
418
+ *
419
+ * @param baseId - ID of the base to delete
420
+ * @returns Promise that resolves when deletion is complete
421
+ * @throws {NotFoundError} If the base doesn't exist
422
+ * @throws {AuthenticationError} If authentication fails
423
+ *
424
+ * @example
425
+ * ```typescript
426
+ * await metaApi.deleteBase('base_abc123');
427
+ * console.log('Base deleted');
428
+ * ```
429
+ */
430
+ deleteBase(baseId) {
431
+ return this.client.request("DELETE", `/api/v2/meta/bases/${baseId}`);
432
+ }
433
+ // ── Sources (Data Sources) ─────────────────────────────────────────
434
+ /**
435
+ * Lists all data sources for a base.
436
+ *
437
+ * @param baseId - ID of the base
438
+ * @returns Promise resolving to paginated list of sources
439
+ * @throws {NotFoundError} If the base doesn't exist
440
+ */
441
+ listSources(baseId) {
442
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/sources`);
443
+ }
444
+ /**
445
+ * Creates a new data source in a base.
446
+ *
447
+ * @param baseId - ID of the base
448
+ * @param body - Source properties (alias, type, config, etc.)
449
+ * @returns Promise resolving to the created source
450
+ * @throws {ValidationError} If the request data is invalid
451
+ */
452
+ createSource(baseId, body) {
453
+ return this.client.request("POST", `/api/v2/meta/bases/${baseId}/sources`, { body });
454
+ }
455
+ /**
456
+ * Gets detailed information about a specific data source.
457
+ *
458
+ * @param baseId - ID of the base
459
+ * @param sourceId - ID of the source to retrieve
460
+ * @returns Promise resolving to the source details
461
+ * @throws {NotFoundError} If the source doesn't exist
462
+ */
463
+ getSource(baseId, sourceId) {
464
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/sources/${sourceId}`);
465
+ }
466
+ /**
467
+ * Updates a data source's properties.
468
+ *
469
+ * @param baseId - ID of the base
470
+ * @param sourceId - ID of the source to update
471
+ * @param body - Properties to update
472
+ * @returns Promise resolving to the updated source
473
+ * @throws {NotFoundError} If the source doesn't exist
474
+ */
475
+ updateSource(baseId, sourceId, body) {
476
+ return this.client.request("PATCH", `/api/v2/meta/bases/${baseId}/sources/${sourceId}`, { body });
477
+ }
478
+ /**
479
+ * Deletes a data source permanently.
480
+ *
481
+ * @param baseId - ID of the base
482
+ * @param sourceId - ID of the source to delete
483
+ * @returns Promise that resolves when deletion is complete
484
+ * @throws {NotFoundError} If the source doesn't exist
485
+ */
486
+ deleteSource(baseId, sourceId) {
487
+ return this.client.request("DELETE", `/api/v2/meta/bases/${baseId}/sources/${sourceId}`);
488
+ }
489
+ /**
490
+ * Lists all tables in a base.
491
+ *
492
+ * @param baseId - ID of the base
493
+ * @returns Promise resolving to paginated list of tables
494
+ * @throws {NotFoundError} If the base doesn't exist
495
+ *
496
+ * @example
497
+ * ```typescript
498
+ * const response = await metaApi.listTables('base_abc123');
499
+ * for (const table of response.list) {
500
+ * console.log(`Table: ${table.title}`);
501
+ * }
502
+ * ```
503
+ */
504
+ listTables(baseId) {
505
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/tables`);
506
+ }
507
+ /**
508
+ * Creates a new table in a base.
509
+ *
510
+ * @param baseId - ID of the base
511
+ * @param body - Table properties (title and table_name are required)
512
+ * @returns Promise resolving to the created table
513
+ * @throws {ValidationError} If the request data is invalid
514
+ * @throws {ConflictError} If a table with the same name already exists
515
+ *
516
+ * @example
517
+ * ```typescript
518
+ * const table = await metaApi.createTable('base_abc123', {
519
+ * title: 'Users',
520
+ * table_name: 'users'
521
+ * });
522
+ * ```
523
+ */
524
+ createTable(baseId, body) {
525
+ return this.client.request("POST", `/api/v2/meta/bases/${baseId}/tables`, { body });
526
+ }
527
+ /**
528
+ * Gets detailed information about a specific table.
529
+ *
530
+ * @param tableId - ID of the table to retrieve
531
+ * @returns Promise resolving to the table details including columns
532
+ * @throws {NotFoundError} If the table doesn't exist
533
+ *
534
+ * @example
535
+ * ```typescript
536
+ * const table = await metaApi.getTable('tbl_abc123');
537
+ * console.log(`Table has ${table.columns?.length} columns`);
538
+ * ```
539
+ */
540
+ getTable(tableId) {
541
+ return this.client.request("GET", `/api/v2/meta/tables/${tableId}`);
542
+ }
543
+ /**
544
+ * Updates a table's properties.
545
+ *
546
+ * @param tableId - ID of the table to update
547
+ * @param body - Properties to update
548
+ * @returns Promise resolving to the updated table
549
+ * @throws {NotFoundError} If the table doesn't exist
550
+ * @throws {ValidationError} If the update data is invalid
551
+ *
552
+ * @example
553
+ * ```typescript
554
+ * const updated = await metaApi.updateTable('tbl_abc123', { title: 'New Title' });
555
+ * ```
556
+ */
557
+ updateTable(tableId, body) {
558
+ return this.client.request("PATCH", `/api/v2/meta/tables/${tableId}`, { body });
559
+ }
560
+ /**
561
+ * Deletes a table permanently.
562
+ *
563
+ * @param tableId - ID of the table to delete
564
+ * @returns Promise that resolves when deletion is complete
565
+ * @throws {NotFoundError} If the table doesn't exist
566
+ *
567
+ * @example
568
+ * ```typescript
569
+ * await metaApi.deleteTable('tbl_abc123');
570
+ * ```
571
+ */
572
+ deleteTable(tableId) {
573
+ return this.client.request("DELETE", `/api/v2/meta/tables/${tableId}`);
574
+ }
575
+ /**
576
+ * Lists all views for a table.
577
+ *
578
+ * @param tableId - ID of the table
579
+ * @returns Promise resolving to paginated list of views
580
+ * @throws {NotFoundError} If the table doesn't exist
581
+ *
582
+ * @example
583
+ * ```typescript
584
+ * const response = await metaApi.listViews('tbl_abc123');
585
+ * for (const view of response.list) {
586
+ * console.log(`View: ${view.title} (${view.type})`);
587
+ * }
588
+ * ```
589
+ */
590
+ listViews(tableId) {
591
+ return this.client.request("GET", `/api/v2/meta/tables/${tableId}/views`);
592
+ }
593
+ /**
594
+ * Creates a new view for a table.
595
+ *
596
+ * @param tableId - ID of the table
597
+ * @param body - View properties (title and type are required)
598
+ * @returns Promise resolving to the created view
599
+ * @throws {ValidationError} If the request data is invalid
600
+ *
601
+ * @example
602
+ * ```typescript
603
+ * const view = await metaApi.createView('tbl_abc123', {
604
+ * title: 'Active Users',
605
+ * type: 'grid'
606
+ * });
607
+ * ```
608
+ */
609
+ createView(tableId, body) {
610
+ return this.client.request("POST", `/api/v2/meta/tables/${tableId}/views`, { body });
611
+ }
612
+ /**
613
+ * Gets detailed information about a specific view.
614
+ *
615
+ * @param viewId - ID of the view to retrieve
616
+ * @returns Promise resolving to the view details
617
+ * @throws {NotFoundError} If the view doesn't exist
618
+ *
619
+ * @example
620
+ * ```typescript
621
+ * const view = await metaApi.getView('vw_abc123');
622
+ * ```
623
+ */
624
+ getView(viewId) {
625
+ return this.client.request("GET", `/api/v2/meta/views/${viewId}`);
626
+ }
627
+ /**
628
+ * Updates a view's properties.
629
+ *
630
+ * @param viewId - ID of the view to update
631
+ * @param body - Properties to update
632
+ * @returns Promise resolving to the updated view
633
+ * @throws {NotFoundError} If the view doesn't exist
634
+ * @throws {ValidationError} If the update data is invalid
635
+ *
636
+ * @example
637
+ * ```typescript
638
+ * const updated = await metaApi.updateView('vw_abc123', { title: 'New Title' });
639
+ * ```
640
+ */
641
+ updateView(viewId, body) {
642
+ return this.client.request("PATCH", `/api/v2/meta/views/${viewId}`, { body });
643
+ }
644
+ /**
645
+ * Deletes a view permanently.
646
+ *
647
+ * @param viewId - ID of the view to delete
648
+ * @returns Promise that resolves when deletion is complete
649
+ * @throws {NotFoundError} If the view doesn't exist
650
+ *
651
+ * @example
652
+ * ```typescript
653
+ * await metaApi.deleteView('vw_abc123');
654
+ * ```
655
+ */
656
+ deleteView(viewId) {
657
+ return this.client.request("DELETE", `/api/v2/meta/views/${viewId}`);
658
+ }
659
+ /**
660
+ * Lists all filters for a view.
661
+ *
662
+ * @param viewId - ID of the view
663
+ * @returns Promise resolving to paginated list of filters
664
+ * @throws {NotFoundError} If the view doesn't exist
665
+ *
666
+ * @example
667
+ * ```typescript
668
+ * const response = await metaApi.listViewFilters('vw_abc123');
669
+ * ```
670
+ */
671
+ listViewFilters(viewId) {
672
+ return this.client.request("GET", `/api/v2/meta/views/${viewId}/filters`);
673
+ }
674
+ /**
675
+ * Creates a new filter for a view.
676
+ *
677
+ * @param viewId - ID of the view
678
+ * @param body - Filter properties
679
+ * @returns Promise resolving to the created filter
680
+ * @throws {ValidationError} If the request data is invalid
681
+ *
682
+ * @example
683
+ * ```typescript
684
+ * const filter = await metaApi.createViewFilter('vw_abc123', {
685
+ * fk_column_id: 'col_xyz',
686
+ * comparison_op: 'eq',
687
+ * value: 'active'
688
+ * });
689
+ * ```
690
+ */
691
+ createViewFilter(viewId, body) {
692
+ return this.client.request("POST", `/api/v2/meta/views/${viewId}/filters`, { body });
693
+ }
694
+ /**
695
+ * Gets detailed information about a specific filter.
696
+ *
697
+ * @param filterId - ID of the filter to retrieve
698
+ * @returns Promise resolving to the filter details
699
+ * @throws {NotFoundError} If the filter doesn't exist
700
+ *
701
+ * @example
702
+ * ```typescript
703
+ * const filter = await metaApi.getFilter('flt_abc123');
704
+ * ```
705
+ */
706
+ getFilter(filterId) {
707
+ return this.client.request("GET", `/api/v2/meta/filters/${filterId}`);
708
+ }
709
+ /**
710
+ * Updates a filter's properties.
711
+ *
712
+ * @param filterId - ID of the filter to update
713
+ * @param body - Properties to update
714
+ * @returns Promise resolving to the updated filter
715
+ * @throws {NotFoundError} If the filter doesn't exist
716
+ * @throws {ValidationError} If the update data is invalid
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * const updated = await metaApi.updateFilter('flt_abc123', { value: 'inactive' });
721
+ * ```
722
+ */
723
+ updateFilter(filterId, body) {
724
+ return this.client.request("PATCH", `/api/v2/meta/filters/${filterId}`, { body });
725
+ }
726
+ /**
727
+ * Deletes a filter permanently.
728
+ *
729
+ * @param filterId - ID of the filter to delete
730
+ * @returns Promise that resolves when deletion is complete
731
+ * @throws {NotFoundError} If the filter doesn't exist
732
+ *
733
+ * @example
734
+ * ```typescript
735
+ * await metaApi.deleteFilter('flt_abc123');
736
+ * ```
737
+ */
738
+ deleteFilter(filterId) {
739
+ return this.client.request("DELETE", `/api/v2/meta/filters/${filterId}`);
740
+ }
741
+ /**
742
+ * Lists all sorts for a view.
743
+ *
744
+ * @param viewId - ID of the view
745
+ * @returns Promise resolving to paginated list of sorts
746
+ * @throws {NotFoundError} If the view doesn't exist
747
+ *
748
+ * @example
749
+ * ```typescript
750
+ * const response = await metaApi.listViewSorts('vw_abc123');
751
+ * ```
752
+ */
753
+ listViewSorts(viewId) {
754
+ return this.client.request("GET", `/api/v2/meta/views/${viewId}/sorts`);
755
+ }
756
+ /**
757
+ * Creates a new sort for a view.
758
+ *
759
+ * @param viewId - ID of the view
760
+ * @param body - Sort properties (fk_column_id and direction are required)
761
+ * @returns Promise resolving to the created sort
762
+ * @throws {ValidationError} If the request data is invalid
763
+ *
764
+ * @example
765
+ * ```typescript
766
+ * const sort = await metaApi.createViewSort('vw_abc123', {
767
+ * fk_column_id: 'col_xyz',
768
+ * direction: 'asc'
769
+ * });
770
+ * ```
771
+ */
772
+ createViewSort(viewId, body) {
773
+ return this.client.request("POST", `/api/v2/meta/views/${viewId}/sorts`, { body });
774
+ }
775
+ /**
776
+ * Gets detailed information about a specific sort.
777
+ *
778
+ * @param sortId - ID of the sort to retrieve
779
+ * @returns Promise resolving to the sort details
780
+ * @throws {NotFoundError} If the sort doesn't exist
781
+ *
782
+ * @example
783
+ * ```typescript
784
+ * const sort = await metaApi.getSort('srt_abc123');
785
+ * ```
786
+ */
787
+ getSort(sortId) {
788
+ return this.client.request("GET", `/api/v2/meta/sorts/${sortId}`);
789
+ }
790
+ /**
791
+ * Updates a sort's properties.
792
+ *
793
+ * @param sortId - ID of the sort to update
794
+ * @param body - Properties to update
795
+ * @returns Promise resolving to the updated sort
796
+ * @throws {NotFoundError} If the sort doesn't exist
797
+ * @throws {ValidationError} If the update data is invalid
798
+ *
799
+ * @example
800
+ * ```typescript
801
+ * const updated = await metaApi.updateSort('srt_abc123', { direction: 'desc' });
802
+ * ```
803
+ */
804
+ updateSort(sortId, body) {
805
+ return this.client.request("PATCH", `/api/v2/meta/sorts/${sortId}`, { body });
806
+ }
807
+ /**
808
+ * Deletes a sort permanently.
809
+ *
810
+ * @param sortId - ID of the sort to delete
811
+ * @returns Promise that resolves when deletion is complete
812
+ * @throws {NotFoundError} If the sort doesn't exist
813
+ *
814
+ * @example
815
+ * ```typescript
816
+ * await metaApi.deleteSort('srt_abc123');
817
+ * ```
818
+ */
819
+ deleteSort(sortId) {
820
+ return this.client.request("DELETE", `/api/v2/meta/sorts/${sortId}`);
821
+ }
822
+ /**
823
+ * Lists all columns for a table.
824
+ *
825
+ * @param tableId - ID of the table
826
+ * @returns Promise resolving to paginated list of columns
827
+ * @throws {NotFoundError} If the table doesn't exist
828
+ *
829
+ * @example
830
+ * ```typescript
831
+ * const response = await metaApi.listColumns('tbl_abc123');
832
+ * for (const col of response.list) {
833
+ * console.log(`Column: ${col.title} (${col.uidt})`);
834
+ * }
835
+ * ```
836
+ */
837
+ listColumns(tableId) {
838
+ return this.client.request("GET", `/api/v2/meta/tables/${tableId}/columns`);
839
+ }
840
+ /**
841
+ * Creates a new column in a table.
842
+ *
843
+ * @param tableId - ID of the table
844
+ * @param body - Column properties (title, column_name, and uidt are required)
845
+ * @returns Promise resolving to the created column
846
+ * @throws {ValidationError} If the request data is invalid
847
+ * @throws {ConflictError} If a column with the same name already exists
848
+ *
849
+ * @example
850
+ * ```typescript
851
+ * const column = await metaApi.createColumn('tbl_abc123', {
852
+ * title: 'Email',
853
+ * column_name: 'email',
854
+ * uidt: 'Email'
855
+ * });
856
+ * ```
857
+ */
858
+ createColumn(tableId, body) {
859
+ return this.client.request("POST", `/api/v2/meta/tables/${tableId}/columns`, { body });
860
+ }
861
+ /**
862
+ * Gets detailed information about a specific column.
863
+ *
864
+ * @param columnId - ID of the column to retrieve
865
+ * @returns Promise resolving to the column details
866
+ * @throws {NotFoundError} If the column doesn't exist
867
+ *
868
+ * @example
869
+ * ```typescript
870
+ * const column = await metaApi.getColumn('col_abc123');
871
+ * ```
872
+ */
873
+ getColumn(columnId) {
874
+ return this.client.request("GET", `/api/v2/meta/columns/${columnId}`);
875
+ }
876
+ /**
877
+ * Updates a column's properties.
878
+ *
879
+ * @param columnId - ID of the column to update
880
+ * @param body - Properties to update
881
+ * @returns Promise resolving to the updated column
882
+ * @throws {NotFoundError} If the column doesn't exist
883
+ * @throws {ValidationError} If the update data is invalid
884
+ *
885
+ * @example
886
+ * ```typescript
887
+ * const updated = await metaApi.updateColumn('col_abc123', { title: 'New Title' });
888
+ * ```
889
+ */
890
+ updateColumn(columnId, body) {
891
+ return this.client.request("PATCH", `/api/v2/meta/columns/${columnId}`, { body });
892
+ }
893
+ /**
894
+ * Deletes a column permanently.
895
+ *
896
+ * @param columnId - ID of the column to delete
897
+ * @returns Promise that resolves when deletion is complete
898
+ * @throws {NotFoundError} If the column doesn't exist
899
+ *
900
+ * @example
901
+ * ```typescript
902
+ * await metaApi.deleteColumn('col_abc123');
903
+ * ```
904
+ */
905
+ deleteColumn(columnId) {
906
+ return this.client.request("DELETE", `/api/v2/meta/columns/${columnId}`);
907
+ }
908
+ // ── Hooks (Webhooks) ──────────────────────────────────────────────
909
+ /**
910
+ * Lists all hooks for a table.
911
+ *
912
+ * @param tableId - ID of the table
913
+ * @returns Promise resolving to paginated list of hooks
914
+ * @throws {NotFoundError} If the table doesn't exist
915
+ */
916
+ listHooks(tableId) {
917
+ return this.client.request("GET", `/api/v2/meta/tables/${tableId}/hooks`);
918
+ }
919
+ /**
920
+ * Creates a new hook (webhook) for a table.
921
+ *
922
+ * @param tableId - ID of the table
923
+ * @param body - Hook properties
924
+ * @returns Promise resolving to the created hook
925
+ * @throws {ValidationError} If the request data is invalid
926
+ */
927
+ createHook(tableId, body) {
928
+ return this.client.request("POST", `/api/v2/meta/tables/${tableId}/hooks`, { body });
929
+ }
930
+ /**
931
+ * Gets detailed information about a specific hook.
932
+ *
933
+ * @param hookId - ID of the hook to retrieve
934
+ * @returns Promise resolving to the hook details
935
+ * @throws {NotFoundError} If the hook doesn't exist
936
+ */
937
+ getHook(hookId) {
938
+ return this.client.request("GET", `/api/v2/meta/hooks/${hookId}`);
939
+ }
940
+ /**
941
+ * Updates a hook's properties.
942
+ *
943
+ * @param hookId - ID of the hook to update
944
+ * @param body - Properties to update
945
+ * @returns Promise resolving to the updated hook
946
+ * @throws {NotFoundError} If the hook doesn't exist
947
+ */
948
+ updateHook(hookId, body) {
949
+ return this.client.request("PATCH", `/api/v2/meta/hooks/${hookId}`, { body });
950
+ }
951
+ /**
952
+ * Deletes a hook permanently.
953
+ *
954
+ * @param hookId - ID of the hook to delete
955
+ * @returns Promise that resolves when deletion is complete
956
+ * @throws {NotFoundError} If the hook doesn't exist
957
+ */
958
+ deleteHook(hookId) {
959
+ return this.client.request("DELETE", `/api/v2/meta/hooks/${hookId}`);
960
+ }
961
+ /**
962
+ * Tests a hook by triggering a sample notification.
963
+ *
964
+ * @param hookId - ID of the hook to test
965
+ * @param body - Optional test payload
966
+ * @returns Promise resolving to the test result
967
+ * @throws {NotFoundError} If the hook doesn't exist
968
+ */
969
+ testHook(hookId, body) {
970
+ return this.client.request("POST", `/api/v2/meta/hooks/${hookId}/test`, body ? { body } : {});
971
+ }
972
+ // ── API Tokens ────────────────────────────────────────────────────
973
+ /**
974
+ * Lists all API tokens for a base.
975
+ *
976
+ * @param baseId - ID of the base
977
+ * @returns Promise resolving to a list of API tokens
978
+ */
979
+ listTokens(baseId) {
980
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/api-tokens`);
981
+ }
982
+ /**
983
+ * Creates a new API token for a base.
984
+ *
985
+ * @param baseId - ID of the base
986
+ * @param body - Token properties (description is recommended)
987
+ * @returns Promise resolving to the created token (includes the token string)
988
+ */
989
+ createToken(baseId, body) {
990
+ return this.client.request("POST", `/api/v2/meta/bases/${baseId}/api-tokens`, { body });
991
+ }
992
+ /**
993
+ * Deletes an API token from a base.
994
+ *
995
+ * @param baseId - ID of the base
996
+ * @param tokenId - ID of the token to delete
997
+ * @returns Promise that resolves when deletion is complete
998
+ */
999
+ deleteToken(baseId, tokenId) {
1000
+ return this.client.request("DELETE", `/api/v2/meta/bases/${baseId}/api-tokens/${tokenId}`);
1001
+ }
1002
+ // ── Base Users (Collaborators) ────────────────────────────────────
1003
+ /**
1004
+ * Lists all users (collaborators) for a base.
1005
+ *
1006
+ * @param baseId - ID of the base
1007
+ * @returns Promise resolving to a list of base users
1008
+ * @throws {NotFoundError} If the base doesn't exist
1009
+ */
1010
+ listBaseUsers(baseId) {
1011
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/users`);
1012
+ }
1013
+ /**
1014
+ * Invites a user to a base.
1015
+ *
1016
+ * @param baseId - ID of the base
1017
+ * @param body - User properties (email and roles are required)
1018
+ * @returns Promise resolving to the invite result
1019
+ * @throws {ValidationError} If the request data is invalid
1020
+ */
1021
+ inviteBaseUser(baseId, body) {
1022
+ return this.client.request("POST", `/api/v2/meta/bases/${baseId}/users`, { body });
1023
+ }
1024
+ /**
1025
+ * Updates a user's role in a base.
1026
+ *
1027
+ * @param baseId - ID of the base
1028
+ * @param userId - ID of the user to update
1029
+ * @param body - Properties to update (typically roles)
1030
+ * @returns Promise resolving to the updated user
1031
+ */
1032
+ updateBaseUser(baseId, userId, body) {
1033
+ return this.client.request("PATCH", `/api/v2/meta/bases/${baseId}/users/${userId}`, { body });
1034
+ }
1035
+ /**
1036
+ * Removes a user from a base.
1037
+ *
1038
+ * @param baseId - ID of the base
1039
+ * @param userId - ID of the user to remove
1040
+ * @returns Promise that resolves when removal is complete
1041
+ */
1042
+ removeBaseUser(baseId, userId) {
1043
+ return this.client.request("DELETE", `/api/v2/meta/bases/${baseId}/users/${userId}`);
1044
+ }
1045
+ // ── Comments ─────────────────────────────────────────────────────
1046
+ /**
1047
+ * Lists comments for a specific row.
1048
+ *
1049
+ * @param tableId - ID of the table (fk_model_id)
1050
+ * @param rowId - ID of the row
1051
+ * @returns Promise resolving to a list of comments
1052
+ */
1053
+ listComments(tableId, rowId) {
1054
+ return this.client.request("GET", "/api/v2/meta/comments", {
1055
+ query: { fk_model_id: tableId, row_id: rowId }
1056
+ });
1057
+ }
1058
+ /**
1059
+ * Creates a comment on a row.
1060
+ *
1061
+ * @param body - Comment properties (fk_model_id, row_id, comment are required)
1062
+ * @returns Promise resolving to the created comment
1063
+ */
1064
+ createComment(body) {
1065
+ return this.client.request("POST", "/api/v2/meta/comments", { body });
1066
+ }
1067
+ /**
1068
+ * Updates a comment.
1069
+ *
1070
+ * @param commentId - ID of the comment to update
1071
+ * @param body - Properties to update (typically comment text)
1072
+ * @returns Promise resolving to the updated comment
1073
+ */
1074
+ updateComment(commentId, body) {
1075
+ return this.client.request("PATCH", `/api/v2/meta/comment/${commentId}`, { body });
1076
+ }
1077
+ /**
1078
+ * Deletes a comment.
1079
+ *
1080
+ * @param commentId - ID of the comment to delete
1081
+ * @returns Promise that resolves when deletion is complete
1082
+ */
1083
+ deleteComment(commentId) {
1084
+ return this.client.request("DELETE", `/api/v2/meta/comment/${commentId}`);
1085
+ }
1086
+ // ── Shared Views ────────────────────────────────────────────────
1087
+ /**
1088
+ * Lists shared views for a table.
1089
+ *
1090
+ * @param tableId - ID of the table
1091
+ * @returns Promise resolving to a list of shared views
1092
+ */
1093
+ listSharedViews(tableId) {
1094
+ return this.client.request("GET", `/api/v2/meta/tables/${tableId}/share`);
1095
+ }
1096
+ /**
1097
+ * Creates a shared view (public link) for a view.
1098
+ *
1099
+ * @param viewId - ID of the view to share
1100
+ * @param body - Optional shared view properties (password, meta)
1101
+ * @returns Promise resolving to the created shared view
1102
+ */
1103
+ createSharedView(viewId, body) {
1104
+ return this.client.request("POST", `/api/v2/meta/views/${viewId}/share`, body ? { body } : {});
1105
+ }
1106
+ /**
1107
+ * Updates a shared view's properties.
1108
+ *
1109
+ * @param viewId - ID of the view whose share to update
1110
+ * @param body - Properties to update (password, meta)
1111
+ * @returns Promise resolving to the updated shared view
1112
+ */
1113
+ updateSharedView(viewId, body) {
1114
+ return this.client.request("PATCH", `/api/v2/meta/views/${viewId}/share`, { body });
1115
+ }
1116
+ /**
1117
+ * Deletes a shared view (removes public link).
1118
+ *
1119
+ * @param viewId - ID of the view whose share to delete
1120
+ * @returns Promise that resolves when deletion is complete
1121
+ */
1122
+ deleteSharedView(viewId) {
1123
+ return this.client.request("DELETE", `/api/v2/meta/views/${viewId}/share`);
1124
+ }
1125
+ // ── Shared Base ─────────────────────────────────────────────────
1126
+ /**
1127
+ * Gets shared base info (uuid, url, roles).
1128
+ *
1129
+ * @param baseId - ID of the base
1130
+ * @returns Promise resolving to the shared base info
1131
+ */
1132
+ getSharedBase(baseId) {
1133
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/shared`);
1134
+ }
1135
+ /**
1136
+ * Creates a shared base (enables public sharing).
1137
+ *
1138
+ * @param baseId - ID of the base
1139
+ * @param body - Shared base properties (roles, password)
1140
+ * @returns Promise resolving to the created shared base
1141
+ */
1142
+ createSharedBase(baseId, body) {
1143
+ return this.client.request("POST", `/api/v2/meta/bases/${baseId}/shared`, body ? { body } : {});
1144
+ }
1145
+ /**
1146
+ * Updates a shared base's properties.
1147
+ *
1148
+ * @param baseId - ID of the base
1149
+ * @param body - Properties to update (roles, password)
1150
+ * @returns Promise resolving to the updated shared base
1151
+ */
1152
+ updateSharedBase(baseId, body) {
1153
+ return this.client.request("PATCH", `/api/v2/meta/bases/${baseId}/shared`, { body });
1154
+ }
1155
+ /**
1156
+ * Disables shared base (removes public sharing).
1157
+ *
1158
+ * @param baseId - ID of the base
1159
+ * @returns Promise that resolves when sharing is disabled
1160
+ */
1161
+ deleteSharedBase(baseId) {
1162
+ return this.client.request("DELETE", `/api/v2/meta/bases/${baseId}/shared`);
1163
+ }
1164
+ // ── View-Type-Specific Endpoints ────────────────────────────────
1165
+ /**
1166
+ * Creates a grid view for a table.
1167
+ *
1168
+ * @param tableId - ID of the table
1169
+ * @param body - View properties (title is required)
1170
+ * @returns Promise resolving to the created view
1171
+ */
1172
+ createGridView(tableId, body) {
1173
+ return this.client.request("POST", `/api/v2/meta/tables/${tableId}/grids`, { body });
1174
+ }
1175
+ /**
1176
+ * Creates a form view for a table.
1177
+ *
1178
+ * @param tableId - ID of the table
1179
+ * @param body - View properties (title is required)
1180
+ * @returns Promise resolving to the created view
1181
+ */
1182
+ createFormView(tableId, body) {
1183
+ return this.client.request("POST", `/api/v2/meta/tables/${tableId}/forms`, { body });
1184
+ }
1185
+ /**
1186
+ * Creates a gallery view for a table.
1187
+ *
1188
+ * @param tableId - ID of the table
1189
+ * @param body - View properties (title is required)
1190
+ * @returns Promise resolving to the created view
1191
+ */
1192
+ createGalleryView(tableId, body) {
1193
+ return this.client.request("POST", `/api/v2/meta/tables/${tableId}/galleries`, { body });
1194
+ }
1195
+ /**
1196
+ * Creates a kanban view for a table.
1197
+ *
1198
+ * @param tableId - ID of the table
1199
+ * @param body - View properties (title is required)
1200
+ * @returns Promise resolving to the created view
1201
+ */
1202
+ createKanbanView(tableId, body) {
1203
+ return this.client.request("POST", `/api/v2/meta/tables/${tableId}/kanbans`, { body });
1204
+ }
1205
+ /**
1206
+ * Gets form view-specific configuration.
1207
+ *
1208
+ * @param formViewId - ID of the form view
1209
+ * @returns Promise resolving to the form view config
1210
+ */
1211
+ getFormView(formViewId) {
1212
+ return this.client.request("GET", `/api/v2/meta/forms/${formViewId}`);
1213
+ }
1214
+ /**
1215
+ * Updates form view-specific configuration.
1216
+ *
1217
+ * @param formViewId - ID of the form view
1218
+ * @param body - Form-specific properties to update
1219
+ * @returns Promise resolving to the updated form view config
1220
+ */
1221
+ updateFormView(formViewId, body) {
1222
+ return this.client.request("PATCH", `/api/v2/meta/forms/${formViewId}`, { body });
1223
+ }
1224
+ /**
1225
+ * Gets gallery view-specific configuration.
1226
+ *
1227
+ * @param galleryViewId - ID of the gallery view
1228
+ * @returns Promise resolving to the gallery view config
1229
+ */
1230
+ getGalleryView(galleryViewId) {
1231
+ return this.client.request("GET", `/api/v2/meta/galleries/${galleryViewId}`);
1232
+ }
1233
+ /**
1234
+ * Updates gallery view-specific configuration.
1235
+ *
1236
+ * @param galleryViewId - ID of the gallery view
1237
+ * @param body - Gallery-specific properties to update
1238
+ * @returns Promise resolving to the updated gallery view config
1239
+ */
1240
+ updateGalleryView(galleryViewId, body) {
1241
+ return this.client.request("PATCH", `/api/v2/meta/galleries/${galleryViewId}`, { body });
1242
+ }
1243
+ /**
1244
+ * Gets kanban view-specific configuration.
1245
+ *
1246
+ * @param kanbanViewId - ID of the kanban view
1247
+ * @returns Promise resolving to the kanban view config
1248
+ */
1249
+ getKanbanView(kanbanViewId) {
1250
+ return this.client.request("GET", `/api/v2/meta/kanbans/${kanbanViewId}`);
1251
+ }
1252
+ /**
1253
+ * Updates kanban view-specific configuration.
1254
+ *
1255
+ * @param kanbanViewId - ID of the kanban view
1256
+ * @param body - Kanban-specific properties to update
1257
+ * @returns Promise resolving to the updated kanban view config
1258
+ */
1259
+ updateKanbanView(kanbanViewId, body) {
1260
+ return this.client.request("PATCH", `/api/v2/meta/kanbans/${kanbanViewId}`, { body });
1261
+ }
1262
+ /**
1263
+ * Updates grid view-specific configuration.
1264
+ *
1265
+ * @param gridViewId - ID of the grid view
1266
+ * @param body - Grid-specific properties to update
1267
+ * @returns Promise resolving to the updated grid view config
1268
+ */
1269
+ updateGridView(gridViewId, body) {
1270
+ return this.client.request("PATCH", `/api/v2/meta/grids/${gridViewId}`, { body });
1271
+ }
1272
+ /**
1273
+ * Lists columns for a view (field visibility/order settings).
1274
+ *
1275
+ * @param viewId - ID of the view
1276
+ * @returns Promise resolving to a list of view columns
1277
+ */
1278
+ listViewColumns(viewId) {
1279
+ return this.client.request("GET", `/api/v2/meta/views/${viewId}/columns`);
1280
+ }
1281
+ // ── Filter Children (Nested Filter Groups) ─────────────────────────
1282
+ /**
1283
+ * Lists child filters of a filter group.
1284
+ *
1285
+ * @param filterGroupId - ID of the parent filter group
1286
+ * @returns Promise resolving to a list of child filters
1287
+ */
1288
+ listFilterChildren(filterGroupId) {
1289
+ return this.client.request("GET", `/api/v2/meta/filters/${filterGroupId}/children`);
1290
+ }
1291
+ // ── Hook Filters ───────────────────────────────────────────────────
1292
+ /**
1293
+ * Lists filters for a hook (webhook).
1294
+ *
1295
+ * @param hookId - ID of the hook
1296
+ * @returns Promise resolving to a list of hook filters
1297
+ */
1298
+ listHookFilters(hookId) {
1299
+ return this.client.request("GET", `/api/v2/meta/hooks/${hookId}/filters`);
1300
+ }
1301
+ /**
1302
+ * Creates a filter for a hook (webhook).
1303
+ *
1304
+ * @param hookId - ID of the hook
1305
+ * @param body - Filter properties
1306
+ * @returns Promise resolving to the created filter
1307
+ */
1308
+ createHookFilter(hookId, body) {
1309
+ return this.client.request("POST", `/api/v2/meta/hooks/${hookId}/filters`, { body });
1310
+ }
1311
+ // ── Column: Set Primary ────────────────────────────────────────────
1312
+ /**
1313
+ * Sets a column as the primary/display column for its table.
1314
+ *
1315
+ * @param columnId - ID of the column to set as primary
1316
+ * @returns Promise resolving when the column is set as primary
1317
+ */
1318
+ setColumnPrimary(columnId) {
1319
+ return this.client.request("POST", `/api/v2/meta/columns/${columnId}/primary`);
1320
+ }
1321
+ // ── Duplicate Operations ───────────────────────────────────────────
1322
+ /**
1323
+ * Duplicates a base.
1324
+ *
1325
+ * @param baseId - ID of the base to duplicate
1326
+ * @param options - Optional duplicate options (excludeData, excludeViews, excludeHooks)
1327
+ * @returns Promise resolving to the duplicate operation result
1328
+ */
1329
+ duplicateBase(baseId, options) {
1330
+ return this.client.request("POST", `/api/v2/meta/duplicate/${baseId}`, options ? { body: { options } } : {});
1331
+ }
1332
+ /**
1333
+ * Duplicates a base source.
1334
+ *
1335
+ * @param baseId - ID of the base
1336
+ * @param sourceId - ID of the source to duplicate
1337
+ * @param options - Optional duplicate options
1338
+ * @returns Promise resolving to the duplicate operation result
1339
+ */
1340
+ duplicateSource(baseId, sourceId, options) {
1341
+ return this.client.request("POST", `/api/v2/meta/duplicate/${baseId}/${sourceId}`, options ? { body: { options } } : {});
1342
+ }
1343
+ /**
1344
+ * Duplicates a table within a base.
1345
+ *
1346
+ * @param baseId - ID of the base
1347
+ * @param tableId - ID of the table to duplicate
1348
+ * @param options - Optional duplicate options
1349
+ * @returns Promise resolving to the duplicate operation result
1350
+ */
1351
+ duplicateTable(baseId, tableId, options) {
1352
+ return this.client.request("POST", `/api/v2/meta/duplicate/${baseId}/table/${tableId}`, options ? { body: { options } } : {});
1353
+ }
1354
+ // ── Visibility Rules (UI ACL) ──────────────────────────────────────
1355
+ /**
1356
+ * Gets view visibility rules for a base (UI ACL).
1357
+ *
1358
+ * @param baseId - ID of the base
1359
+ * @returns Promise resolving to the visibility rules
1360
+ */
1361
+ getVisibilityRules(baseId) {
1362
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/visibility-rules`);
1363
+ }
1364
+ /**
1365
+ * Sets view visibility rules for a base (UI ACL).
1366
+ *
1367
+ * @param baseId - ID of the base
1368
+ * @param body - Visibility rules to set
1369
+ * @returns Promise resolving when rules are set
1370
+ */
1371
+ setVisibilityRules(baseId, body) {
1372
+ return this.client.request("POST", `/api/v2/meta/bases/${baseId}/visibility-rules`, { body });
1373
+ }
1374
+ // ── App Info ───────────────────────────────────────────────────────
1375
+ /**
1376
+ * Gets NocoDB server application info (version, etc.).
1377
+ *
1378
+ * @returns Promise resolving to the app info
1379
+ */
1380
+ getAppInfo() {
1381
+ return this.client.request("GET", "/api/v2/meta/nocodb/info");
1382
+ }
1383
+ // ── Cloud Workspaces (☁ cloud-only) ──────────────────────────────
1384
+ /**
1385
+ * Lists all workspaces (☁ cloud-only).
1386
+ *
1387
+ * @returns Promise resolving to paginated list of workspaces
1388
+ * @throws {NetworkError} If the instance doesn't support workspaces (self-hosted)
1389
+ */
1390
+ listWorkspaces() {
1391
+ return this.client.request("GET", "/api/v2/meta/workspaces");
1392
+ }
1393
+ /**
1394
+ * Gets a workspace by ID (☁ cloud-only).
1395
+ *
1396
+ * @param workspaceId - ID of the workspace
1397
+ * @returns Promise resolving to the workspace details and user count
1398
+ * @throws {NotFoundError} If the workspace doesn't exist
1399
+ */
1400
+ getWorkspace(workspaceId) {
1401
+ return this.client.request("GET", `/api/v2/meta/workspaces/${workspaceId}`);
1402
+ }
1403
+ /**
1404
+ * Creates a new workspace (☁ cloud-only).
1405
+ *
1406
+ * @param body - Workspace properties (title is required)
1407
+ * @returns Promise resolving to the created workspace
1408
+ * @throws {ValidationError} If the request data is invalid
1409
+ */
1410
+ createWorkspace(body) {
1411
+ return this.client.request("POST", "/api/v2/meta/workspaces", { body });
1412
+ }
1413
+ /**
1414
+ * Updates a workspace (☁ cloud-only).
1415
+ *
1416
+ * @param workspaceId - ID of the workspace to update
1417
+ * @param body - Properties to update
1418
+ * @returns Promise resolving when the update is complete
1419
+ */
1420
+ updateWorkspace(workspaceId, body) {
1421
+ return this.client.request("PATCH", `/api/v2/meta/workspaces/${workspaceId}`, { body });
1422
+ }
1423
+ /**
1424
+ * Deletes a workspace (☁ cloud-only).
1425
+ *
1426
+ * @param workspaceId - ID of the workspace to delete
1427
+ * @returns Promise resolving when deletion is complete
1428
+ */
1429
+ deleteWorkspace(workspaceId) {
1430
+ return this.client.request("DELETE", `/api/v2/meta/workspaces/${workspaceId}`);
1431
+ }
1432
+ /**
1433
+ * Lists users in a workspace (☁ cloud-only).
1434
+ *
1435
+ * @param workspaceId - ID of the workspace
1436
+ * @returns Promise resolving to a list of workspace users
1437
+ */
1438
+ listWorkspaceUsers(workspaceId) {
1439
+ return this.client.request("GET", `/api/v2/meta/workspaces/${workspaceId}/users`);
1440
+ }
1441
+ /**
1442
+ * Gets a specific user in a workspace (☁ cloud-only).
1443
+ *
1444
+ * @param workspaceId - ID of the workspace
1445
+ * @param userId - ID of the user
1446
+ * @returns Promise resolving to the workspace user details
1447
+ */
1448
+ getWorkspaceUser(workspaceId, userId) {
1449
+ return this.client.request("GET", `/api/v2/meta/workspaces/${workspaceId}/users/${userId}`);
1450
+ }
1451
+ /**
1452
+ * Invites a user to a workspace (☁ cloud-only).
1453
+ *
1454
+ * @param workspaceId - ID of the workspace
1455
+ * @param body - Invite properties (email and roles are required)
1456
+ * @returns Promise resolving to the invite result
1457
+ */
1458
+ inviteWorkspaceUser(workspaceId, body) {
1459
+ return this.client.request("POST", `/api/v2/meta/workspaces/${workspaceId}/invitations`, { body });
1460
+ }
1461
+ /**
1462
+ * Updates a user's role in a workspace (☁ cloud-only).
1463
+ *
1464
+ * @param workspaceId - ID of the workspace
1465
+ * @param userId - ID of the user to update
1466
+ * @param body - Properties to update (typically roles)
1467
+ * @returns Promise resolving when the update is complete
1468
+ */
1469
+ updateWorkspaceUser(workspaceId, userId, body) {
1470
+ return this.client.request("PATCH", `/api/v2/meta/workspaces/${workspaceId}/users/${userId}`, { body });
1471
+ }
1472
+ /**
1473
+ * Removes a user from a workspace (☁ cloud-only).
1474
+ *
1475
+ * @param workspaceId - ID of the workspace
1476
+ * @param userId - ID of the user to remove
1477
+ * @returns Promise resolving when removal is complete
1478
+ */
1479
+ deleteWorkspaceUser(workspaceId, userId) {
1480
+ return this.client.request("DELETE", `/api/v2/meta/workspaces/${workspaceId}/users/${userId}`);
1481
+ }
1482
+ /**
1483
+ * Lists bases in a workspace (☁ cloud-only).
1484
+ *
1485
+ * @param workspaceId - ID of the workspace
1486
+ * @returns Promise resolving to a paginated list of bases
1487
+ */
1488
+ listWorkspaceBases(workspaceId) {
1489
+ return this.client.request("GET", `/api/v2/meta/workspaces/${workspaceId}/bases`);
1490
+ }
1491
+ /**
1492
+ * Creates a base in a workspace (☁ cloud-only).
1493
+ *
1494
+ * @param workspaceId - ID of the workspace
1495
+ * @param body - Base properties (title is required)
1496
+ * @returns Promise resolving to the created base
1497
+ */
1498
+ createWorkspaceBase(workspaceId, body) {
1499
+ return this.client.request("POST", `/api/v2/meta/workspaces/${workspaceId}/bases`, { body });
1500
+ }
1501
+ /**
1502
+ * Gets the Swagger/OpenAPI specification for a base.
1503
+ *
1504
+ * Returns the complete API documentation for all tables and operations
1505
+ * in the specified base.
1506
+ *
1507
+ * @param baseId - ID of the base
1508
+ * @returns Promise resolving to the Swagger document
1509
+ * @throws {NotFoundError} If the base doesn't exist
1510
+ *
1511
+ * @example
1512
+ * ```typescript
1513
+ * const swagger = await metaApi.getBaseSwagger('base_abc123');
1514
+ * console.log(`API version: ${swagger.info.version}`);
1515
+ * ```
1516
+ */
1517
+ getBaseSwagger(baseId) {
1518
+ return this.client.request("GET", `/api/v2/meta/bases/${baseId}/swagger.json`);
1519
+ }
1520
+ /**
1521
+ * Uploads a file attachment.
1522
+ *
1523
+ * Uploads a file from the local filesystem to NocoDB storage.
1524
+ * The returned data can be used in attachment column fields.
1525
+ *
1526
+ * @param filePath - Path to the file to upload
1527
+ * @returns Promise resolving to upload response with file metadata
1528
+ * @throws {ValidationError} If the file doesn't exist or is invalid
1529
+ * @throws {NetworkError} If the upload fails
1530
+ *
1531
+ * @example
1532
+ * ```typescript
1533
+ * const result = await metaApi.uploadAttachment('/path/to/image.png');
1534
+ * // Use result in an attachment column
1535
+ * ```
1536
+ */
1537
+ async uploadAttachment(filePath) {
1538
+ const fileName = path.basename(filePath);
1539
+ const fileContent = await fs.promises.readFile(filePath);
1540
+ const boundary = `----nocodb-${Date.now()}`;
1541
+ const header = `--${boundary}\r
1542
+ Content-Disposition: form-data; name="file"; filename="${fileName}"\r
1543
+ Content-Type: application/octet-stream\r
1544
+ \r
1545
+ `;
1546
+ const footer = `\r
1547
+ --${boundary}--\r
1548
+ `;
1549
+ const body = Buffer.concat([Buffer.from(header), fileContent, Buffer.from(footer)]);
1550
+ return this.client.request("POST", "/api/v2/storage/upload", {
1551
+ body,
1552
+ headers: { "content-type": `multipart/form-data; boundary=${boundary}` }
1553
+ });
1554
+ }
1555
+ };
1556
+ var DataApi = class {
1557
+ constructor(client) {
1558
+ this.client = client;
1559
+ }
1560
+ /**
1561
+ * List linked records for a specific record and link field.
1562
+ *
1563
+ * @param tableId - ID of the table containing the record
1564
+ * @param linkFieldId - ID of the link field (column)
1565
+ * @param recordId - ID of the record to get links for
1566
+ * @param query - Optional query parameters for filtering/pagination
1567
+ * @returns Paginated list of linked rows
1568
+ *
1569
+ * @example
1570
+ * ```typescript
1571
+ * const links = await dataApi.listLinks('tbl123', 'col456', 'rec789');
1572
+ * console.log(`Found ${links.pageInfo.totalRows} linked records`);
1573
+ * ```
1574
+ */
1575
+ listLinks(tableId, linkFieldId, recordId, query) {
1576
+ return this.client.request("GET", `/api/v2/tables/${tableId}/links/${linkFieldId}/records/${recordId}`, { query });
1577
+ }
1578
+ /**
1579
+ * Link records together via a link field.
1580
+ *
1581
+ * @param tableId - ID of the table containing the record
1582
+ * @param linkFieldId - ID of the link field (column)
1583
+ * @param recordId - ID of the record to link from
1584
+ * @param body - Array of record IDs or objects to link
1585
+ * @returns Success response
1586
+ *
1587
+ * @example
1588
+ * ```typescript
1589
+ * await dataApi.linkRecords('tbl123', 'col456', 'rec789', [{ Id: 'rec999' }]);
1590
+ * ```
1591
+ */
1592
+ linkRecords(tableId, linkFieldId, recordId, body) {
1593
+ return this.client.request("POST", `/api/v2/tables/${tableId}/links/${linkFieldId}/records/${recordId}`, { body });
1594
+ }
1595
+ /**
1596
+ * Unlink records from a link field.
1597
+ *
1598
+ * @param tableId - ID of the table containing the record
1599
+ * @param linkFieldId - ID of the link field (column)
1600
+ * @param recordId - ID of the record to unlink from
1601
+ * @param body - Array of record IDs or objects to unlink
1602
+ * @returns Success response
1603
+ *
1604
+ * @example
1605
+ * ```typescript
1606
+ * await dataApi.unlinkRecords('tbl123', 'col456', 'rec789', [{ Id: 'rec999' }]);
1607
+ * ```
1608
+ */
1609
+ unlinkRecords(tableId, linkFieldId, recordId, body) {
1610
+ return this.client.request("DELETE", `/api/v2/tables/${tableId}/links/${linkFieldId}/records/${recordId}`, { body });
1611
+ }
1612
+ };
1613
+ function normalizeBaseUrl(input) {
1614
+ return input.replace(/\/+$/, "");
1615
+ }
1616
+ function parseHeader(input) {
1617
+ const idx = input.indexOf(":");
1618
+ if (idx === -1) {
1619
+ throw new Error(`Invalid header '${input}'. Use 'Name: Value'.`);
1620
+ }
1621
+ const name = input.slice(0, idx).trim();
1622
+ const value = input.slice(idx + 1).trim();
1623
+ if (!name || !value) {
1624
+ throw new Error(`Invalid header '${input}'. Use 'Name: Value'.`);
1625
+ }
1626
+ return [name, value];
1627
+ }
1628
+ export {
1629
+ AuthenticationError,
1630
+ ConflictError,
1631
+ DataApi,
1632
+ MetaApi,
1633
+ NetworkError,
1634
+ NocoClient,
1635
+ NocoDBError,
1636
+ NotFoundError,
1637
+ ValidationError,
1638
+ normalizeBaseUrl,
1639
+ parseHeader
1640
+ };