zone4code-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -0
- package/dist/index.cjs +476 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +248 -0
- package/dist/index.d.ts +248 -0
- package/dist/index.js +443 -0
- package/dist/index.js.map +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# zone4code-sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript & JavaScript Client SDK for the **Zone4Code Platform** & **Singulary**.
|
|
4
|
+
|
|
5
|
+
Provides a type-safe, chainable interface (similar to Supabase / Prisma) for **Keycloak Authentication**, **Adaptive Object-Model (AOM) Dynamic Schemas**, and **JSONB Querying** over the Unified API Gateway.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📦 Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install zone4code-sdk
|
|
13
|
+
# or
|
|
14
|
+
pnpm add zone4code-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { createClient } from 'zone4code-sdk';
|
|
23
|
+
|
|
24
|
+
const client = createClient({
|
|
25
|
+
gatewayUrl: 'http://localhost:8080', // Or your remote server: https://api.yourdomain.com
|
|
26
|
+
tenantId: 'my-workspace-id'
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// 1. Check Gateway Health
|
|
30
|
+
const health = await client.health();
|
|
31
|
+
console.log('Connected to Gateway:', health.licenseTier);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🔐 Authentication
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Register a new user
|
|
40
|
+
await client.auth.register({
|
|
41
|
+
email: 'alice@example.com',
|
|
42
|
+
password: 'SecurePassword123!',
|
|
43
|
+
name: 'Alice Smith'
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Login (JWT token is automatically saved to localStorage/Memory)
|
|
47
|
+
const { token } = await client.auth.login({
|
|
48
|
+
email: 'alice@example.com',
|
|
49
|
+
password: 'SecurePassword123!'
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Check status & profile
|
|
53
|
+
if (client.auth.isAuthenticated()) {
|
|
54
|
+
const profile = await client.auth.getProfile();
|
|
55
|
+
console.log('Logged in as:', profile.email);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Logout
|
|
59
|
+
client.auth.logout();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 📊 Database CRUD & Fluent Query Builder
|
|
65
|
+
|
|
66
|
+
### 1. Create a Record
|
|
67
|
+
```typescript
|
|
68
|
+
const newOrder = await client.from('order').create({
|
|
69
|
+
orderNumber: 'ORD-9021',
|
|
70
|
+
amount: 250.00,
|
|
71
|
+
status: 'pending',
|
|
72
|
+
customer: 'Acme Corp'
|
|
73
|
+
});
|
|
74
|
+
console.log('Created order ID:', newOrder.id);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Query with Chainable Filters
|
|
78
|
+
```typescript
|
|
79
|
+
const { data, total } = await client.from('order')
|
|
80
|
+
.eq('status', 'pending')
|
|
81
|
+
.gte('amount', 100)
|
|
82
|
+
.like('customer', 'Acme') // Case-insensitive ILIKE %Acme%
|
|
83
|
+
.orderBy('amount', 'desc') // Sort highest amount first
|
|
84
|
+
.page(1, 20) // Page 1, 20 items per page
|
|
85
|
+
.list();
|
|
86
|
+
|
|
87
|
+
console.log(`Found ${total} orders:`, data);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 3. Update & Delete
|
|
91
|
+
```typescript
|
|
92
|
+
// Update
|
|
93
|
+
await client.from('order').update(orderId, {
|
|
94
|
+
status: 'paid'
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Soft Delete
|
|
98
|
+
await client.from('order').delete(orderId);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 🛠️ Dynamic Schema Alteration
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
await client.schema.define({
|
|
107
|
+
typeName: 'invoice',
|
|
108
|
+
schema: {
|
|
109
|
+
type: 'object',
|
|
110
|
+
required: ['invoiceNumber', 'total'],
|
|
111
|
+
properties: {
|
|
112
|
+
invoiceNumber: { type: 'string' },
|
|
113
|
+
total: { type: 'number' },
|
|
114
|
+
dueDate: { type: 'string', format: 'date-time' }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 🛡️ Complete Operator Reference
|
|
123
|
+
|
|
124
|
+
| Method | Generated SQL Clause | Description |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `.eq(field, value)` | `data->>'field' = value` | Exact equality |
|
|
127
|
+
| `.ne(field, value)` | `data->>'field' != value` | Not equal |
|
|
128
|
+
| `.gt(field, number)` | `(data->>'field')::numeric > number` | Numeric greater than |
|
|
129
|
+
| `.gte(field, number)` | `(data->>'field')::numeric >= number` | Numeric greater than or equal |
|
|
130
|
+
| `.lt(field, number)` | `(data->>'field')::numeric < number` | Numeric less than |
|
|
131
|
+
| `.lte(field, number)` | `(data->>'field')::numeric <= number` | Numeric less than or equal |
|
|
132
|
+
| `.like(field, sub)` | `data->>'field' ILIKE '%sub%'` | Substring search (case-insensitive) |
|
|
133
|
+
| `.in(field, [a, b])` | `data->>'field' = ANY(ARRAY['a', 'b'])` | In set |
|
|
134
|
+
| `.isNull(field)` | `data->>'field' IS NULL` | Field is null or missing |
|
|
135
|
+
| `.isNotNull(field)` | `data->>'field' IS NOT NULL` | Field is present |
|
|
136
|
+
| `.related(name, ids)`| `EXISTS (entity_relations)` | Graph relation filter |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 📄 License
|
|
141
|
+
MIT © Zone4Code
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthClient: () => AuthClient,
|
|
24
|
+
EntityQueryBuilder: () => EntityQueryBuilder,
|
|
25
|
+
MemoryStorage: () => MemoryStorage,
|
|
26
|
+
SchemaClient: () => SchemaClient,
|
|
27
|
+
Zone4CodeClient: () => Zone4CodeClient,
|
|
28
|
+
createClient: () => createClient,
|
|
29
|
+
default: () => createClient,
|
|
30
|
+
getDefaultStorage: () => getDefaultStorage
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
|
|
34
|
+
// src/storage.ts
|
|
35
|
+
var MemoryStorage = class {
|
|
36
|
+
store = /* @__PURE__ */ new Map();
|
|
37
|
+
getItem(key) {
|
|
38
|
+
return this.store.get(key) ?? null;
|
|
39
|
+
}
|
|
40
|
+
setItem(key, value) {
|
|
41
|
+
this.store.set(key, value);
|
|
42
|
+
}
|
|
43
|
+
removeItem(key) {
|
|
44
|
+
this.store.delete(key);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
function getDefaultStorage() {
|
|
48
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
49
|
+
return window.localStorage;
|
|
50
|
+
}
|
|
51
|
+
return new MemoryStorage();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/auth.ts
|
|
55
|
+
var AuthClient = class _AuthClient {
|
|
56
|
+
gatewayUrl;
|
|
57
|
+
tenantId;
|
|
58
|
+
storage;
|
|
59
|
+
token = null;
|
|
60
|
+
fetchFn;
|
|
61
|
+
static TOKEN_KEY_PREFIX = "z4c_token_";
|
|
62
|
+
constructor(options) {
|
|
63
|
+
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
64
|
+
this.tenantId = options.tenantId;
|
|
65
|
+
this.storage = options.storage;
|
|
66
|
+
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
67
|
+
if (options.initialToken) {
|
|
68
|
+
this.setToken(options.initialToken);
|
|
69
|
+
} else {
|
|
70
|
+
Promise.resolve(this.storage.getItem(_AuthClient.TOKEN_KEY_PREFIX + this.tenantId)).then((stored) => {
|
|
71
|
+
if (stored) this.token = stored;
|
|
72
|
+
}).catch(() => {
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
getToken() {
|
|
77
|
+
return this.token;
|
|
78
|
+
}
|
|
79
|
+
setToken(token) {
|
|
80
|
+
this.token = token;
|
|
81
|
+
const storageKey = _AuthClient.TOKEN_KEY_PREFIX + this.tenantId;
|
|
82
|
+
if (token) {
|
|
83
|
+
this.storage.setItem(storageKey, token);
|
|
84
|
+
} else {
|
|
85
|
+
this.storage.removeItem(storageKey);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
isAuthenticated() {
|
|
89
|
+
return !!this.token;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Register a new user in the tenant realm
|
|
93
|
+
*/
|
|
94
|
+
async register(data) {
|
|
95
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/register`;
|
|
96
|
+
const res = await this.fetchFn(url, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
"x-tenant-id": this.tenantId
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify(data)
|
|
103
|
+
});
|
|
104
|
+
if (!res.ok) {
|
|
105
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
106
|
+
throw new Error(err.message || err.error || `Registration failed with HTTP ${res.status}`);
|
|
107
|
+
}
|
|
108
|
+
const json = await res.json();
|
|
109
|
+
const token = json.token || json.access_token;
|
|
110
|
+
if (token) {
|
|
111
|
+
this.setToken(token);
|
|
112
|
+
}
|
|
113
|
+
return json;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Log in an existing user and store their JWT token
|
|
117
|
+
*/
|
|
118
|
+
async login(credentials) {
|
|
119
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/login`;
|
|
120
|
+
const res = await this.fetchFn(url, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: {
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
"x-tenant-id": this.tenantId
|
|
125
|
+
},
|
|
126
|
+
body: JSON.stringify(credentials)
|
|
127
|
+
});
|
|
128
|
+
if (!res.ok) {
|
|
129
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
130
|
+
throw new Error(err.message || err.error || `Login failed with HTTP ${res.status}`);
|
|
131
|
+
}
|
|
132
|
+
const json = await res.json();
|
|
133
|
+
const token = json.token || json.access_token;
|
|
134
|
+
if (token) {
|
|
135
|
+
this.setToken(token);
|
|
136
|
+
}
|
|
137
|
+
return json;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Fetch current authenticated user profile
|
|
141
|
+
*/
|
|
142
|
+
async getProfile() {
|
|
143
|
+
if (!this.token) {
|
|
144
|
+
throw new Error("Not authenticated: please call login() or setToken() first");
|
|
145
|
+
}
|
|
146
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/profile`;
|
|
147
|
+
const res = await this.fetchFn(url, {
|
|
148
|
+
headers: {
|
|
149
|
+
"Authorization": `Bearer ${this.token}`,
|
|
150
|
+
"x-tenant-id": this.tenantId
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
if (!res.ok) {
|
|
154
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
155
|
+
throw new Error(err.message || `Failed to fetch profile (HTTP ${res.status})`);
|
|
156
|
+
}
|
|
157
|
+
return res.json();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Log out and clear saved token
|
|
161
|
+
*/
|
|
162
|
+
logout() {
|
|
163
|
+
this.setToken(null);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// src/schema.ts
|
|
168
|
+
var SchemaClient = class {
|
|
169
|
+
gatewayUrl;
|
|
170
|
+
tenantId;
|
|
171
|
+
getToken;
|
|
172
|
+
fetchFn;
|
|
173
|
+
constructor(options) {
|
|
174
|
+
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
175
|
+
this.tenantId = options.tenantId;
|
|
176
|
+
this.getToken = options.getToken;
|
|
177
|
+
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
178
|
+
}
|
|
179
|
+
getHeaders() {
|
|
180
|
+
const headers = {
|
|
181
|
+
"Content-Type": "application/json",
|
|
182
|
+
"x-tenant-id": this.tenantId
|
|
183
|
+
};
|
|
184
|
+
const token = this.getToken();
|
|
185
|
+
if (token) {
|
|
186
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
187
|
+
}
|
|
188
|
+
return headers;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Define a new JSON Schema or alter an existing schema for an entity type in real-time
|
|
192
|
+
*/
|
|
193
|
+
async define(definition) {
|
|
194
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/definition`;
|
|
195
|
+
const res = await this.fetchFn(url, {
|
|
196
|
+
method: "POST",
|
|
197
|
+
headers: this.getHeaders(),
|
|
198
|
+
body: JSON.stringify(definition)
|
|
199
|
+
});
|
|
200
|
+
if (!res.ok) {
|
|
201
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
202
|
+
throw new Error(err.message || `Failed to define schema for ${definition.typeName}`);
|
|
203
|
+
}
|
|
204
|
+
return res.json();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// src/query-builder.ts
|
|
209
|
+
var EntityQueryBuilder = class {
|
|
210
|
+
gatewayUrl;
|
|
211
|
+
tenantId;
|
|
212
|
+
typeName;
|
|
213
|
+
getToken;
|
|
214
|
+
fetchFn;
|
|
215
|
+
queryParams = new URLSearchParams();
|
|
216
|
+
constructor(options) {
|
|
217
|
+
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
218
|
+
this.tenantId = options.tenantId;
|
|
219
|
+
this.typeName = options.typeName;
|
|
220
|
+
this.getToken = options.getToken;
|
|
221
|
+
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
222
|
+
}
|
|
223
|
+
getHeaders() {
|
|
224
|
+
const headers = {
|
|
225
|
+
"Content-Type": "application/json",
|
|
226
|
+
"x-tenant-id": this.tenantId
|
|
227
|
+
};
|
|
228
|
+
const token = this.getToken();
|
|
229
|
+
if (token) {
|
|
230
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
231
|
+
}
|
|
232
|
+
return headers;
|
|
233
|
+
}
|
|
234
|
+
// ----------------------------------------------------
|
|
235
|
+
// Filter Operators
|
|
236
|
+
// ----------------------------------------------------
|
|
237
|
+
eq(field, value) {
|
|
238
|
+
this.queryParams.append(`${field}[eq]`, String(value));
|
|
239
|
+
return this;
|
|
240
|
+
}
|
|
241
|
+
ne(field, value) {
|
|
242
|
+
this.queryParams.append(`${field}[ne]`, String(value));
|
|
243
|
+
return this;
|
|
244
|
+
}
|
|
245
|
+
gt(field, value) {
|
|
246
|
+
this.queryParams.append(`${field}[gt]`, String(value));
|
|
247
|
+
return this;
|
|
248
|
+
}
|
|
249
|
+
gte(field, value) {
|
|
250
|
+
this.queryParams.append(`${field}[gte]`, String(value));
|
|
251
|
+
return this;
|
|
252
|
+
}
|
|
253
|
+
lt(field, value) {
|
|
254
|
+
this.queryParams.append(`${field}[lt]`, String(value));
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
257
|
+
lte(field, value) {
|
|
258
|
+
this.queryParams.append(`${field}[lte]`, String(value));
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Case-insensitive substring search (ILIKE %substring%)
|
|
263
|
+
*/
|
|
264
|
+
like(field, substring) {
|
|
265
|
+
this.queryParams.append(`${field}[like]`, substring);
|
|
266
|
+
return this;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Set membership: matches if field value is in the array
|
|
270
|
+
*/
|
|
271
|
+
in(field, values) {
|
|
272
|
+
this.queryParams.append(`${field}[in]`, values.map(String).join(","));
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
isNull(field) {
|
|
276
|
+
this.queryParams.append(`${field}[null]`, "true");
|
|
277
|
+
return this;
|
|
278
|
+
}
|
|
279
|
+
isNotNull(field) {
|
|
280
|
+
this.queryParams.append(`${field}[null]`, "false");
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Filter entities connected by graph relationship
|
|
285
|
+
*/
|
|
286
|
+
related(relationName, entityIds) {
|
|
287
|
+
const ids = Array.isArray(entityIds) ? entityIds.join(",") : entityIds;
|
|
288
|
+
this.queryParams.append(`related[${relationName}]`, ids);
|
|
289
|
+
return this;
|
|
290
|
+
}
|
|
291
|
+
// ----------------------------------------------------
|
|
292
|
+
// Sorting, Pagination & Modifiers
|
|
293
|
+
// ----------------------------------------------------
|
|
294
|
+
orderBy(field, direction = "asc") {
|
|
295
|
+
const sortVal = direction === "desc" ? `-${field}` : field;
|
|
296
|
+
this.queryParams.append("sort", sortVal);
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
limit(limit) {
|
|
300
|
+
this.queryParams.set("limit", String(limit));
|
|
301
|
+
return this;
|
|
302
|
+
}
|
|
303
|
+
page(page, limit) {
|
|
304
|
+
this.queryParams.set("page", String(page));
|
|
305
|
+
if (limit) this.queryParams.set("limit", String(limit));
|
|
306
|
+
return this;
|
|
307
|
+
}
|
|
308
|
+
offset(offset) {
|
|
309
|
+
this.queryParams.set("offset", String(offset));
|
|
310
|
+
return this;
|
|
311
|
+
}
|
|
312
|
+
cursor(token) {
|
|
313
|
+
this.queryParams.set("cursor", token);
|
|
314
|
+
return this;
|
|
315
|
+
}
|
|
316
|
+
flat(enabled = true) {
|
|
317
|
+
this.queryParams.set("flat", enabled ? "true" : "false");
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
// ----------------------------------------------------
|
|
321
|
+
// Execution Methods
|
|
322
|
+
// ----------------------------------------------------
|
|
323
|
+
/**
|
|
324
|
+
* Execute query and list matching records with pagination metadata
|
|
325
|
+
*/
|
|
326
|
+
async list() {
|
|
327
|
+
const qs = this.queryParams.toString();
|
|
328
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}${qs ? `?${qs}` : ""}`;
|
|
329
|
+
const res = await this.fetchFn(url, {
|
|
330
|
+
headers: this.getHeaders()
|
|
331
|
+
});
|
|
332
|
+
if (!res.ok) {
|
|
333
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
334
|
+
throw new Error(err.message || `Query failed with HTTP ${res.status}`);
|
|
335
|
+
}
|
|
336
|
+
return res.json();
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Fetch a single entity by ID
|
|
340
|
+
*/
|
|
341
|
+
async get(id) {
|
|
342
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;
|
|
343
|
+
const res = await this.fetchFn(url, {
|
|
344
|
+
headers: this.getHeaders()
|
|
345
|
+
});
|
|
346
|
+
if (!res.ok) {
|
|
347
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
348
|
+
throw new Error(err.message || `Failed to fetch ${this.typeName}/${id}`);
|
|
349
|
+
}
|
|
350
|
+
return res.json();
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Create a new entity record matching schema
|
|
354
|
+
*/
|
|
355
|
+
async create(data) {
|
|
356
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}`;
|
|
357
|
+
const res = await this.fetchFn(url, {
|
|
358
|
+
method: "POST",
|
|
359
|
+
headers: this.getHeaders(),
|
|
360
|
+
body: JSON.stringify(data)
|
|
361
|
+
});
|
|
362
|
+
if (!res.ok) {
|
|
363
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
364
|
+
throw new Error(err.message || `Failed to create record in ${this.typeName}`);
|
|
365
|
+
}
|
|
366
|
+
return res.json();
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Update an existing entity record
|
|
370
|
+
*/
|
|
371
|
+
async update(id, partialData) {
|
|
372
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;
|
|
373
|
+
const res = await this.fetchFn(url, {
|
|
374
|
+
method: "PATCH",
|
|
375
|
+
headers: this.getHeaders(),
|
|
376
|
+
body: JSON.stringify(partialData)
|
|
377
|
+
});
|
|
378
|
+
if (!res.ok) {
|
|
379
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
380
|
+
throw new Error(err.message || `Failed to update ${this.typeName}/${id}`);
|
|
381
|
+
}
|
|
382
|
+
return res.json();
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Soft-delete an entity record
|
|
386
|
+
*/
|
|
387
|
+
async delete(id) {
|
|
388
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;
|
|
389
|
+
const res = await this.fetchFn(url, {
|
|
390
|
+
method: "DELETE",
|
|
391
|
+
headers: this.getHeaders()
|
|
392
|
+
});
|
|
393
|
+
if (!res.ok) {
|
|
394
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
395
|
+
throw new Error(err.message || `Failed to delete ${this.typeName}/${id}`);
|
|
396
|
+
}
|
|
397
|
+
return { success: true };
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
// src/client.ts
|
|
402
|
+
var Zone4CodeClient = class {
|
|
403
|
+
gatewayUrl;
|
|
404
|
+
tenantId;
|
|
405
|
+
auth;
|
|
406
|
+
schema;
|
|
407
|
+
storage;
|
|
408
|
+
fetchFn;
|
|
409
|
+
constructor(config) {
|
|
410
|
+
if (!config.gatewayUrl) {
|
|
411
|
+
throw new Error("Zone4CodeClient requires a `gatewayUrl` (e.g., http://localhost:8080)");
|
|
412
|
+
}
|
|
413
|
+
if (!config.tenantId) {
|
|
414
|
+
throw new Error("Zone4CodeClient requires a `tenantId` (workspace identifier)");
|
|
415
|
+
}
|
|
416
|
+
this.gatewayUrl = config.gatewayUrl.replace(/\/+$/, "");
|
|
417
|
+
this.tenantId = config.tenantId;
|
|
418
|
+
this.storage = config.storage || getDefaultStorage();
|
|
419
|
+
this.fetchFn = config.fetch || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
420
|
+
this.auth = new AuthClient({
|
|
421
|
+
gatewayUrl: this.gatewayUrl,
|
|
422
|
+
tenantId: this.tenantId,
|
|
423
|
+
storage: this.storage,
|
|
424
|
+
initialToken: config.token,
|
|
425
|
+
fetchFn: this.fetchFn
|
|
426
|
+
});
|
|
427
|
+
this.schema = new SchemaClient({
|
|
428
|
+
gatewayUrl: this.gatewayUrl,
|
|
429
|
+
tenantId: this.tenantId,
|
|
430
|
+
getToken: () => this.auth.getToken(),
|
|
431
|
+
fetchFn: this.fetchFn
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Access an entity collection with chainable query builder (like Supabase .from('orders'))
|
|
436
|
+
*/
|
|
437
|
+
from(typeName) {
|
|
438
|
+
return new EntityQueryBuilder({
|
|
439
|
+
gatewayUrl: this.gatewayUrl,
|
|
440
|
+
tenantId: this.tenantId,
|
|
441
|
+
typeName,
|
|
442
|
+
getToken: () => this.auth.getToken(),
|
|
443
|
+
fetchFn: this.fetchFn
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Alias for .from(typeName)
|
|
448
|
+
*/
|
|
449
|
+
entities(typeName) {
|
|
450
|
+
return this.from(typeName);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Check gateway connectivity & health
|
|
454
|
+
*/
|
|
455
|
+
async health() {
|
|
456
|
+
const res = await this.fetchFn(`${this.gatewayUrl}/health`);
|
|
457
|
+
if (!res.ok) {
|
|
458
|
+
throw new Error(`Gateway health check failed with HTTP ${res.status}`);
|
|
459
|
+
}
|
|
460
|
+
return res.json();
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
function createClient(config) {
|
|
464
|
+
return new Zone4CodeClient(config);
|
|
465
|
+
}
|
|
466
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
467
|
+
0 && (module.exports = {
|
|
468
|
+
AuthClient,
|
|
469
|
+
EntityQueryBuilder,
|
|
470
|
+
MemoryStorage,
|
|
471
|
+
SchemaClient,
|
|
472
|
+
Zone4CodeClient,
|
|
473
|
+
createClient,
|
|
474
|
+
getDefaultStorage
|
|
475
|
+
});
|
|
476
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/storage.ts","../src/auth.ts","../src/schema.ts","../src/query-builder.ts","../src/client.ts"],"sourcesContent":["export * from './types';\nexport * from './storage';\nexport * from './auth';\nexport * from './schema';\nexport * from './query-builder';\nexport * from './client';\n\nexport { createClient as default } from './client';\n","import { StorageAdapter } from './types';\n\nexport class MemoryStorage implements StorageAdapter {\n private store = new Map<string, string>();\n\n getItem(key: string): string | null {\n return this.store.get(key) ?? null;\n }\n\n setItem(key: string, value: string): void {\n this.store.set(key, value);\n }\n\n removeItem(key: string): void {\n this.store.delete(key);\n }\n}\n\nexport function getDefaultStorage(): StorageAdapter {\n if (typeof window !== 'undefined' && window.localStorage) {\n return window.localStorage;\n }\n return new MemoryStorage();\n}\n","import { AuthResponse, AuthUser, StorageAdapter } from './types';\n\nexport class AuthClient {\n private gatewayUrl: string;\n private tenantId: string;\n private storage: StorageAdapter;\n private token: string | null = null;\n private fetchFn: typeof fetch;\n\n private static TOKEN_KEY_PREFIX = 'z4c_token_';\n\n constructor(options: {\n gatewayUrl: string;\n tenantId: string;\n storage: StorageAdapter;\n initialToken?: string;\n fetchFn?: typeof fetch;\n }) {\n this.gatewayUrl = options.gatewayUrl.replace(/\\/+$/, '');\n this.tenantId = options.tenantId;\n this.storage = options.storage;\n this.fetchFn = options.fetchFn || (typeof fetch !== 'undefined' ? fetch : (globalThis.fetch as any));\n\n if (options.initialToken) {\n this.setToken(options.initialToken);\n } else {\n // Attempt load from storage\n Promise.resolve(this.storage.getItem(AuthClient.TOKEN_KEY_PREFIX + this.tenantId))\n .then((stored) => {\n if (stored) this.token = stored;\n })\n .catch(() => {});\n }\n }\n\n public getToken(): string | null {\n return this.token;\n }\n\n public setToken(token: string | null): void {\n this.token = token;\n const storageKey = AuthClient.TOKEN_KEY_PREFIX + this.tenantId;\n if (token) {\n this.storage.setItem(storageKey, token);\n } else {\n this.storage.removeItem(storageKey);\n }\n }\n\n public isAuthenticated(): boolean {\n return !!this.token;\n }\n\n /**\n * Register a new user in the tenant realm\n */\n async register(data: {\n email: string;\n password: string;\n name?: string;\n username?: string;\n attributes?: Record<string, any>;\n }): Promise<AuthResponse> {\n const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/register`;\n const res = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-tenant-id': this.tenantId\n },\n body: JSON.stringify(data)\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || err.error || `Registration failed with HTTP ${res.status}`);\n }\n\n const json = await res.json();\n const token = json.token || json.access_token;\n if (token) {\n this.setToken(token);\n }\n return json;\n }\n\n /**\n * Log in an existing user and store their JWT token\n */\n async login(credentials: {\n email?: string;\n username?: string;\n password: string;\n }): Promise<AuthResponse> {\n const url = `${this.gatewayUrl}/auth/${this.tenantId}/login`;\n const res = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-tenant-id': this.tenantId\n },\n body: JSON.stringify(credentials)\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || err.error || `Login failed with HTTP ${res.status}`);\n }\n\n const json = await res.json();\n const token = json.token || json.access_token;\n if (token) {\n this.setToken(token);\n }\n return json;\n }\n\n /**\n * Fetch current authenticated user profile\n */\n async getProfile(): Promise<AuthUser> {\n if (!this.token) {\n throw new Error('Not authenticated: please call login() or setToken() first');\n }\n\n const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/profile`;\n const res = await this.fetchFn(url, {\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'x-tenant-id': this.tenantId\n }\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || `Failed to fetch profile (HTTP ${res.status})`);\n }\n\n return res.json();\n }\n\n /**\n * Log out and clear saved token\n */\n logout(): void {\n this.setToken(null);\n }\n}\n","import { EntitySchemaDefinition } from './types';\n\nexport class SchemaClient {\n private gatewayUrl: string;\n private tenantId: string;\n private getToken: () => string | null;\n private fetchFn: typeof fetch;\n\n constructor(options: {\n gatewayUrl: string;\n tenantId: string;\n getToken: () => string | null;\n fetchFn?: typeof fetch;\n }) {\n this.gatewayUrl = options.gatewayUrl.replace(/\\/+$/, '');\n this.tenantId = options.tenantId;\n this.getToken = options.getToken;\n this.fetchFn = options.fetchFn || (typeof fetch !== 'undefined' ? fetch : (globalThis.fetch as any));\n }\n\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-tenant-id': this.tenantId\n };\n const token = this.getToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n return headers;\n }\n\n /**\n * Define a new JSON Schema or alter an existing schema for an entity type in real-time\n */\n async define(definition: EntitySchemaDefinition): Promise<{ success: boolean; version?: number }> {\n const url = `${this.gatewayUrl}/generic/${this.tenantId}/definition`;\n const res = await this.fetchFn(url, {\n method: 'POST',\n headers: this.getHeaders(),\n body: JSON.stringify(definition)\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || `Failed to define schema for ${definition.typeName}`);\n }\n\n return res.json();\n }\n}\n","import { EntityListResponse, EntityRecord, FilterOperator } from './types';\n\nexport class EntityQueryBuilder<T = Record<string, any>> {\n private gatewayUrl: string;\n private tenantId: string;\n private typeName: string;\n private getToken: () => string | null;\n private fetchFn: typeof fetch;\n\n private queryParams = new URLSearchParams();\n\n constructor(options: {\n gatewayUrl: string;\n tenantId: string;\n typeName: string;\n getToken: () => string | null;\n fetchFn?: typeof fetch;\n }) {\n this.gatewayUrl = options.gatewayUrl.replace(/\\/+$/, '');\n this.tenantId = options.tenantId;\n this.typeName = options.typeName;\n this.getToken = options.getToken;\n this.fetchFn = options.fetchFn || (typeof fetch !== 'undefined' ? fetch : (globalThis.fetch as any));\n }\n\n private getHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'x-tenant-id': this.tenantId\n };\n const token = this.getToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n return headers;\n }\n\n // ----------------------------------------------------\n // Filter Operators\n // ----------------------------------------------------\n\n eq(field: string, value: string | number | boolean): this {\n this.queryParams.append(`${field}[eq]`, String(value));\n return this;\n }\n\n ne(field: string, value: string | number | boolean): this {\n this.queryParams.append(`${field}[ne]`, String(value));\n return this;\n }\n\n gt(field: string, value: number): this {\n this.queryParams.append(`${field}[gt]`, String(value));\n return this;\n }\n\n gte(field: string, value: number): this {\n this.queryParams.append(`${field}[gte]`, String(value));\n return this;\n }\n\n lt(field: string, value: number): this {\n this.queryParams.append(`${field}[lt]`, String(value));\n return this;\n }\n\n lte(field: string, value: number): this {\n this.queryParams.append(`${field}[lte]`, String(value));\n return this;\n }\n\n /**\n * Case-insensitive substring search (ILIKE %substring%)\n */\n like(field: string, substring: string): this {\n this.queryParams.append(`${field}[like]`, substring);\n return this;\n }\n\n /**\n * Set membership: matches if field value is in the array\n */\n in(field: string, values: Array<string | number>): this {\n this.queryParams.append(`${field}[in]`, values.map(String).join(','));\n return this;\n }\n\n isNull(field: string): this {\n this.queryParams.append(`${field}[null]`, 'true');\n return this;\n }\n\n isNotNull(field: string): this {\n this.queryParams.append(`${field}[null]`, 'false');\n return this;\n }\n\n /**\n * Filter entities connected by graph relationship\n */\n related(relationName: string, entityIds: string | string[]): this {\n const ids = Array.isArray(entityIds) ? entityIds.join(',') : entityIds;\n this.queryParams.append(`related[${relationName}]`, ids);\n return this;\n }\n\n // ----------------------------------------------------\n // Sorting, Pagination & Modifiers\n // ----------------------------------------------------\n\n orderBy(field: string, direction: 'asc' | 'desc' = 'asc'): this {\n const sortVal = direction === 'desc' ? `-${field}` : field;\n this.queryParams.append('sort', sortVal);\n return this;\n }\n\n limit(limit: number): this {\n this.queryParams.set('limit', String(limit));\n return this;\n }\n\n page(page: number, limit?: number): this {\n this.queryParams.set('page', String(page));\n if (limit) this.queryParams.set('limit', String(limit));\n return this;\n }\n\n offset(offset: number): this {\n this.queryParams.set('offset', String(offset));\n return this;\n }\n\n cursor(token: string): this {\n this.queryParams.set('cursor', token);\n return this;\n }\n\n flat(enabled: boolean = true): this {\n this.queryParams.set('flat', enabled ? 'true' : 'false');\n return this;\n }\n\n // ----------------------------------------------------\n // Execution Methods\n // ----------------------------------------------------\n\n /**\n * Execute query and list matching records with pagination metadata\n */\n async list(): Promise<EntityListResponse<T>> {\n const qs = this.queryParams.toString();\n const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}${qs ? `?${qs}` : ''}`;\n \n const res = await this.fetchFn(url, {\n headers: this.getHeaders()\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || `Query failed with HTTP ${res.status}`);\n }\n\n return res.json();\n }\n\n /**\n * Fetch a single entity by ID\n */\n async get(id: string): Promise<EntityRecord<T>> {\n const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;\n const res = await this.fetchFn(url, {\n headers: this.getHeaders()\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || `Failed to fetch ${this.typeName}/${id}`);\n }\n\n return res.json();\n }\n\n /**\n * Create a new entity record matching schema\n */\n async create(data: T): Promise<EntityRecord<T>> {\n const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}`;\n const res = await this.fetchFn(url, {\n method: 'POST',\n headers: this.getHeaders(),\n body: JSON.stringify(data)\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || `Failed to create record in ${this.typeName}`);\n }\n\n return res.json();\n }\n\n /**\n * Update an existing entity record\n */\n async update(id: string, partialData: Partial<T>): Promise<EntityRecord<T>> {\n const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;\n const res = await this.fetchFn(url, {\n method: 'PATCH',\n headers: this.getHeaders(),\n body: JSON.stringify(partialData)\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || `Failed to update ${this.typeName}/${id}`);\n }\n\n return res.json();\n }\n\n /**\n * Soft-delete an entity record\n */\n async delete(id: string): Promise<{ success: boolean }> {\n const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;\n const res = await this.fetchFn(url, {\n method: 'DELETE',\n headers: this.getHeaders()\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(err.message || `Failed to delete ${this.typeName}/${id}`);\n }\n\n return { success: true };\n }\n}\n","import { AuthClient } from './auth';\nimport { EntityQueryBuilder } from './query-builder';\nimport { SchemaClient } from './schema';\nimport { getDefaultStorage } from './storage';\nimport { StorageAdapter, Zone4CodeConfig } from './types';\n\nexport class Zone4CodeClient {\n public readonly gatewayUrl: string;\n public readonly tenantId: string;\n public readonly auth: AuthClient;\n public readonly schema: SchemaClient;\n\n private storage: StorageAdapter;\n private fetchFn: typeof fetch;\n\n constructor(config: Zone4CodeConfig) {\n if (!config.gatewayUrl) {\n throw new Error('Zone4CodeClient requires a `gatewayUrl` (e.g., http://localhost:8080)');\n }\n if (!config.tenantId) {\n throw new Error('Zone4CodeClient requires a `tenantId` (workspace identifier)');\n }\n\n this.gatewayUrl = config.gatewayUrl.replace(/\\/+$/, '');\n this.tenantId = config.tenantId;\n this.storage = config.storage || getDefaultStorage();\n this.fetchFn = config.fetch || (typeof fetch !== 'undefined' ? fetch : (globalThis.fetch as any));\n\n this.auth = new AuthClient({\n gatewayUrl: this.gatewayUrl,\n tenantId: this.tenantId,\n storage: this.storage,\n initialToken: config.token,\n fetchFn: this.fetchFn\n });\n\n this.schema = new SchemaClient({\n gatewayUrl: this.gatewayUrl,\n tenantId: this.tenantId,\n getToken: () => this.auth.getToken(),\n fetchFn: this.fetchFn\n });\n }\n\n /**\n * Access an entity collection with chainable query builder (like Supabase .from('orders'))\n */\n public from<T = Record<string, any>>(typeName: string): EntityQueryBuilder<T> {\n return new EntityQueryBuilder<T>({\n gatewayUrl: this.gatewayUrl,\n tenantId: this.tenantId,\n typeName,\n getToken: () => this.auth.getToken(),\n fetchFn: this.fetchFn\n });\n }\n\n /**\n * Alias for .from(typeName)\n */\n public entities<T = Record<string, any>>(typeName: string): EntityQueryBuilder<T> {\n return this.from<T>(typeName);\n }\n\n /**\n * Check gateway connectivity & health\n */\n public async health(): Promise<{ status: string; licenseTier?: string }> {\n const res = await this.fetchFn(`${this.gatewayUrl}/health`);\n if (!res.ok) {\n throw new Error(`Gateway health check failed with HTTP ${res.status}`);\n }\n return res.json();\n }\n}\n\n/**\n * Factory function to instantiate a new Zone4Code client\n */\nexport function createClient(config: Zone4CodeConfig): Zone4CodeClient {\n return new Zone4CodeClient(config);\n}\n"],"mappings":"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","names":[]}
|