@centrali-io/centrali-sdk 2.0.0 → 2.0.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.
Files changed (4) hide show
  1. package/README.md +197 -0
  2. package/dist/index.js +29 -10
  3. package/index.ts +30 -11
  4. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # Centrali JavaScript/TypeScript SDK
2
+
3
+ Official Node.js SDK for Centrali - Build modern web applications without managing infrastructure.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40centrali-io%2Fcentrali-sdk.svg)](https://www.npmjs.com/package/@centrali-io/centrali-sdk)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @centrali-io/centrali-sdk
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { CentraliSDK } from '@centrali-io/centrali-sdk';
17
+
18
+ // Initialize the SDK
19
+ const centrali = new CentraliSDK({
20
+ baseUrl: 'https://centrali.io',
21
+ workspaceId: 'your-workspace',
22
+ token: 'your-api-key'
23
+ });
24
+
25
+ // Create a record
26
+ const product = await centrali.createRecord('Product', {
27
+ name: 'Awesome Product',
28
+ price: 99.99,
29
+ inStock: true
30
+ });
31
+
32
+ console.log('Created product:', product.data);
33
+
34
+ // Invoke a compute function
35
+ const result = await centrali.invokeFunction('calculate-discount', {
36
+ productId: product.id,
37
+ couponCode: 'SAVE20'
38
+ });
39
+
40
+ console.log('Discount result:', result.data);
41
+ ```
42
+
43
+ ## Authentication
44
+
45
+ The SDK supports two authentication methods:
46
+
47
+ ### Bearer Token (User Authentication)
48
+
49
+ ```typescript
50
+ const centrali = new CentraliSDK({
51
+ baseUrl: 'https://centrali.io',
52
+ workspaceId: 'your-workspace',
53
+ token: 'your-jwt-token'
54
+ });
55
+ ```
56
+
57
+ ### Service Account (Server-to-Server)
58
+
59
+ ```typescript
60
+ const centrali = new CentraliSDK({
61
+ baseUrl: 'https://centrali.io',
62
+ workspaceId: 'your-workspace',
63
+ clientId: process.env.CENTRALI_CLIENT_ID,
64
+ clientSecret: process.env.CENTRALI_CLIENT_SECRET
65
+ });
66
+
67
+ // The SDK automatically fetches and manages tokens
68
+ ```
69
+
70
+ ## Features
71
+
72
+ - ✅ **Type-safe API** with full TypeScript support
73
+ - ✅ **Automatic authentication** and token management
74
+ - ✅ **Records management** - Create, read, update, delete records
75
+ - ✅ **Query operations** - Powerful data querying with filters and sorting
76
+ - ✅ **Compute functions** - Execute serverless functions
77
+ - ✅ **File uploads** - Upload files to Centrali storage
78
+ - ✅ **Service accounts** - Automatic token refresh for server-to-server auth
79
+
80
+ ## Core Operations
81
+
82
+ ### Records
83
+
84
+ ```typescript
85
+ // Create a record
86
+ const record = await centrali.createRecord('StructureName', {
87
+ field1: 'value1',
88
+ field2: 123
89
+ });
90
+
91
+ // Get a record
92
+ const record = await centrali.getRecord('StructureName', 'record-id');
93
+
94
+ // Update a record
95
+ await centrali.updateRecord('StructureName', 'record-id', {
96
+ field1: 'new value'
97
+ });
98
+
99
+ // Delete a record
100
+ await centrali.deleteRecord('StructureName', 'record-id');
101
+
102
+ // Query records
103
+ const products = await centrali.queryRecords('Product', {
104
+ filter: 'inStock = true AND price < 100',
105
+ sort: '-createdAt',
106
+ limit: 10
107
+ });
108
+ ```
109
+
110
+ ### Compute Functions
111
+
112
+ ```typescript
113
+ // Execute a function
114
+ const result = await centrali.invokeFunction('myFunction', {
115
+ data: 'your-input-data'
116
+ });
117
+ ```
118
+
119
+ ### File Uploads
120
+
121
+ ```typescript
122
+ // Upload a file
123
+ const uploadResult = await centrali.uploadFile(
124
+ file,
125
+ 'folder-name',
126
+ true // make publicly accessible
127
+ );
128
+
129
+ console.log('File URL:', uploadResult.data);
130
+ ```
131
+
132
+ ## TypeScript Support
133
+
134
+ The SDK includes full TypeScript definitions for type-safe development:
135
+
136
+ ```typescript
137
+ interface Product {
138
+ name: string;
139
+ price: number;
140
+ inStock: boolean;
141
+ }
142
+
143
+ const product = await centrali.createRecord<Product>('Product', {
144
+ name: 'Laptop',
145
+ price: 999.99,
146
+ inStock: true
147
+ });
148
+
149
+ // TypeScript knows product.data is of type Product
150
+ console.log(product.data.price);
151
+ ```
152
+
153
+ ## Error Handling
154
+
155
+ ```typescript
156
+ try {
157
+ const record = await centrali.createRecord('Product', productData);
158
+ console.log('Success:', record);
159
+ } catch (error) {
160
+ if (error.response?.status === 400) {
161
+ console.error('Validation error:', error.response.data);
162
+ } else if (error.response?.status === 401) {
163
+ console.error('Authentication failed');
164
+ } else {
165
+ console.error('Error:', error.message);
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## Documentation
171
+
172
+ 📚 **Full documentation available at**: [docs.centrali.io](https://docs.centrali.io)
173
+
174
+ - [Complete SDK Guide](https://docs.centrali.io/guides/centrali-sdk)
175
+ - [API Reference](https://docs.centrali.io/api-reference/overview)
176
+ - [Quick Start Tutorial](https://docs.centrali.io/getting-started/02-quickstart)
177
+ - [Compute Functions Guide](https://docs.centrali.io/guides/compute-functions-guide)
178
+
179
+ ## Examples
180
+
181
+ Check out complete example applications:
182
+ - [Blog Platform](https://docs.centrali.io/examples/blog-platform)
183
+ - [E-commerce API](https://docs.centrali.io/examples/ecommerce-api)
184
+
185
+ ## Support
186
+
187
+ - 📖 [Documentation](https://docs.centrali.io)
188
+ - 🐛 [GitHub Issues](https://github.com/blueinit/centrali-sdk/issues)
189
+ - 💬 [Community Support](https://centrali.io/community)
190
+
191
+ ## License
192
+
193
+ ISC © Blueinit
194
+
195
+ ---
196
+
197
+ **Built with ❤️ by the Centrali team**
package/dist/index.js CHANGED
@@ -19,6 +19,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.CentraliSDK = void 0;
22
+ exports.getApiUrl = getApiUrl;
22
23
  exports.getAuthUrl = getAuthUrl;
23
24
  exports.fetchClientToken = fetchClientToken;
24
25
  exports.getRecordApiPath = getRecordApiPath;
@@ -31,25 +32,42 @@ function encodeFormData(data) {
31
32
  return new URLSearchParams(data).toString();
32
33
  }
33
34
  /**
34
- * Generate the auth server URL from the API base URL.
35
+ * Generate the API URL from the base URL by adding the 'api.' subdomain.
36
+ * E.g., https://centrali.io -> https://api.centrali.io
35
37
  */
36
- function getAuthUrl(apiBaseUrl) {
37
- const url = new URL(apiBaseUrl);
38
- // assume auth is hosted at auth.<api-domain>
39
- return `${url.protocol}//auth.${url.hostname}`;
38
+ function getApiUrl(baseUrl) {
39
+ const url = new URL(baseUrl);
40
+ // If already has 'api.' subdomain, return as-is
41
+ if (url.hostname.startsWith('api.')) {
42
+ return `${url.protocol}//${url.hostname}`;
43
+ }
44
+ return `${url.protocol}//api.${url.hostname}`;
45
+ }
46
+ /**
47
+ * Generate the auth server URL from the base URL.
48
+ * E.g., https://centrali.io -> https://auth.centrali.io
49
+ */
50
+ function getAuthUrl(baseUrl) {
51
+ const url = new URL(baseUrl);
52
+ // Strip 'api.' prefix if present to get root domain
53
+ const hostname = url.hostname.startsWith('api.')
54
+ ? url.hostname.slice(4)
55
+ : url.hostname;
56
+ return `${url.protocol}//auth.${hostname}`;
40
57
  }
41
58
  /**
42
59
  * Retrieve an access token using the Client Credentials flow.
43
60
  */
44
- function fetchClientToken(clientId, clientSecret, apiBaseUrl) {
61
+ function fetchClientToken(clientId, clientSecret, baseUrl) {
45
62
  return __awaiter(this, void 0, void 0, function* () {
46
- const authUrl = getAuthUrl(apiBaseUrl);
63
+ const authUrl = getAuthUrl(baseUrl);
64
+ const apiUrl = getApiUrl(baseUrl);
47
65
  const tokenEndpoint = `${authUrl}/token`;
48
66
  const form = encodeFormData({
49
67
  grant_type: 'client_credentials',
50
68
  client_id: clientId,
51
69
  client_secret: clientSecret,
52
- resource: `${apiBaseUrl}/data`
70
+ resource: `${apiUrl}/data`
53
71
  });
54
72
  const resp = yield axios_1.default.post(tokenEndpoint, form, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
55
73
  proxy: false
@@ -84,7 +102,8 @@ class CentraliSDK {
84
102
  this.token = null;
85
103
  this.options = options;
86
104
  this.token = options.token || null;
87
- this.axios = axios_1.default.create(Object.assign({ baseURL: options.baseUrl, paramsSerializer: (params) => qs_1.default.stringify(params, { arrayFormat: "repeat" }), proxy: false }, options.axiosConfig));
105
+ const apiUrl = getApiUrl(options.baseUrl);
106
+ this.axios = axios_1.default.create(Object.assign({ baseURL: apiUrl, paramsSerializer: (params) => qs_1.default.stringify(params, { arrayFormat: "repeat" }), proxy: false }, options.axiosConfig));
88
107
  // Attach async interceptor to fetch token on first request if needed
89
108
  this.axios.interceptors.request.use((config) => __awaiter(this, void 0, void 0, function* () {
90
109
  if (!this.token && this.options.clientId && this.options.clientSecret) {
@@ -195,7 +214,7 @@ exports.CentraliSDK = CentraliSDK;
195
214
  * import { CentraliSDK, CentraliSDKOptions } from 'centrali-sdk';
196
215
  *
197
216
  * const options: CentraliSDKOptions = {
198
- * baseUrl: 'https://api.centrali.com',
217
+ * baseUrl: 'https://centrali.io',
199
218
  * clientId: process.env.CLIENT_ID,
200
219
  * clientSecret: process.env.CLIENT_SECRET,
201
220
  * };
package/index.ts CHANGED
@@ -16,7 +16,7 @@ function encodeFormData(data: Record<string, string>): string {
16
16
  * Options for initializing the Centrali SDK client.
17
17
  */
18
18
  export interface CentraliSDKOptions {
19
- /** Base URL of the Centrali API (e.g. https://api.centrali.com) */
19
+ /** Base URL of Centrali (e.g. https://centrali.io). The SDK automatically uses api.centrali.io for API calls. */
20
20
  baseUrl: string;
21
21
  workspaceId: string;
22
22
  /** Optional initial bearer token for authentication */
@@ -43,12 +43,29 @@ export interface ApiResponse<T> {
43
43
 
44
44
 
45
45
  /**
46
- * Generate the auth server URL from the API base URL.
46
+ * Generate the API URL from the base URL by adding the 'api.' subdomain.
47
+ * E.g., https://centrali.io -> https://api.centrali.io
47
48
  */
48
- export function getAuthUrl(apiBaseUrl: string): string {
49
- const url = new URL(apiBaseUrl);
50
- // assume auth is hosted at auth.<api-domain>
51
- return `${url.protocol}//auth.${url.hostname}`;
49
+ export function getApiUrl(baseUrl: string): string {
50
+ const url = new URL(baseUrl);
51
+ // If already has 'api.' subdomain, return as-is
52
+ if (url.hostname.startsWith('api.')) {
53
+ return `${url.protocol}//${url.hostname}`;
54
+ }
55
+ return `${url.protocol}//api.${url.hostname}`;
56
+ }
57
+
58
+ /**
59
+ * Generate the auth server URL from the base URL.
60
+ * E.g., https://centrali.io -> https://auth.centrali.io
61
+ */
62
+ export function getAuthUrl(baseUrl: string): string {
63
+ const url = new URL(baseUrl);
64
+ // Strip 'api.' prefix if present to get root domain
65
+ const hostname = url.hostname.startsWith('api.')
66
+ ? url.hostname.slice(4)
67
+ : url.hostname;
68
+ return `${url.protocol}//auth.${hostname}`;
52
69
  }
53
70
 
54
71
  /**
@@ -57,15 +74,16 @@ export function getAuthUrl(apiBaseUrl: string): string {
57
74
  export async function fetchClientToken(
58
75
  clientId: string,
59
76
  clientSecret: string,
60
- apiBaseUrl: string
77
+ baseUrl: string
61
78
  ): Promise<string> {
62
- const authUrl = getAuthUrl(apiBaseUrl);
79
+ const authUrl = getAuthUrl(baseUrl);
80
+ const apiUrl = getApiUrl(baseUrl);
63
81
  const tokenEndpoint = `${authUrl}/token`;
64
82
  const form = encodeFormData({
65
83
  grant_type: 'client_credentials',
66
84
  client_id: clientId,
67
85
  client_secret: clientSecret,
68
- resource: `${apiBaseUrl}/data`
86
+ resource: `${apiUrl}/data`
69
87
  });
70
88
  const resp = await axios.post(
71
89
  tokenEndpoint,
@@ -113,8 +131,9 @@ export class CentraliSDK {
113
131
  constructor(options: CentraliSDKOptions) {
114
132
  this.options = options;
115
133
  this.token = options.token || null;
134
+ const apiUrl = getApiUrl(options.baseUrl);
116
135
  this.axios = axios.create({
117
- baseURL: options.baseUrl,
136
+ baseURL: apiUrl,
118
137
  paramsSerializer: (params: Record<string, any>): string =>
119
138
  qs.stringify(params, { arrayFormat: "repeat" }),
120
139
  proxy: false,
@@ -299,7 +318,7 @@ export class CentraliSDK {
299
318
  * import { CentraliSDK, CentraliSDKOptions } from 'centrali-sdk';
300
319
  *
301
320
  * const options: CentraliSDKOptions = {
302
- * baseUrl: 'https://api.centrali.com',
321
+ * baseUrl: 'https://centrali.io',
303
322
  * clientId: process.env.CLIENT_ID,
304
323
  * clientSecret: process.env.CLIENT_SECRET,
305
324
  * };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centrali-io/centrali-sdk",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Centrali Node SDK",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",