@apito-io/js-admin-sdk 2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Apito
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,351 @@
1
+ # Apito Admin JavaScript SDK
2
+
3
+ [![npm version](https://badge.fury.io/js/%40apito-io%2Fjs-admin-sdk.svg)](https://badge.fury.io/js/%40apito-io%2Fjs-admin-sdk)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A comprehensive JavaScript SDK for communicating with Apito GraphQL API endpoints. This SDK provides both type-safe and flexible interfaces for interacting with Apito's backend services.
7
+
8
+ ## 🚀 Features
9
+
10
+ - ✅ **Complete SDK Implementation**: Full implementation matching the Go SDK
11
+ - ✅ **Type-Safe Operations**: Generic typed methods for better development experience
12
+ - ✅ **GraphQL-Based**: Native GraphQL communication with Apito backend
13
+ - ✅ **Authentication Ready**: API key and tenant-based authentication
14
+ - ✅ **Promise-Based**: Modern async/await support
15
+ - ✅ **Comprehensive Error Handling**: Detailed error responses and GraphQL error support
16
+ - ✅ **Plugin-Ready**: Perfect for Node.js applications and microservices
17
+ - ✅ **Production Ready**: Battle-tested patterns and error handling
18
+
19
+ ## 📦 Installation
20
+
21
+ ```bash
22
+ npm install @apito-io/js-admin-sdk
23
+ ```
24
+
25
+ or
26
+
27
+ ```bash
28
+ yarn add @apito-io/js-admin-sdk
29
+ ```
30
+
31
+ ## 🎯 Quick Start
32
+
33
+ ```javascript
34
+ import { ApitoClient } from '@apito-io/js-admin-sdk';
35
+
36
+ // Create a new client
37
+ const client = new ApitoClient({
38
+ baseURL: 'https://api.apito.io/graphql',
39
+ apiKey: 'your-api-key-here',
40
+ timeout: 30000,
41
+ });
42
+
43
+ // Create a new todo
44
+ async function createTodo() {
45
+ const todoData = {
46
+ title: 'Learn Apito SDK',
47
+ description: 'Complete the SDK tutorial',
48
+ status: 'todo',
49
+ priority: 'high',
50
+ };
51
+
52
+ const request = {
53
+ model: 'todos',
54
+ payload: todoData,
55
+ };
56
+
57
+ const todo = await client.createNewResource(request);
58
+ console.log('Created todo:', todo.id);
59
+ }
60
+ ```
61
+
62
+ ## 📚 API Reference
63
+
64
+ ### Client Configuration
65
+
66
+ ```javascript
67
+ const client = new ApitoClient({
68
+ baseURL: 'https://api.apito.io/graphql', // Your Apito GraphQL endpoint
69
+ apiKey: 'your-api-key-here', // X-APITO-KEY header value
70
+ timeout: 30000, // Request timeout in milliseconds
71
+ tenantId: 'your-tenant-id', // Optional tenant ID
72
+ httpClient: { // Optional axios configuration
73
+ maxRedirects: 5,
74
+ // ... other axios config
75
+ },
76
+ });
77
+ ```
78
+
79
+ ### Core Methods
80
+
81
+ #### `getSingleResource(model, id, singlePageData?)`
82
+ Get a single resource by model and ID.
83
+
84
+ ```javascript
85
+ const todo = await client.getSingleResource('todos', '123');
86
+ console.log(todo.data.title);
87
+ ```
88
+
89
+ #### `searchResources(model, filter?, aggregate?)`
90
+ Search resources in a model with filtering. Only these `filter` fields are sent to GraphQL (same as the Go internal SDK): `_key`, `page`, `limit`, `where`, `search`. The `aggregate` argument is reserved for a future schema option and is not sent today.
91
+
92
+ ```javascript
93
+ const results = await client.searchResources('todos', {
94
+ where: { status: 'todo' },
95
+ limit: 10,
96
+ page: 1,
97
+ });
98
+ console.log(`Found ${results.count} todos`);
99
+ ```
100
+
101
+ #### `createNewResource(request)`
102
+ Create a new resource.
103
+
104
+ ```javascript
105
+ const newTodo = await client.createNewResource({
106
+ model: 'todos',
107
+ payload: {
108
+ title: 'New Task',
109
+ status: 'todo',
110
+ },
111
+ connect: { user: 'user-123' }, // Optional relations
112
+ });
113
+ ```
114
+
115
+ #### `updateResource(request)`
116
+ Update an existing resource.
117
+
118
+ ```javascript
119
+ const updatedTodo = await client.updateResource({
120
+ model: 'todos',
121
+ id: '123',
122
+ payload: {
123
+ status: 'completed',
124
+ completed_at: new Date().toISOString(),
125
+ },
126
+ connect: { tags: ['urgent'] }, // Add relations
127
+ disconnect: { tags: ['low-priority'] }, // Remove relations
128
+ });
129
+ ```
130
+
131
+ #### `deleteResource(model, id)`
132
+ Delete a resource.
133
+
134
+ ```javascript
135
+ await client.deleteResource('todos', '123');
136
+ ```
137
+
138
+ #### `getRelationDocuments(id, connection)`
139
+ Get related documents.
140
+
141
+ ```javascript
142
+ const relatedUsers = await client.getRelationDocuments('todo-123', {
143
+ model: 'users',
144
+ field: 'assigned_to',
145
+ });
146
+ ```
147
+
148
+ ### Typed Operations
149
+
150
+ For type-safe operations, use the `TypedOperations` class:
151
+
152
+ ```javascript
153
+ import { TypedOperations } from '@apito-io/js-admin-sdk';
154
+
155
+ const typed = new TypedOperations(client);
156
+
157
+ // Define your types
158
+ interface Todo {
159
+ id: string;
160
+ title: string;
161
+ description: string;
162
+ status: 'todo' | 'in_progress' | 'completed';
163
+ priority: 'low' | 'medium' | 'high';
164
+ }
165
+
166
+ // Type-safe operations
167
+ const typedTodo = await typed.createNewResourceTyped<Todo>({
168
+ model: 'todos',
169
+ payload: {
170
+ title: 'Type-safe todo',
171
+ status: 'todo',
172
+ priority: 'high',
173
+ },
174
+ });
175
+
176
+ // TypeScript will infer the correct type
177
+ console.log(typedTodo.data.title); // string
178
+ console.log(typedTodo.data.status); // 'todo' | 'in_progress' | 'completed'
179
+ ```
180
+
181
+ ### Error Handling
182
+
183
+ The SDK provides comprehensive error handling:
184
+
185
+ ```javascript
186
+ import { ApitoError, ValidationError, GraphQLError } from '@apito-io/js-admin-sdk';
187
+
188
+ try {
189
+ const result = await client.getSingleResource('todos', 'invalid-id');
190
+ } catch (error) {
191
+ if (error instanceof ValidationError) {
192
+ console.error('Validation error:', error.message);
193
+ } else if (error instanceof GraphQLError) {
194
+ console.error('GraphQL error:', error.graphQLErrors);
195
+ } else if (error instanceof ApitoError) {
196
+ console.error('API error:', error.statusCode, error.message);
197
+ } else {
198
+ console.error('Unknown error:', error);
199
+ }
200
+ }
201
+ ```
202
+
203
+ ### Environment Variables
204
+
205
+ You can configure the client using environment variables:
206
+
207
+ ```bash
208
+ # Required
209
+ APITO_BASE_URL=https://api.apito.io/graphql
210
+ APITO_API_KEY=your-production-api-key
211
+
212
+ # Optional
213
+ APITO_TENANT_ID=your-tenant-id
214
+ APITO_TIMEOUT=30000
215
+ ```
216
+
217
+ ```javascript
218
+ import { ApitoClient } from '@apito-io/js-admin-sdk';
219
+
220
+ const client = new ApitoClient({
221
+ baseURL: process.env.APITO_BASE_URL,
222
+ apiKey: process.env.APITO_API_KEY,
223
+ tenantId: process.env.APITO_TENANT_ID,
224
+ timeout: parseInt(process.env.APITO_TIMEOUT || '30000'),
225
+ });
226
+ ```
227
+
228
+ ## 🧪 Examples
229
+
230
+ ### Basic CRUD Operations
231
+
232
+ ```javascript
233
+ import { ApitoClient } from '@apito-io/js-admin-sdk';
234
+
235
+ const client = new ApitoClient({
236
+ baseURL: 'https://api.apito.io/graphql',
237
+ apiKey: 'your-api-key',
238
+ });
239
+
240
+ // Create
241
+ const user = await client.createNewResource({
242
+ model: 'users',
243
+ payload: {
244
+ name: 'John Doe',
245
+ email: 'john@example.com',
246
+ },
247
+ });
248
+
249
+ // Read
250
+ const fetchedUser = await client.getSingleResource('users', user.id);
251
+
252
+ // Update
253
+ const updatedUser = await client.updateResource({
254
+ model: 'users',
255
+ id: user.id,
256
+ payload: {
257
+ name: 'John Updated',
258
+ },
259
+ });
260
+
261
+ // Delete
262
+ await client.deleteResource('users', user.id);
263
+ ```
264
+
265
+ ### Advanced Filtering
266
+
267
+ ```javascript
268
+ // Complex search with multiple filters
269
+ const results = await client.searchResources('products', {
270
+ where: {
271
+ AND: [
272
+ { price: { gte: 100 } },
273
+ { category: { in: ['electronics', 'books'] } },
274
+ { status: 'active' },
275
+ ],
276
+ },
277
+ search: 'laptop',
278
+ limit: 20,
279
+ page: 1,
280
+ });
281
+ ```
282
+
283
+ ### Batch Operations
284
+
285
+ ```javascript
286
+ // Create multiple records
287
+ const todos = [
288
+ { title: 'Task 1', status: 'todo' },
289
+ { title: 'Task 2', status: 'todo' },
290
+ { title: 'Task 3', status: 'todo' },
291
+ ];
292
+
293
+ const createdTodos = await Promise.all(
294
+ todos.map(todo => client.createNewResource({
295
+ model: 'todos',
296
+ payload: todo,
297
+ }))
298
+ );
299
+ ```
300
+
301
+ ## Parity with the Go internal SDK
302
+
303
+ This client mirrors the Go `go-internal-sdk` package and the `InternalSDKOperation` interface from `github.com/apito-io/types`.
304
+
305
+ - **Tenant header:** In Go, set `context.WithValue(ctx, "tenant_id", id)` before calls. In JavaScript, set `tenantId` on `ClientConfig`, or rely on `generateTenantToken`, which sends `X-Apito-Tenant-ID` for that mutation.
306
+ - **GraphQL errors:** The Go client returns `(response, err)` when the response includes `errors`. This SDK throws `GraphQLError` with `graphQLErrors` and the full payload on `response`; use `error.partialData` to read `data` when the server returns partial success.
307
+ - **`searchResources` filter:** Only `_key`, `page`, `limit`, `where`, and `search` are forwarded. Extra keys are ignored so unknown GraphQL variables cannot break the request.
308
+ - **`TypedOperations`:** `data` is deep-cloned via `JSON.parse(JSON.stringify(...))`, matching the Go SDK’s marshal/unmarshal approach for typed document `data`.
309
+
310
+ ## 🏗️ Development
311
+
312
+ ### Building from Source
313
+
314
+ ```bash
315
+ git clone https://github.com/apito-io/js-admin-sdk.git
316
+ cd js-admin-sdk
317
+ npm install
318
+ npm run build
319
+ ```
320
+
321
+ ### Running Tests
322
+
323
+ ```bash
324
+ npm test
325
+ ```
326
+
327
+ ### Running Examples
328
+
329
+ ```bash
330
+ cd examples/basic
331
+ npm install
332
+ npm start
333
+ ```
334
+
335
+ ## 📄 License
336
+
337
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
338
+
339
+ ## 🔗 Links
340
+
341
+ - [Apito Documentation](https://docs.apito.io)
342
+ - [npm Package](https://www.npmjs.com/package/@apito-io/js-admin-sdk)
343
+ - [GitHub Repository](https://github.com/apito-io/js-admin-sdk)
344
+ - [Issues](https://github.com/apito-io/js-admin-sdk/issues)
345
+
346
+ ## 🆘 Support
347
+
348
+ - 📧 Email: support@apito.io
349
+ - 💬 Discord: [Join our community](https://discord.gg/apito)
350
+ - 📖 Documentation: [docs.apito.io](https://docs.apito.io)
351
+ - 🐛 Bug Reports: [GitHub Issues](https://github.com/apito-io/js-admin-sdk/issues)
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Type definitions for the Apito JavaScript SDK
3
+ */
4
+ interface MetaField {
5
+ created_at: string;
6
+ updated_at: string;
7
+ status: string;
8
+ revision?: string;
9
+ revision_at?: string;
10
+ root_revision_id?: string;
11
+ }
12
+ interface DefaultDocumentStructure {
13
+ _key?: string;
14
+ _id?: string;
15
+ data: any;
16
+ meta?: MetaField;
17
+ id: string;
18
+ expire_at?: string | number;
19
+ relation_doc_id?: string;
20
+ last_revision_doc_id?: string;
21
+ type?: string;
22
+ tenant_id?: string;
23
+ tenant_model?: string;
24
+ }
25
+ interface SearchResult {
26
+ results: DefaultDocumentStructure[];
27
+ count: number;
28
+ }
29
+ interface TypedDocumentStructure<T> {
30
+ _key?: string;
31
+ _id?: string;
32
+ data: T;
33
+ meta?: MetaField;
34
+ id: string;
35
+ expire_at?: string | number;
36
+ relation_doc_id?: string;
37
+ last_revision_doc_id?: string;
38
+ type?: string;
39
+ tenant_id?: string;
40
+ tenant_model?: string;
41
+ }
42
+ interface TypedSearchResult<T> {
43
+ results: TypedDocumentStructure<T>[];
44
+ count: number;
45
+ }
46
+ interface Filter {
47
+ page?: number;
48
+ offset?: number;
49
+ limit?: number;
50
+ order?: string;
51
+ min?: number;
52
+ max?: number;
53
+ category?: string;
54
+ }
55
+ interface GraphQLErrorLocation {
56
+ line: number;
57
+ column: number;
58
+ }
59
+ interface GraphQLResponse {
60
+ data?: any;
61
+ errors?: GraphQLError[];
62
+ }
63
+ interface CreateAndUpdateRequest {
64
+ id?: string;
65
+ model: string;
66
+ payload: any;
67
+ connect?: Record<string, any>;
68
+ disconnect?: Record<string, any>;
69
+ singlePageData?: boolean;
70
+ forceUpdate?: boolean;
71
+ }
72
+ interface ClientConfig {
73
+ baseURL: string;
74
+ apiKey: string;
75
+ timeout?: number;
76
+ httpClient?: any;
77
+ tenantId?: string;
78
+ }
79
+ interface RequestOptions {
80
+ headers?: Record<string, string>;
81
+ timeout?: number;
82
+ }
83
+ interface SearchOptions {
84
+ limit?: number;
85
+ page?: number;
86
+ offset?: number;
87
+ where?: Record<string, any>;
88
+ search?: string;
89
+ sort?: Record<string, 1 | -1>;
90
+ }
91
+ interface ConnectionOptions {
92
+ model: string;
93
+ filter?: SearchOptions;
94
+ }
95
+ interface InjectedDBOperationInterface {
96
+ generateTenantToken(token: string, tenantId: string): Promise<string>;
97
+ getSingleResource(model: string, id: string, singlePageData?: boolean): Promise<DefaultDocumentStructure>;
98
+ searchResources(model: string, filter?: Record<string, any>, aggregate?: boolean): Promise<SearchResult>;
99
+ getRelationDocuments(id: string, connection: Record<string, any>): Promise<SearchResult>;
100
+ createNewResource(request: CreateAndUpdateRequest): Promise<DefaultDocumentStructure>;
101
+ updateResource(request: CreateAndUpdateRequest): Promise<DefaultDocumentStructure>;
102
+ deleteResource(model: string, id: string): Promise<void>;
103
+ debug(stage: string, ...data: any[]): Promise<any>;
104
+ }
105
+ declare class ApitoError extends Error {
106
+ code?: string;
107
+ statusCode?: number;
108
+ details?: any;
109
+ constructor(message: string, code?: string, statusCode?: number, details?: any);
110
+ }
111
+ interface GraphQLError {
112
+ message: string;
113
+ locations?: GraphQLErrorLocation[];
114
+ path?: (string | number)[];
115
+ extensions?: Record<string, any>;
116
+ }
117
+ declare class GraphQLError extends ApitoError {
118
+ graphQLErrors: GraphQLError[];
119
+ response?: any;
120
+ constructor(message: string, graphQLErrors: GraphQLError[], response?: any);
121
+ get partialData(): any;
122
+ }
123
+ declare class ValidationError extends ApitoError {
124
+ field?: string;
125
+ constructor(message: string, field?: string);
126
+ }
127
+
128
+ /**
129
+ * Apito SDK Client - JavaScript implementation matching the Go SDK
130
+ */
131
+ declare class ApitoClient implements InjectedDBOperationInterface {
132
+ private httpClient;
133
+ private baseURL;
134
+ private apiKey;
135
+ private tenantId?;
136
+ constructor(config: ClientConfig);
137
+ /**
138
+ * Execute a GraphQL query or mutation
139
+ */
140
+ private executeGraphQL;
141
+ /**
142
+ * Generate a new tenant token for the specified tenant ID
143
+ */
144
+ generateTenantToken(token: string, tenantId: string): Promise<string>;
145
+ /**
146
+ * Get a single resource by model and ID
147
+ */
148
+ getSingleResource(model: string, id: string, singlePageData?: boolean): Promise<DefaultDocumentStructure>;
149
+ /**
150
+ * Search resources in a model
151
+ */
152
+ searchResources(model: string, filter?: Record<string, any>, aggregate?: boolean): Promise<SearchResult>;
153
+ /**
154
+ * Get related documents
155
+ */
156
+ getRelationDocuments(id: string, connection: Record<string, any>): Promise<SearchResult>;
157
+ /**
158
+ * Create a new resource
159
+ */
160
+ createNewResource(request: CreateAndUpdateRequest): Promise<DefaultDocumentStructure>;
161
+ /**
162
+ * Update an existing resource
163
+ */
164
+ updateResource(request: CreateAndUpdateRequest): Promise<DefaultDocumentStructure>;
165
+ /**
166
+ * Delete a resource by model and ID
167
+ */
168
+ deleteResource(model: string, id: string): Promise<void>;
169
+ /**
170
+ * Debug is used to debug the plugin, you can pass data here to debug the plugin
171
+ */
172
+ debug(stage: string, ...data: any[]): Promise<any>;
173
+ }
174
+ /**
175
+ * Factory function to create a new Apito client
176
+ */
177
+ declare function createClient(config: ClientConfig): ApitoClient;
178
+
179
+ /**
180
+ * Typed operations wrapper for the Apito SDK
181
+ * Provides type-safe methods for working with typed data
182
+ */
183
+ declare class TypedOperations {
184
+ private client;
185
+ constructor(client: ApitoClient);
186
+ private static toTypedDocument;
187
+ /**
188
+ * Get a single resource with type safety
189
+ */
190
+ getSingleResourceTyped<T>(model: string, id: string, singlePageData?: boolean): Promise<TypedDocumentStructure<T>>;
191
+ /**
192
+ * Search resources with type safety
193
+ */
194
+ searchResourcesTyped<T>(model: string, filter?: Record<string, any>, aggregate?: boolean): Promise<TypedSearchResult<T>>;
195
+ /**
196
+ * Get related documents with type safety
197
+ */
198
+ getRelationDocumentsTyped<T>(id: string, connection: Record<string, any>): Promise<TypedSearchResult<T>>;
199
+ /**
200
+ * Create a new resource with type safety
201
+ */
202
+ createNewResourceTyped<T>(request: CreateAndUpdateRequest): Promise<TypedDocumentStructure<T>>;
203
+ /**
204
+ * Update a resource with type safety
205
+ */
206
+ updateResourceTyped<T>(request: CreateAndUpdateRequest): Promise<TypedDocumentStructure<T>>;
207
+ }
208
+
209
+ /**
210
+ * Apito JavaScript internal SDK version (kept in sync with package.json for releases)
211
+ */
212
+ declare const Version = "2.0.0";
213
+ /**
214
+ * GetVersion returns the current version of the SDK
215
+ */
216
+ declare function getVersion(): string;
217
+
218
+ export { ApitoClient, ApitoError, type ClientConfig, type ConnectionOptions, type CreateAndUpdateRequest, type DefaultDocumentStructure, type Filter, GraphQLError, type GraphQLErrorLocation, type GraphQLResponse, type InjectedDBOperationInterface, type MetaField, type RequestOptions, type SearchOptions, type SearchResult, type TypedDocumentStructure, TypedOperations, type TypedSearchResult, ValidationError, Version, createClient, ApitoClient as default, getVersion };