@objectql/sdk 1.8.0 → 1.8.2

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 CHANGED
@@ -1,6 +1,49 @@
1
1
  "use strict";
2
+ /**
3
+ * @objectql/sdk - Universal HTTP Client for ObjectQL
4
+ *
5
+ * This package provides type-safe HTTP clients for ObjectQL servers.
6
+ * It works seamlessly in browsers, Node.js, Deno, and edge runtimes.
7
+ *
8
+ * ## Browser Compatibility
9
+ *
10
+ * The SDK uses modern JavaScript APIs:
11
+ * - fetch API (universal)
12
+ * - AbortSignal.timeout() (Chrome 103+, Firefox 100+, Safari 16.4+)
13
+ *
14
+ * For older browsers, a polyfill is automatically applied if AbortSignal.timeout is not available.
15
+ *
16
+ * @packageDocumentation
17
+ */
2
18
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RemoteDriver = void 0;
19
+ exports.MetadataApiClient = exports.DataApiClient = exports.RemoteDriver = void 0;
20
+ const types_1 = require("@objectql/types");
21
+ /**
22
+ * Polyfill for AbortSignal.timeout if not available (for older browsers)
23
+ * This ensures the SDK works universally across all JavaScript environments.
24
+ */
25
+ if (typeof AbortSignal !== 'undefined' && !AbortSignal.timeout) {
26
+ AbortSignal.timeout = function (ms) {
27
+ const controller = new AbortController();
28
+ setTimeout(() => controller.abort(), ms);
29
+ return controller.signal;
30
+ };
31
+ }
32
+ /**
33
+ * Helper function to create a timeout signal that works in all environments
34
+ */
35
+ function createTimeoutSignal(ms) {
36
+ if (typeof AbortSignal !== 'undefined' && AbortSignal.timeout) {
37
+ return AbortSignal.timeout(ms);
38
+ }
39
+ // Fallback for environments without AbortSignal
40
+ const controller = new AbortController();
41
+ setTimeout(() => controller.abort(), ms);
42
+ return controller.signal;
43
+ }
44
+ /**
45
+ * Legacy Driver implementation that uses JSON-RPC style API
46
+ */
4
47
  class RemoteDriver {
5
48
  constructor(baseUrl) {
6
49
  this.baseUrl = baseUrl;
@@ -56,4 +99,175 @@ class RemoteDriver {
56
99
  }
57
100
  }
58
101
  exports.RemoteDriver = RemoteDriver;
102
+ /**
103
+ * REST-based Data API Client
104
+ *
105
+ * Implements type-safe client for ObjectQL Data API endpoints.
106
+ * Uses the RESTful interface described in docs/api/rest.md
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const client = new DataApiClient({ baseUrl: 'http://localhost:3000' });
111
+ *
112
+ * // List users
113
+ * const response = await client.list('users', {
114
+ * filter: [['status', '=', 'active']],
115
+ * sort: [['created_at', 'desc']],
116
+ * limit: 20
117
+ * });
118
+ *
119
+ * // Get single user
120
+ * const user = await client.get('users', 'user_123');
121
+ *
122
+ * // Create user
123
+ * const newUser = await client.create('users', {
124
+ * name: 'Alice',
125
+ * email: 'alice@example.com'
126
+ * });
127
+ * ```
128
+ */
129
+ class DataApiClient {
130
+ constructor(config) {
131
+ this.baseUrl = config.baseUrl.replace(/\/$/, '');
132
+ this.token = config.token;
133
+ this.headers = config.headers || {};
134
+ this.timeout = config.timeout || 30000;
135
+ }
136
+ async request(method, path, body, queryParams) {
137
+ const url = new URL(`${this.baseUrl}${path}`);
138
+ // Add query parameters
139
+ if (queryParams) {
140
+ Object.entries(queryParams).forEach(([key, value]) => {
141
+ if (value !== undefined && value !== null) {
142
+ url.searchParams.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value));
143
+ }
144
+ });
145
+ }
146
+ const headers = {
147
+ 'Content-Type': 'application/json',
148
+ ...this.headers
149
+ };
150
+ if (this.token) {
151
+ headers['Authorization'] = `Bearer ${this.token}`;
152
+ }
153
+ const response = await fetch(url.toString(), {
154
+ method,
155
+ headers,
156
+ body: body ? JSON.stringify(body) : undefined,
157
+ signal: createTimeoutSignal(this.timeout)
158
+ });
159
+ const json = await response.json();
160
+ if (json.error) {
161
+ throw new types_1.ObjectQLError({
162
+ code: json.error.code || types_1.ApiErrorCode.INTERNAL_ERROR,
163
+ message: json.error.message,
164
+ details: json.error.details
165
+ });
166
+ }
167
+ return json;
168
+ }
169
+ async list(objectName, params) {
170
+ return this.request('GET', `/api/data/${objectName}`, undefined, params);
171
+ }
172
+ async get(objectName, id) {
173
+ return this.request('GET', `/api/data/${objectName}/${id}`);
174
+ }
175
+ async create(objectName, data) {
176
+ return this.request('POST', `/api/data/${objectName}`, data);
177
+ }
178
+ async createMany(objectName, data) {
179
+ return this.request('POST', `/api/data/${objectName}`, data);
180
+ }
181
+ async update(objectName, id, data) {
182
+ return this.request('PUT', `/api/data/${objectName}/${id}`, data);
183
+ }
184
+ async updateMany(objectName, request) {
185
+ return this.request('POST', `/api/data/${objectName}/bulk-update`, request);
186
+ }
187
+ async delete(objectName, id) {
188
+ return this.request('DELETE', `/api/data/${objectName}/${id}`);
189
+ }
190
+ async deleteMany(objectName, request) {
191
+ return this.request('POST', `/api/data/${objectName}/bulk-delete`, request);
192
+ }
193
+ async count(objectName, filters) {
194
+ return this.request('GET', `/api/data/${objectName}`, undefined, { filter: filters, limit: 0 });
195
+ }
196
+ }
197
+ exports.DataApiClient = DataApiClient;
198
+ /**
199
+ * REST-based Metadata API Client
200
+ *
201
+ * Implements type-safe client for ObjectQL Metadata API endpoints.
202
+ * Uses the interface described in docs/api/metadata.md
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * const client = new MetadataApiClient({ baseUrl: 'http://localhost:3000' });
207
+ *
208
+ * // List all objects
209
+ * const objects = await client.listObjects();
210
+ *
211
+ * // Get detailed object metadata
212
+ * const userSchema = await client.getObject('users');
213
+ * console.log(userSchema.fields);
214
+ *
215
+ * // Get field metadata
216
+ * const emailField = await client.getField('users', 'email');
217
+ *
218
+ * // List actions
219
+ * const actions = await client.listActions('users');
220
+ * ```
221
+ */
222
+ class MetadataApiClient {
223
+ constructor(config) {
224
+ this.baseUrl = config.baseUrl.replace(/\/$/, '');
225
+ this.token = config.token;
226
+ this.headers = config.headers || {};
227
+ this.timeout = config.timeout || 30000;
228
+ }
229
+ async request(method, path, body) {
230
+ const headers = {
231
+ 'Content-Type': 'application/json',
232
+ ...this.headers
233
+ };
234
+ if (this.token) {
235
+ headers['Authorization'] = `Bearer ${this.token}`;
236
+ }
237
+ const response = await fetch(`${this.baseUrl}${path}`, {
238
+ method,
239
+ headers,
240
+ body: body ? JSON.stringify(body) : undefined,
241
+ signal: createTimeoutSignal(this.timeout)
242
+ });
243
+ const json = await response.json();
244
+ if (json.error) {
245
+ throw new types_1.ObjectQLError({
246
+ code: json.error.code || types_1.ApiErrorCode.INTERNAL_ERROR,
247
+ message: json.error.message,
248
+ details: json.error.details
249
+ });
250
+ }
251
+ return json;
252
+ }
253
+ async listObjects() {
254
+ return this.request('GET', '/api/metadata/objects');
255
+ }
256
+ async getObject(objectName) {
257
+ return this.request('GET', `/api/metadata/object/${objectName}`);
258
+ }
259
+ async getField(objectName, fieldName) {
260
+ return this.request('GET', `/api/metadata/object/${objectName}/fields/${fieldName}`);
261
+ }
262
+ async listActions(objectName) {
263
+ return this.request('GET', `/api/metadata/object/${objectName}/actions`);
264
+ }
265
+ async listByType(metadataType) {
266
+ return this.request('GET', `/api/metadata/${metadataType}`);
267
+ }
268
+ async getMetadata(metadataType, id) {
269
+ return this.request('GET', `/api/metadata/${metadataType}/${id}`);
270
+ }
271
+ }
272
+ exports.MetadataApiClient = MetadataApiClient;
59
273
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IACrB,YAAoB,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;IAAG,CAAC;IAE/B,KAAK,CAAC,OAAO,CAAC,EAAU,EAAE,UAAkB,EAAE,IAAS;QAC3D,iFAAiF;QACjF,2CAA2C;QAC3C,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC;QAEnE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YAC9B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACjB,EAAE;gBACF,MAAM,EAAE,UAAU;gBAClB,IAAI;aACP,CAAC;SACL,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAE9B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,KAAU,EAAE,OAAa;QACpD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,UAAkB,EAAE,EAAmB,EAAE,KAAW,EAAE,OAAa;QAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,kDAAkD;IACjH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAE,IAAS,EAAE,OAAa;QACrD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAE,EAAmB,EAAE,IAAS,EAAE,OAAa;QAC1E,8FAA8F;QAC9F,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAE,EAAmB,EAAE,OAAa;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB,EAAE,OAAY,EAAE,OAAa;QACvD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,IAAW,EAAE,OAAa;QAC3D,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,OAAY,EAAE,IAAS,EAAE,OAAa;QACvE,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB,EAAE,OAAY,EAAE,OAAa;QAC5D,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/D,CAAC;CACJ;AAjED,oCAiEC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/jest.config.js CHANGED
@@ -3,7 +3,9 @@ module.exports = {
3
3
  testEnvironment: 'node',
4
4
  testMatch: ['**/test/**/*.test.ts'],
5
5
  moduleNameMapper: {
6
- '^@objectql/(.*)$': '<rootDir>/../$1/src',
6
+ '^@objectql/types$': '<rootDir>/../../foundation/types/src',
7
+ '^@objectql/core$': '<rootDir>/../../foundation/core/src',
8
+ '^@objectql/platform-node$': '<rootDir>/../../foundation/platform-node/src',
7
9
  },
8
10
  transform: {
9
11
  '^.+\\.ts$': ['ts-jest', {
package/package.json CHANGED
@@ -1,16 +1,46 @@
1
1
  {
2
2
  "name": "@objectql/sdk",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
+ "description": "Remote HTTP driver for ObjectQL - Universal client for browser, Node.js, and edge runtimes",
5
+ "keywords": [
6
+ "objectql",
7
+ "sdk",
8
+ "driver",
9
+ "remote",
10
+ "http",
11
+ "client",
12
+ "browser",
13
+ "frontend",
14
+ "universal",
15
+ "api",
16
+ "rest",
17
+ "fetch",
18
+ "typescript",
19
+ "esm",
20
+ "react",
21
+ "vue",
22
+ "angular"
23
+ ],
4
24
  "license": "MIT",
5
- "description": "Remote/HTTP Driver for ObjectQL",
6
25
  "main": "dist/index.js",
7
26
  "types": "dist/index.d.ts",
27
+ "browser": "dist/index.js",
28
+ "sideEffects": false,
8
29
  "dependencies": {
9
- "@objectql/types": "1.8.0"
30
+ "@objectql/types": "1.8.2"
10
31
  },
11
32
  "devDependencies": {
12
33
  "typescript": "^5.3.0"
13
34
  },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/objectstack-ai/objectql.git",
38
+ "directory": "packages/drivers/sdk"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/objectstack-ai/objectql/issues"
42
+ },
43
+ "homepage": "https://objectql.org",
14
44
  "scripts": {
15
45
  "build": "tsc",
16
46
  "test": "jest"
package/src/index.ts CHANGED
@@ -1,5 +1,76 @@
1
- import { Driver } from '@objectql/types';
1
+ /**
2
+ * @objectql/sdk - Universal HTTP Client for ObjectQL
3
+ *
4
+ * This package provides type-safe HTTP clients for ObjectQL servers.
5
+ * It works seamlessly in browsers, Node.js, Deno, and edge runtimes.
6
+ *
7
+ * ## Browser Compatibility
8
+ *
9
+ * The SDK uses modern JavaScript APIs:
10
+ * - fetch API (universal)
11
+ * - AbortSignal.timeout() (Chrome 103+, Firefox 100+, Safari 16.4+)
12
+ *
13
+ * For older browsers, a polyfill is automatically applied if AbortSignal.timeout is not available.
14
+ *
15
+ * @packageDocumentation
16
+ */
2
17
 
18
+ import {
19
+ Driver,
20
+ IDataApiClient,
21
+ IMetadataApiClient,
22
+ DataApiClientConfig,
23
+ MetadataApiClientConfig,
24
+ DataApiListParams,
25
+ DataApiListResponse,
26
+ DataApiItemResponse,
27
+ DataApiCreateRequest,
28
+ DataApiCreateManyRequest,
29
+ DataApiUpdateRequest,
30
+ DataApiBulkUpdateRequest,
31
+ DataApiBulkDeleteRequest,
32
+ DataApiCountResponse,
33
+ DataApiDeleteResponse,
34
+ DataApiResponse,
35
+ MetadataApiObjectListResponse,
36
+ MetadataApiObjectDetailResponse,
37
+ FieldMetadataResponse,
38
+ MetadataApiActionsResponse,
39
+ MetadataApiListResponse,
40
+ MetadataApiResponse,
41
+ ObjectQLError,
42
+ ApiErrorCode,
43
+ FilterExpression
44
+ } from '@objectql/types';
45
+
46
+ /**
47
+ * Polyfill for AbortSignal.timeout if not available (for older browsers)
48
+ * This ensures the SDK works universally across all JavaScript environments.
49
+ */
50
+ if (typeof AbortSignal !== 'undefined' && !AbortSignal.timeout) {
51
+ (AbortSignal as any).timeout = function(ms: number): AbortSignal {
52
+ const controller = new AbortController();
53
+ setTimeout(() => controller.abort(), ms);
54
+ return controller.signal;
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Helper function to create a timeout signal that works in all environments
60
+ */
61
+ function createTimeoutSignal(ms: number): AbortSignal {
62
+ if (typeof AbortSignal !== 'undefined' && AbortSignal.timeout) {
63
+ return AbortSignal.timeout(ms);
64
+ }
65
+ // Fallback for environments without AbortSignal
66
+ const controller = new AbortController();
67
+ setTimeout(() => controller.abort(), ms);
68
+ return controller.signal;
69
+ }
70
+
71
+ /**
72
+ * Legacy Driver implementation that uses JSON-RPC style API
73
+ */
3
74
  export class RemoteDriver implements Driver {
4
75
  constructor(private baseUrl: string) {}
5
76
 
@@ -66,3 +137,272 @@ export class RemoteDriver implements Driver {
66
137
  return this.request('deleteMany', objectName, { filters });
67
138
  }
68
139
  }
140
+
141
+ /**
142
+ * REST-based Data API Client
143
+ *
144
+ * Implements type-safe client for ObjectQL Data API endpoints.
145
+ * Uses the RESTful interface described in docs/api/rest.md
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * const client = new DataApiClient({ baseUrl: 'http://localhost:3000' });
150
+ *
151
+ * // List users
152
+ * const response = await client.list('users', {
153
+ * filter: [['status', '=', 'active']],
154
+ * sort: [['created_at', 'desc']],
155
+ * limit: 20
156
+ * });
157
+ *
158
+ * // Get single user
159
+ * const user = await client.get('users', 'user_123');
160
+ *
161
+ * // Create user
162
+ * const newUser = await client.create('users', {
163
+ * name: 'Alice',
164
+ * email: 'alice@example.com'
165
+ * });
166
+ * ```
167
+ */
168
+ export class DataApiClient implements IDataApiClient {
169
+ private baseUrl: string;
170
+ private token?: string;
171
+ private headers: Record<string, string>;
172
+ private timeout: number;
173
+
174
+ constructor(config: DataApiClientConfig) {
175
+ this.baseUrl = config.baseUrl.replace(/\/$/, '');
176
+ this.token = config.token;
177
+ this.headers = config.headers || {};
178
+ this.timeout = config.timeout || 30000;
179
+ }
180
+
181
+ private async request<T>(
182
+ method: string,
183
+ path: string,
184
+ body?: unknown,
185
+ queryParams?: Record<string, unknown>
186
+ ): Promise<T> {
187
+ const url = new URL(`${this.baseUrl}${path}`);
188
+
189
+ // Add query parameters
190
+ if (queryParams) {
191
+ Object.entries(queryParams).forEach(([key, value]) => {
192
+ if (value !== undefined && value !== null) {
193
+ url.searchParams.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value));
194
+ }
195
+ });
196
+ }
197
+
198
+ const headers: Record<string, string> = {
199
+ 'Content-Type': 'application/json',
200
+ ...this.headers
201
+ };
202
+
203
+ if (this.token) {
204
+ headers['Authorization'] = `Bearer ${this.token}`;
205
+ }
206
+
207
+ const response = await fetch(url.toString(), {
208
+ method,
209
+ headers,
210
+ body: body ? JSON.stringify(body) : undefined,
211
+ signal: createTimeoutSignal(this.timeout)
212
+ });
213
+
214
+ const json = await response.json();
215
+
216
+ if (json.error) {
217
+ throw new ObjectQLError({
218
+ code: json.error.code || ApiErrorCode.INTERNAL_ERROR,
219
+ message: json.error.message,
220
+ details: json.error.details
221
+ });
222
+ }
223
+
224
+ return json as T;
225
+ }
226
+
227
+ async list<T = unknown>(objectName: string, params?: DataApiListParams): Promise<DataApiListResponse<T>> {
228
+ return this.request<DataApiListResponse<T>>(
229
+ 'GET',
230
+ `/api/data/${objectName}`,
231
+ undefined,
232
+ params as Record<string, unknown>
233
+ );
234
+ }
235
+
236
+ async get<T = unknown>(objectName: string, id: string | number): Promise<DataApiItemResponse<T>> {
237
+ return this.request<DataApiItemResponse<T>>(
238
+ 'GET',
239
+ `/api/data/${objectName}/${id}`
240
+ );
241
+ }
242
+
243
+ async create<T = unknown>(objectName: string, data: DataApiCreateRequest): Promise<DataApiItemResponse<T>> {
244
+ return this.request<DataApiItemResponse<T>>(
245
+ 'POST',
246
+ `/api/data/${objectName}`,
247
+ data
248
+ );
249
+ }
250
+
251
+ async createMany<T = unknown>(objectName: string, data: DataApiCreateManyRequest): Promise<DataApiListResponse<T>> {
252
+ return this.request<DataApiListResponse<T>>(
253
+ 'POST',
254
+ `/api/data/${objectName}`,
255
+ data
256
+ );
257
+ }
258
+
259
+ async update<T = unknown>(objectName: string, id: string | number, data: DataApiUpdateRequest): Promise<DataApiItemResponse<T>> {
260
+ return this.request<DataApiItemResponse<T>>(
261
+ 'PUT',
262
+ `/api/data/${objectName}/${id}`,
263
+ data
264
+ );
265
+ }
266
+
267
+ async updateMany(objectName: string, request: DataApiBulkUpdateRequest): Promise<DataApiResponse> {
268
+ return this.request<DataApiResponse>(
269
+ 'POST',
270
+ `/api/data/${objectName}/bulk-update`,
271
+ request
272
+ );
273
+ }
274
+
275
+ async delete(objectName: string, id: string | number): Promise<DataApiDeleteResponse> {
276
+ return this.request<DataApiDeleteResponse>(
277
+ 'DELETE',
278
+ `/api/data/${objectName}/${id}`
279
+ );
280
+ }
281
+
282
+ async deleteMany(objectName: string, request: DataApiBulkDeleteRequest): Promise<DataApiDeleteResponse> {
283
+ return this.request<DataApiDeleteResponse>(
284
+ 'POST',
285
+ `/api/data/${objectName}/bulk-delete`,
286
+ request
287
+ );
288
+ }
289
+
290
+ async count(objectName: string, filters?: FilterExpression): Promise<DataApiCountResponse> {
291
+ return this.request<DataApiCountResponse>(
292
+ 'GET',
293
+ `/api/data/${objectName}`,
294
+ undefined,
295
+ { filter: filters, limit: 0 }
296
+ );
297
+ }
298
+ }
299
+
300
+ /**
301
+ * REST-based Metadata API Client
302
+ *
303
+ * Implements type-safe client for ObjectQL Metadata API endpoints.
304
+ * Uses the interface described in docs/api/metadata.md
305
+ *
306
+ * @example
307
+ * ```typescript
308
+ * const client = new MetadataApiClient({ baseUrl: 'http://localhost:3000' });
309
+ *
310
+ * // List all objects
311
+ * const objects = await client.listObjects();
312
+ *
313
+ * // Get detailed object metadata
314
+ * const userSchema = await client.getObject('users');
315
+ * console.log(userSchema.fields);
316
+ *
317
+ * // Get field metadata
318
+ * const emailField = await client.getField('users', 'email');
319
+ *
320
+ * // List actions
321
+ * const actions = await client.listActions('users');
322
+ * ```
323
+ */
324
+ export class MetadataApiClient implements IMetadataApiClient {
325
+ private baseUrl: string;
326
+ private token?: string;
327
+ private headers: Record<string, string>;
328
+ private timeout: number;
329
+
330
+ constructor(config: MetadataApiClientConfig) {
331
+ this.baseUrl = config.baseUrl.replace(/\/$/, '');
332
+ this.token = config.token;
333
+ this.headers = config.headers || {};
334
+ this.timeout = config.timeout || 30000;
335
+ }
336
+
337
+ private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
338
+ const headers: Record<string, string> = {
339
+ 'Content-Type': 'application/json',
340
+ ...this.headers
341
+ };
342
+
343
+ if (this.token) {
344
+ headers['Authorization'] = `Bearer ${this.token}`;
345
+ }
346
+
347
+ const response = await fetch(`${this.baseUrl}${path}`, {
348
+ method,
349
+ headers,
350
+ body: body ? JSON.stringify(body) : undefined,
351
+ signal: createTimeoutSignal(this.timeout)
352
+ });
353
+
354
+ const json = await response.json();
355
+
356
+ if (json.error) {
357
+ throw new ObjectQLError({
358
+ code: json.error.code || ApiErrorCode.INTERNAL_ERROR,
359
+ message: json.error.message,
360
+ details: json.error.details
361
+ });
362
+ }
363
+
364
+ return json as T;
365
+ }
366
+
367
+ async listObjects(): Promise<MetadataApiObjectListResponse> {
368
+ return this.request<MetadataApiObjectListResponse>(
369
+ 'GET',
370
+ '/api/metadata/objects'
371
+ );
372
+ }
373
+
374
+ async getObject(objectName: string): Promise<MetadataApiObjectDetailResponse> {
375
+ return this.request<MetadataApiObjectDetailResponse>(
376
+ 'GET',
377
+ `/api/metadata/object/${objectName}`
378
+ );
379
+ }
380
+
381
+ async getField(objectName: string, fieldName: string): Promise<FieldMetadataResponse> {
382
+ return this.request<FieldMetadataResponse>(
383
+ 'GET',
384
+ `/api/metadata/object/${objectName}/fields/${fieldName}`
385
+ );
386
+ }
387
+
388
+ async listActions(objectName: string): Promise<MetadataApiActionsResponse> {
389
+ return this.request<MetadataApiActionsResponse>(
390
+ 'GET',
391
+ `/api/metadata/object/${objectName}/actions`
392
+ );
393
+ }
394
+
395
+ async listByType<T = unknown>(metadataType: string): Promise<MetadataApiListResponse<T>> {
396
+ return this.request<MetadataApiListResponse<T>>(
397
+ 'GET',
398
+ `/api/metadata/${metadataType}`
399
+ );
400
+ }
401
+
402
+ async getMetadata<T = unknown>(metadataType: string, id: string): Promise<MetadataApiResponse<T>> {
403
+ return this.request<MetadataApiResponse<T>>(
404
+ 'GET',
405
+ `/api/metadata/${metadataType}/${id}`
406
+ );
407
+ }
408
+ }