zone4code-sdk 1.0.2 → 1.0.4
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 +94 -16
- package/dist/index.cjs +415 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +166 -31
- package/dist/index.d.ts +166 -31
- package/dist/index.js +415 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
// src/storage.ts
|
|
2
|
-
var MemoryStorage = class {
|
|
3
|
-
store = /* @__PURE__ */ new Map();
|
|
4
|
-
getItem(key) {
|
|
5
|
-
return this.store.get(key) ?? null;
|
|
6
|
-
}
|
|
7
|
-
setItem(key, value) {
|
|
8
|
-
this.store.set(key, value);
|
|
9
|
-
}
|
|
10
|
-
removeItem(key) {
|
|
11
|
-
this.store.delete(key);
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
function getDefaultStorage() {
|
|
15
|
-
if (typeof window !== "undefined" && window.localStorage) {
|
|
16
|
-
return window.localStorage;
|
|
17
|
-
}
|
|
18
|
-
return new MemoryStorage();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
1
|
// src/auth.ts
|
|
22
2
|
function decodeJwtPayload(token) {
|
|
23
3
|
try {
|
|
@@ -42,7 +22,9 @@ var AuthClient = class _AuthClient {
|
|
|
42
22
|
tenantId;
|
|
43
23
|
storage;
|
|
44
24
|
storageKey;
|
|
25
|
+
refreshStorageKey;
|
|
45
26
|
token = null;
|
|
27
|
+
refreshTokenValue = null;
|
|
46
28
|
fetchFn;
|
|
47
29
|
static TOKEN_KEY_PREFIX = "z4c_token_";
|
|
48
30
|
constructor(options) {
|
|
@@ -50,6 +32,7 @@ var AuthClient = class _AuthClient {
|
|
|
50
32
|
this.tenantId = options.tenantId;
|
|
51
33
|
this.storage = options.storage;
|
|
52
34
|
this.storageKey = options.storageKey || _AuthClient.TOKEN_KEY_PREFIX + this.tenantId;
|
|
35
|
+
this.refreshStorageKey = this.storageKey + "_refresh";
|
|
53
36
|
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
54
37
|
if (options.initialToken) {
|
|
55
38
|
this.setToken(options.initialToken);
|
|
@@ -58,11 +41,18 @@ var AuthClient = class _AuthClient {
|
|
|
58
41
|
if (stored) this.token = stored;
|
|
59
42
|
}).catch(() => {
|
|
60
43
|
});
|
|
44
|
+
Promise.resolve(this.storage.getItem(this.refreshStorageKey)).then((stored) => {
|
|
45
|
+
if (stored) this.refreshTokenValue = stored;
|
|
46
|
+
}).catch(() => {
|
|
47
|
+
});
|
|
61
48
|
}
|
|
62
49
|
}
|
|
63
50
|
getToken() {
|
|
64
51
|
return this.token;
|
|
65
52
|
}
|
|
53
|
+
getRefreshToken() {
|
|
54
|
+
return this.refreshTokenValue;
|
|
55
|
+
}
|
|
66
56
|
setToken(token) {
|
|
67
57
|
this.token = token;
|
|
68
58
|
if (token) {
|
|
@@ -71,6 +61,14 @@ var AuthClient = class _AuthClient {
|
|
|
71
61
|
this.storage.removeItem(this.storageKey);
|
|
72
62
|
}
|
|
73
63
|
}
|
|
64
|
+
setRefreshToken(token) {
|
|
65
|
+
this.refreshTokenValue = token;
|
|
66
|
+
if (token) {
|
|
67
|
+
this.storage.setItem(this.refreshStorageKey, token);
|
|
68
|
+
} else {
|
|
69
|
+
this.storage.removeItem(this.refreshStorageKey);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
74
72
|
isAuthenticated() {
|
|
75
73
|
return !!this.token;
|
|
76
74
|
}
|
|
@@ -179,6 +177,9 @@ var AuthClient = class _AuthClient {
|
|
|
179
177
|
if (token) {
|
|
180
178
|
this.setToken(token);
|
|
181
179
|
}
|
|
180
|
+
if (json.refresh_token) {
|
|
181
|
+
this.setRefreshToken(json.refresh_token);
|
|
182
|
+
}
|
|
182
183
|
const user = this.getUser() || json.user;
|
|
183
184
|
return {
|
|
184
185
|
token: token || "",
|
|
@@ -187,6 +188,163 @@ var AuthClient = class _AuthClient {
|
|
|
187
188
|
...json
|
|
188
189
|
};
|
|
189
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Authenticate via Google OAuth ID token
|
|
193
|
+
*/
|
|
194
|
+
async loginWithGoogle(token) {
|
|
195
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/login/google`;
|
|
196
|
+
const res = await this.fetchFn(url, {
|
|
197
|
+
method: "POST",
|
|
198
|
+
headers: {
|
|
199
|
+
"Content-Type": "application/json",
|
|
200
|
+
"x-tenant-id": this.tenantId
|
|
201
|
+
},
|
|
202
|
+
body: JSON.stringify({ token })
|
|
203
|
+
});
|
|
204
|
+
if (!res.ok) {
|
|
205
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
206
|
+
throw new Error(err.message || err.error || `Google login failed with HTTP ${res.status}`);
|
|
207
|
+
}
|
|
208
|
+
const json = await res.json();
|
|
209
|
+
const jwt = json.token || json.access_token;
|
|
210
|
+
if (jwt) {
|
|
211
|
+
this.setToken(jwt);
|
|
212
|
+
}
|
|
213
|
+
if (json.refresh_token) {
|
|
214
|
+
this.setRefreshToken(json.refresh_token);
|
|
215
|
+
}
|
|
216
|
+
const user = this.getUser() || json.user;
|
|
217
|
+
return {
|
|
218
|
+
token: jwt || "",
|
|
219
|
+
refreshToken: json.refresh_token,
|
|
220
|
+
user,
|
|
221
|
+
...json
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Renew expired access token using stored or provided refresh token
|
|
226
|
+
*/
|
|
227
|
+
async refreshToken(refreshToken) {
|
|
228
|
+
const tokenToUse = refreshToken || this.getRefreshToken();
|
|
229
|
+
if (!tokenToUse) {
|
|
230
|
+
throw new Error("No refresh token available");
|
|
231
|
+
}
|
|
232
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/refresh`;
|
|
233
|
+
const res = await this.fetchFn(url, {
|
|
234
|
+
method: "POST",
|
|
235
|
+
headers: {
|
|
236
|
+
"Content-Type": "application/json",
|
|
237
|
+
"x-tenant-id": this.tenantId
|
|
238
|
+
},
|
|
239
|
+
body: JSON.stringify({ refresh_token: tokenToUse })
|
|
240
|
+
});
|
|
241
|
+
if (!res.ok) {
|
|
242
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
243
|
+
throw new Error(err.message || err.error || `Token refresh failed with HTTP ${res.status}`);
|
|
244
|
+
}
|
|
245
|
+
const json = await res.json();
|
|
246
|
+
const token = json.token || json.access_token;
|
|
247
|
+
if (token) {
|
|
248
|
+
this.setToken(token);
|
|
249
|
+
}
|
|
250
|
+
if (json.refresh_token) {
|
|
251
|
+
this.setRefreshToken(json.refresh_token);
|
|
252
|
+
}
|
|
253
|
+
const user = this.getUser() || json.user;
|
|
254
|
+
return {
|
|
255
|
+
token: token || "",
|
|
256
|
+
refreshToken: json.refresh_token,
|
|
257
|
+
user,
|
|
258
|
+
...json
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Request password reset email
|
|
263
|
+
*/
|
|
264
|
+
async forgotPassword(data) {
|
|
265
|
+
const payload = typeof data === "string" ? { email: data } : data;
|
|
266
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/auth/forgot-password`;
|
|
267
|
+
const res = await this.fetchFn(url, {
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: {
|
|
270
|
+
"Content-Type": "application/json",
|
|
271
|
+
"x-tenant-id": this.tenantId
|
|
272
|
+
},
|
|
273
|
+
body: JSON.stringify(payload)
|
|
274
|
+
});
|
|
275
|
+
const json = await res.json().catch(() => ({}));
|
|
276
|
+
if (!res.ok) {
|
|
277
|
+
throw new Error(json.message || json.error || `Forgot password request failed with HTTP ${res.status}`);
|
|
278
|
+
}
|
|
279
|
+
return json;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Complete password reset using action token
|
|
283
|
+
*/
|
|
284
|
+
async resetPassword(data) {
|
|
285
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/auth/reset-password`;
|
|
286
|
+
const res = await this.fetchFn(url, {
|
|
287
|
+
method: "POST",
|
|
288
|
+
headers: {
|
|
289
|
+
"Content-Type": "application/json",
|
|
290
|
+
"x-tenant-id": this.tenantId
|
|
291
|
+
},
|
|
292
|
+
body: JSON.stringify(data)
|
|
293
|
+
});
|
|
294
|
+
const json = await res.json().catch(() => ({}));
|
|
295
|
+
if (!res.ok) {
|
|
296
|
+
throw new Error(json.message || json.error || `Reset password failed with HTTP ${res.status}`);
|
|
297
|
+
}
|
|
298
|
+
return json;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Change password for current or specified user
|
|
302
|
+
*/
|
|
303
|
+
async changePassword(data, userId) {
|
|
304
|
+
const targetUserId = userId || this.getUser()?.id;
|
|
305
|
+
if (!targetUserId) {
|
|
306
|
+
throw new Error("User ID required: user is not logged in and no userId was provided");
|
|
307
|
+
}
|
|
308
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/${targetUserId}/change-password`;
|
|
309
|
+
const res = await this.fetchFn(url, {
|
|
310
|
+
method: "POST",
|
|
311
|
+
headers: {
|
|
312
|
+
"Content-Type": "application/json",
|
|
313
|
+
"x-tenant-id": this.tenantId,
|
|
314
|
+
...this.token ? { "Authorization": `Bearer ${this.token}` } : {}
|
|
315
|
+
},
|
|
316
|
+
body: JSON.stringify(data)
|
|
317
|
+
});
|
|
318
|
+
if (!res.ok) {
|
|
319
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
320
|
+
throw new Error(err.message || err.error || `Change password failed with HTTP ${res.status}`);
|
|
321
|
+
}
|
|
322
|
+
return res.json().catch(() => ({ success: true }));
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Update profile attributes for current or specified user
|
|
326
|
+
*/
|
|
327
|
+
async updateProfile(data, userId) {
|
|
328
|
+
const targetUserId = userId || this.getUser()?.id;
|
|
329
|
+
if (!targetUserId) {
|
|
330
|
+
throw new Error("User ID required: user is not logged in and no userId was provided");
|
|
331
|
+
}
|
|
332
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/${targetUserId}`;
|
|
333
|
+
const res = await this.fetchFn(url, {
|
|
334
|
+
method: "PUT",
|
|
335
|
+
headers: {
|
|
336
|
+
"Content-Type": "application/json",
|
|
337
|
+
"x-tenant-id": this.tenantId,
|
|
338
|
+
...this.token ? { "Authorization": `Bearer ${this.token}` } : {}
|
|
339
|
+
},
|
|
340
|
+
body: JSON.stringify(data)
|
|
341
|
+
});
|
|
342
|
+
if (!res.ok) {
|
|
343
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
344
|
+
throw new Error(err.message || err.error || `Update profile failed with HTTP ${res.status}`);
|
|
345
|
+
}
|
|
346
|
+
return res.json();
|
|
347
|
+
}
|
|
190
348
|
/**
|
|
191
349
|
* Fetch current authenticated user profile
|
|
192
350
|
*/
|
|
@@ -212,51 +370,11 @@ var AuthClient = class _AuthClient {
|
|
|
212
370
|
return res.json();
|
|
213
371
|
}
|
|
214
372
|
/**
|
|
215
|
-
* Log out and clear saved
|
|
373
|
+
* Log out and clear saved tokens
|
|
216
374
|
*/
|
|
217
375
|
logout() {
|
|
218
376
|
this.setToken(null);
|
|
219
|
-
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
// src/schema.ts
|
|
223
|
-
var SchemaClient = class {
|
|
224
|
-
gatewayUrl;
|
|
225
|
-
tenantId;
|
|
226
|
-
getToken;
|
|
227
|
-
fetchFn;
|
|
228
|
-
constructor(options) {
|
|
229
|
-
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
230
|
-
this.tenantId = options.tenantId;
|
|
231
|
-
this.getToken = options.getToken;
|
|
232
|
-
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
233
|
-
}
|
|
234
|
-
getHeaders() {
|
|
235
|
-
const headers = {
|
|
236
|
-
"Content-Type": "application/json",
|
|
237
|
-
"x-tenant-id": this.tenantId
|
|
238
|
-
};
|
|
239
|
-
const token = this.getToken();
|
|
240
|
-
if (token) {
|
|
241
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
242
|
-
}
|
|
243
|
-
return headers;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Define a new JSON Schema or alter an existing schema for an entity type in real-time
|
|
247
|
-
*/
|
|
248
|
-
async define(definition) {
|
|
249
|
-
const url = `${this.gatewayUrl}/generic/${this.tenantId}/definition`;
|
|
250
|
-
const res = await this.fetchFn(url, {
|
|
251
|
-
method: "POST",
|
|
252
|
-
headers: this.getHeaders(),
|
|
253
|
-
body: JSON.stringify(definition)
|
|
254
|
-
});
|
|
255
|
-
if (!res.ok) {
|
|
256
|
-
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
257
|
-
throw new Error(err.message || `Failed to define schema for ${definition.typeName}`);
|
|
258
|
-
}
|
|
259
|
-
return res.json();
|
|
377
|
+
this.setRefreshToken(null);
|
|
260
378
|
}
|
|
261
379
|
};
|
|
262
380
|
|
|
@@ -343,6 +461,19 @@ var EntityQueryBuilder = class {
|
|
|
343
461
|
this.queryParams.append(`related[${relationName}]`, ids);
|
|
344
462
|
return this;
|
|
345
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Declaratively expand graph relations (Supabase-style join expansion)
|
|
466
|
+
* Example: .include('placed_by', 'payment', 'items')
|
|
467
|
+
*/
|
|
468
|
+
include(...relations) {
|
|
469
|
+
const existing = this.queryParams.get("include");
|
|
470
|
+
const existingList = existing ? existing.split(",").map((s) => s.trim()) : [];
|
|
471
|
+
const combined = Array.from(/* @__PURE__ */ new Set([...existingList, ...relations.map((s) => s.trim())])).filter(Boolean);
|
|
472
|
+
if (combined.length > 0) {
|
|
473
|
+
this.queryParams.set("include", combined.join(","));
|
|
474
|
+
}
|
|
475
|
+
return this;
|
|
476
|
+
}
|
|
346
477
|
// ----------------------------------------------------
|
|
347
478
|
// Sorting, Pagination & Modifiers
|
|
348
479
|
// ----------------------------------------------------
|
|
@@ -391,10 +522,21 @@ var EntityQueryBuilder = class {
|
|
|
391
522
|
return res.json();
|
|
392
523
|
}
|
|
393
524
|
/**
|
|
394
|
-
* Fetch a single entity by ID
|
|
525
|
+
* Fetch a single entity by ID with optional expansion and flattening
|
|
395
526
|
*/
|
|
396
|
-
async get(id) {
|
|
397
|
-
const
|
|
527
|
+
async get(id, options) {
|
|
528
|
+
const params = new URLSearchParams(this.queryParams);
|
|
529
|
+
if (options?.flat !== void 0) {
|
|
530
|
+
params.set("flat", options.flat ? "true" : "false");
|
|
531
|
+
}
|
|
532
|
+
if (options?.include && options.include.length > 0) {
|
|
533
|
+
const existing = params.get("include");
|
|
534
|
+
const existingList = existing ? existing.split(",").map((s) => s.trim()) : [];
|
|
535
|
+
const combined = Array.from(/* @__PURE__ */ new Set([...existingList, ...options.include.map((s) => s.trim())])).filter(Boolean);
|
|
536
|
+
params.set("include", combined.join(","));
|
|
537
|
+
}
|
|
538
|
+
const qs = params.toString();
|
|
539
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}${qs ? `?${qs}` : ""}`;
|
|
398
540
|
const res = await this.fetchFn(url, {
|
|
399
541
|
headers: this.getHeaders()
|
|
400
542
|
});
|
|
@@ -451,7 +593,194 @@ var EntityQueryBuilder = class {
|
|
|
451
593
|
}
|
|
452
594
|
return { success: true };
|
|
453
595
|
}
|
|
596
|
+
/**
|
|
597
|
+
* Fetch revision history for an entity record
|
|
598
|
+
*/
|
|
599
|
+
async revisions(id) {
|
|
600
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/revisions`;
|
|
601
|
+
const res = await this.fetchFn(url, {
|
|
602
|
+
headers: this.getHeaders()
|
|
603
|
+
});
|
|
604
|
+
if (!res.ok) {
|
|
605
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
606
|
+
throw new Error(err.message || `Failed to fetch revisions for ${this.typeName}/${id}`);
|
|
607
|
+
}
|
|
608
|
+
return res.json();
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Fetch all graph relations for this entity record
|
|
612
|
+
*/
|
|
613
|
+
async getRelations(id, lang) {
|
|
614
|
+
const qs = lang ? `?lang=${encodeURIComponent(lang)}` : "";
|
|
615
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations${qs}`;
|
|
616
|
+
const res = await this.fetchFn(url, {
|
|
617
|
+
headers: this.getHeaders()
|
|
618
|
+
});
|
|
619
|
+
if (!res.ok) {
|
|
620
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
621
|
+
throw new Error(err.message || `Failed to fetch relations for ${this.typeName}/${id}`);
|
|
622
|
+
}
|
|
623
|
+
return res.json();
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Link this record to another entity record
|
|
627
|
+
*/
|
|
628
|
+
async link(id, payload) {
|
|
629
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations`;
|
|
630
|
+
const res = await this.fetchFn(url, {
|
|
631
|
+
method: "POST",
|
|
632
|
+
headers: this.getHeaders(),
|
|
633
|
+
body: JSON.stringify(payload)
|
|
634
|
+
});
|
|
635
|
+
if (!res.ok) {
|
|
636
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
637
|
+
throw new Error(err.message || `Failed to create relation for ${this.typeName}/${id}`);
|
|
638
|
+
}
|
|
639
|
+
return res.json().catch(() => ({ success: true }));
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Replace the full set of relations of one relation name
|
|
643
|
+
*/
|
|
644
|
+
async setLinks(id, payload) {
|
|
645
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations`;
|
|
646
|
+
const res = await this.fetchFn(url, {
|
|
647
|
+
method: "PUT",
|
|
648
|
+
headers: this.getHeaders(),
|
|
649
|
+
body: JSON.stringify(payload)
|
|
650
|
+
});
|
|
651
|
+
if (!res.ok) {
|
|
652
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
653
|
+
throw new Error(err.message || `Failed to replace relations for ${this.typeName}/${id}`);
|
|
654
|
+
}
|
|
655
|
+
return res.json().catch(() => ({ success: true }));
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Remove one graph link between two records
|
|
659
|
+
*/
|
|
660
|
+
async unlink(id, relationName, targetId, targetTypeName) {
|
|
661
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations/${encodeURIComponent(relationName)}/${encodeURIComponent(targetId)}?targetTypeName=${encodeURIComponent(targetTypeName)}`;
|
|
662
|
+
const res = await this.fetchFn(url, {
|
|
663
|
+
method: "DELETE",
|
|
664
|
+
headers: this.getHeaders()
|
|
665
|
+
});
|
|
666
|
+
if (!res.ok) {
|
|
667
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
668
|
+
throw new Error(err.message || `Failed to delete relation ${relationName} for ${this.typeName}/${id}`);
|
|
669
|
+
}
|
|
670
|
+
return res.json().catch(() => ({ success: true }));
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Execute a type-level workflow plugin action (e.g. checkout, batch-process)
|
|
674
|
+
*/
|
|
675
|
+
async action(actionName, payload) {
|
|
676
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/actions/${actionName}`;
|
|
677
|
+
const res = await this.fetchFn(url, {
|
|
678
|
+
method: "POST",
|
|
679
|
+
headers: this.getHeaders(),
|
|
680
|
+
body: payload ? JSON.stringify(payload) : void 0
|
|
681
|
+
});
|
|
682
|
+
if (!res.ok) {
|
|
683
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
684
|
+
throw new Error(err.message || `Action ${actionName} failed on type ${this.typeName}`);
|
|
685
|
+
}
|
|
686
|
+
return res.json();
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Execute an instance-level workflow plugin action (e.g. cancel order, approve)
|
|
690
|
+
*/
|
|
691
|
+
async instanceAction(id, actionName, payload) {
|
|
692
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/actions/${actionName}`;
|
|
693
|
+
const res = await this.fetchFn(url, {
|
|
694
|
+
method: "POST",
|
|
695
|
+
headers: this.getHeaders(),
|
|
696
|
+
body: payload ? JSON.stringify(payload) : void 0
|
|
697
|
+
});
|
|
698
|
+
if (!res.ok) {
|
|
699
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
700
|
+
throw new Error(err.message || `Action ${actionName} failed on ${this.typeName}/${id}`);
|
|
701
|
+
}
|
|
702
|
+
return res.json();
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Export matching entity records to CSV format with active filters
|
|
706
|
+
*/
|
|
707
|
+
async exportCsv() {
|
|
708
|
+
const qs = this.queryParams.toString();
|
|
709
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/export/csv${qs ? `?${qs}` : ""}`;
|
|
710
|
+
const res = await this.fetchFn(url, {
|
|
711
|
+
headers: {
|
|
712
|
+
...this.getHeaders(),
|
|
713
|
+
"Accept": "text/csv"
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
if (!res.ok) {
|
|
717
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
718
|
+
throw new Error(err.message || `Failed to export CSV for ${this.typeName}`);
|
|
719
|
+
}
|
|
720
|
+
return res.text();
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
// src/schema.ts
|
|
725
|
+
var SchemaClient = class {
|
|
726
|
+
gatewayUrl;
|
|
727
|
+
tenantId;
|
|
728
|
+
getToken;
|
|
729
|
+
fetchFn;
|
|
730
|
+
constructor(options) {
|
|
731
|
+
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
732
|
+
this.tenantId = options.tenantId;
|
|
733
|
+
this.getToken = options.getToken;
|
|
734
|
+
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
735
|
+
}
|
|
736
|
+
getHeaders() {
|
|
737
|
+
const headers = {
|
|
738
|
+
"Content-Type": "application/json",
|
|
739
|
+
"x-tenant-id": this.tenantId
|
|
740
|
+
};
|
|
741
|
+
const token = this.getToken();
|
|
742
|
+
if (token) {
|
|
743
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
744
|
+
}
|
|
745
|
+
return headers;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Define a new JSON Schema or alter an existing schema for an entity type in real-time
|
|
749
|
+
*/
|
|
750
|
+
async define(definition) {
|
|
751
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/definition`;
|
|
752
|
+
const res = await this.fetchFn(url, {
|
|
753
|
+
method: "POST",
|
|
754
|
+
headers: this.getHeaders(),
|
|
755
|
+
body: JSON.stringify(definition)
|
|
756
|
+
});
|
|
757
|
+
if (!res.ok) {
|
|
758
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
759
|
+
throw new Error(err.message || `Failed to define schema for ${definition.typeName}`);
|
|
760
|
+
}
|
|
761
|
+
return res.json();
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
// src/storage.ts
|
|
766
|
+
var MemoryStorage = class {
|
|
767
|
+
store = /* @__PURE__ */ new Map();
|
|
768
|
+
getItem(key) {
|
|
769
|
+
return this.store.get(key) ?? null;
|
|
770
|
+
}
|
|
771
|
+
setItem(key, value) {
|
|
772
|
+
this.store.set(key, value);
|
|
773
|
+
}
|
|
774
|
+
removeItem(key) {
|
|
775
|
+
this.store.delete(key);
|
|
776
|
+
}
|
|
454
777
|
};
|
|
778
|
+
function getDefaultStorage() {
|
|
779
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
780
|
+
return window.localStorage;
|
|
781
|
+
}
|
|
782
|
+
return new MemoryStorage();
|
|
783
|
+
}
|
|
455
784
|
|
|
456
785
|
// src/client.ts
|
|
457
786
|
var Zone4CodeClient = class {
|
|
@@ -505,6 +834,27 @@ var Zone4CodeClient = class {
|
|
|
505
834
|
entities(typeName) {
|
|
506
835
|
return this.from(typeName);
|
|
507
836
|
}
|
|
837
|
+
/**
|
|
838
|
+
* Get current authenticated user profile and platform wallet
|
|
839
|
+
*/
|
|
840
|
+
async getMe() {
|
|
841
|
+
const token = this.auth.getToken();
|
|
842
|
+
if (!token) {
|
|
843
|
+
throw new Error("Not authenticated: please call login() or setToken() first");
|
|
844
|
+
}
|
|
845
|
+
const res = await this.fetchFn(`${this.gatewayUrl}/generic/${this.tenantId}/me`, {
|
|
846
|
+
headers: {
|
|
847
|
+
"Content-Type": "application/json",
|
|
848
|
+
"Authorization": `Bearer ${token}`,
|
|
849
|
+
"x-tenant-id": this.tenantId
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
if (!res.ok) {
|
|
853
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
854
|
+
throw new Error(err.message || `Failed to fetch profile & wallet (HTTP ${res.status})`);
|
|
855
|
+
}
|
|
856
|
+
return res.json();
|
|
857
|
+
}
|
|
508
858
|
/**
|
|
509
859
|
* Check gateway connectivity & health
|
|
510
860
|
*/
|