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.cjs
CHANGED
|
@@ -31,26 +31,6 @@ __export(index_exports, {
|
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(index_exports);
|
|
33
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
34
|
// src/auth.ts
|
|
55
35
|
function decodeJwtPayload(token) {
|
|
56
36
|
try {
|
|
@@ -75,7 +55,9 @@ var AuthClient = class _AuthClient {
|
|
|
75
55
|
tenantId;
|
|
76
56
|
storage;
|
|
77
57
|
storageKey;
|
|
58
|
+
refreshStorageKey;
|
|
78
59
|
token = null;
|
|
60
|
+
refreshTokenValue = null;
|
|
79
61
|
fetchFn;
|
|
80
62
|
static TOKEN_KEY_PREFIX = "z4c_token_";
|
|
81
63
|
constructor(options) {
|
|
@@ -83,6 +65,7 @@ var AuthClient = class _AuthClient {
|
|
|
83
65
|
this.tenantId = options.tenantId;
|
|
84
66
|
this.storage = options.storage;
|
|
85
67
|
this.storageKey = options.storageKey || _AuthClient.TOKEN_KEY_PREFIX + this.tenantId;
|
|
68
|
+
this.refreshStorageKey = this.storageKey + "_refresh";
|
|
86
69
|
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
87
70
|
if (options.initialToken) {
|
|
88
71
|
this.setToken(options.initialToken);
|
|
@@ -91,11 +74,18 @@ var AuthClient = class _AuthClient {
|
|
|
91
74
|
if (stored) this.token = stored;
|
|
92
75
|
}).catch(() => {
|
|
93
76
|
});
|
|
77
|
+
Promise.resolve(this.storage.getItem(this.refreshStorageKey)).then((stored) => {
|
|
78
|
+
if (stored) this.refreshTokenValue = stored;
|
|
79
|
+
}).catch(() => {
|
|
80
|
+
});
|
|
94
81
|
}
|
|
95
82
|
}
|
|
96
83
|
getToken() {
|
|
97
84
|
return this.token;
|
|
98
85
|
}
|
|
86
|
+
getRefreshToken() {
|
|
87
|
+
return this.refreshTokenValue;
|
|
88
|
+
}
|
|
99
89
|
setToken(token) {
|
|
100
90
|
this.token = token;
|
|
101
91
|
if (token) {
|
|
@@ -104,6 +94,14 @@ var AuthClient = class _AuthClient {
|
|
|
104
94
|
this.storage.removeItem(this.storageKey);
|
|
105
95
|
}
|
|
106
96
|
}
|
|
97
|
+
setRefreshToken(token) {
|
|
98
|
+
this.refreshTokenValue = token;
|
|
99
|
+
if (token) {
|
|
100
|
+
this.storage.setItem(this.refreshStorageKey, token);
|
|
101
|
+
} else {
|
|
102
|
+
this.storage.removeItem(this.refreshStorageKey);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
107
105
|
isAuthenticated() {
|
|
108
106
|
return !!this.token;
|
|
109
107
|
}
|
|
@@ -212,6 +210,9 @@ var AuthClient = class _AuthClient {
|
|
|
212
210
|
if (token) {
|
|
213
211
|
this.setToken(token);
|
|
214
212
|
}
|
|
213
|
+
if (json.refresh_token) {
|
|
214
|
+
this.setRefreshToken(json.refresh_token);
|
|
215
|
+
}
|
|
215
216
|
const user = this.getUser() || json.user;
|
|
216
217
|
return {
|
|
217
218
|
token: token || "",
|
|
@@ -220,6 +221,163 @@ var AuthClient = class _AuthClient {
|
|
|
220
221
|
...json
|
|
221
222
|
};
|
|
222
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Authenticate via Google OAuth ID token
|
|
226
|
+
*/
|
|
227
|
+
async loginWithGoogle(token) {
|
|
228
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/login/google`;
|
|
229
|
+
const res = await this.fetchFn(url, {
|
|
230
|
+
method: "POST",
|
|
231
|
+
headers: {
|
|
232
|
+
"Content-Type": "application/json",
|
|
233
|
+
"x-tenant-id": this.tenantId
|
|
234
|
+
},
|
|
235
|
+
body: JSON.stringify({ token })
|
|
236
|
+
});
|
|
237
|
+
if (!res.ok) {
|
|
238
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
239
|
+
throw new Error(err.message || err.error || `Google login failed with HTTP ${res.status}`);
|
|
240
|
+
}
|
|
241
|
+
const json = await res.json();
|
|
242
|
+
const jwt = json.token || json.access_token;
|
|
243
|
+
if (jwt) {
|
|
244
|
+
this.setToken(jwt);
|
|
245
|
+
}
|
|
246
|
+
if (json.refresh_token) {
|
|
247
|
+
this.setRefreshToken(json.refresh_token);
|
|
248
|
+
}
|
|
249
|
+
const user = this.getUser() || json.user;
|
|
250
|
+
return {
|
|
251
|
+
token: jwt || "",
|
|
252
|
+
refreshToken: json.refresh_token,
|
|
253
|
+
user,
|
|
254
|
+
...json
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Renew expired access token using stored or provided refresh token
|
|
259
|
+
*/
|
|
260
|
+
async refreshToken(refreshToken) {
|
|
261
|
+
const tokenToUse = refreshToken || this.getRefreshToken();
|
|
262
|
+
if (!tokenToUse) {
|
|
263
|
+
throw new Error("No refresh token available");
|
|
264
|
+
}
|
|
265
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/refresh`;
|
|
266
|
+
const res = await this.fetchFn(url, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: {
|
|
269
|
+
"Content-Type": "application/json",
|
|
270
|
+
"x-tenant-id": this.tenantId
|
|
271
|
+
},
|
|
272
|
+
body: JSON.stringify({ refresh_token: tokenToUse })
|
|
273
|
+
});
|
|
274
|
+
if (!res.ok) {
|
|
275
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
276
|
+
throw new Error(err.message || err.error || `Token refresh failed with HTTP ${res.status}`);
|
|
277
|
+
}
|
|
278
|
+
const json = await res.json();
|
|
279
|
+
const token = json.token || json.access_token;
|
|
280
|
+
if (token) {
|
|
281
|
+
this.setToken(token);
|
|
282
|
+
}
|
|
283
|
+
if (json.refresh_token) {
|
|
284
|
+
this.setRefreshToken(json.refresh_token);
|
|
285
|
+
}
|
|
286
|
+
const user = this.getUser() || json.user;
|
|
287
|
+
return {
|
|
288
|
+
token: token || "",
|
|
289
|
+
refreshToken: json.refresh_token,
|
|
290
|
+
user,
|
|
291
|
+
...json
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Request password reset email
|
|
296
|
+
*/
|
|
297
|
+
async forgotPassword(data) {
|
|
298
|
+
const payload = typeof data === "string" ? { email: data } : data;
|
|
299
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/auth/forgot-password`;
|
|
300
|
+
const res = await this.fetchFn(url, {
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: {
|
|
303
|
+
"Content-Type": "application/json",
|
|
304
|
+
"x-tenant-id": this.tenantId
|
|
305
|
+
},
|
|
306
|
+
body: JSON.stringify(payload)
|
|
307
|
+
});
|
|
308
|
+
const json = await res.json().catch(() => ({}));
|
|
309
|
+
if (!res.ok) {
|
|
310
|
+
throw new Error(json.message || json.error || `Forgot password request failed with HTTP ${res.status}`);
|
|
311
|
+
}
|
|
312
|
+
return json;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Complete password reset using action token
|
|
316
|
+
*/
|
|
317
|
+
async resetPassword(data) {
|
|
318
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/auth/reset-password`;
|
|
319
|
+
const res = await this.fetchFn(url, {
|
|
320
|
+
method: "POST",
|
|
321
|
+
headers: {
|
|
322
|
+
"Content-Type": "application/json",
|
|
323
|
+
"x-tenant-id": this.tenantId
|
|
324
|
+
},
|
|
325
|
+
body: JSON.stringify(data)
|
|
326
|
+
});
|
|
327
|
+
const json = await res.json().catch(() => ({}));
|
|
328
|
+
if (!res.ok) {
|
|
329
|
+
throw new Error(json.message || json.error || `Reset password failed with HTTP ${res.status}`);
|
|
330
|
+
}
|
|
331
|
+
return json;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Change password for current or specified user
|
|
335
|
+
*/
|
|
336
|
+
async changePassword(data, userId) {
|
|
337
|
+
const targetUserId = userId || this.getUser()?.id;
|
|
338
|
+
if (!targetUserId) {
|
|
339
|
+
throw new Error("User ID required: user is not logged in and no userId was provided");
|
|
340
|
+
}
|
|
341
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/${targetUserId}/change-password`;
|
|
342
|
+
const res = await this.fetchFn(url, {
|
|
343
|
+
method: "POST",
|
|
344
|
+
headers: {
|
|
345
|
+
"Content-Type": "application/json",
|
|
346
|
+
"x-tenant-id": this.tenantId,
|
|
347
|
+
...this.token ? { "Authorization": `Bearer ${this.token}` } : {}
|
|
348
|
+
},
|
|
349
|
+
body: JSON.stringify(data)
|
|
350
|
+
});
|
|
351
|
+
if (!res.ok) {
|
|
352
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
353
|
+
throw new Error(err.message || err.error || `Change password failed with HTTP ${res.status}`);
|
|
354
|
+
}
|
|
355
|
+
return res.json().catch(() => ({ success: true }));
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Update profile attributes for current or specified user
|
|
359
|
+
*/
|
|
360
|
+
async updateProfile(data, userId) {
|
|
361
|
+
const targetUserId = userId || this.getUser()?.id;
|
|
362
|
+
if (!targetUserId) {
|
|
363
|
+
throw new Error("User ID required: user is not logged in and no userId was provided");
|
|
364
|
+
}
|
|
365
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/user/${targetUserId}`;
|
|
366
|
+
const res = await this.fetchFn(url, {
|
|
367
|
+
method: "PUT",
|
|
368
|
+
headers: {
|
|
369
|
+
"Content-Type": "application/json",
|
|
370
|
+
"x-tenant-id": this.tenantId,
|
|
371
|
+
...this.token ? { "Authorization": `Bearer ${this.token}` } : {}
|
|
372
|
+
},
|
|
373
|
+
body: JSON.stringify(data)
|
|
374
|
+
});
|
|
375
|
+
if (!res.ok) {
|
|
376
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
377
|
+
throw new Error(err.message || err.error || `Update profile failed with HTTP ${res.status}`);
|
|
378
|
+
}
|
|
379
|
+
return res.json();
|
|
380
|
+
}
|
|
223
381
|
/**
|
|
224
382
|
* Fetch current authenticated user profile
|
|
225
383
|
*/
|
|
@@ -245,51 +403,11 @@ var AuthClient = class _AuthClient {
|
|
|
245
403
|
return res.json();
|
|
246
404
|
}
|
|
247
405
|
/**
|
|
248
|
-
* Log out and clear saved
|
|
406
|
+
* Log out and clear saved tokens
|
|
249
407
|
*/
|
|
250
408
|
logout() {
|
|
251
409
|
this.setToken(null);
|
|
252
|
-
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
// src/schema.ts
|
|
256
|
-
var SchemaClient = class {
|
|
257
|
-
gatewayUrl;
|
|
258
|
-
tenantId;
|
|
259
|
-
getToken;
|
|
260
|
-
fetchFn;
|
|
261
|
-
constructor(options) {
|
|
262
|
-
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
263
|
-
this.tenantId = options.tenantId;
|
|
264
|
-
this.getToken = options.getToken;
|
|
265
|
-
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
266
|
-
}
|
|
267
|
-
getHeaders() {
|
|
268
|
-
const headers = {
|
|
269
|
-
"Content-Type": "application/json",
|
|
270
|
-
"x-tenant-id": this.tenantId
|
|
271
|
-
};
|
|
272
|
-
const token = this.getToken();
|
|
273
|
-
if (token) {
|
|
274
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
275
|
-
}
|
|
276
|
-
return headers;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Define a new JSON Schema or alter an existing schema for an entity type in real-time
|
|
280
|
-
*/
|
|
281
|
-
async define(definition) {
|
|
282
|
-
const url = `${this.gatewayUrl}/generic/${this.tenantId}/definition`;
|
|
283
|
-
const res = await this.fetchFn(url, {
|
|
284
|
-
method: "POST",
|
|
285
|
-
headers: this.getHeaders(),
|
|
286
|
-
body: JSON.stringify(definition)
|
|
287
|
-
});
|
|
288
|
-
if (!res.ok) {
|
|
289
|
-
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
290
|
-
throw new Error(err.message || `Failed to define schema for ${definition.typeName}`);
|
|
291
|
-
}
|
|
292
|
-
return res.json();
|
|
410
|
+
this.setRefreshToken(null);
|
|
293
411
|
}
|
|
294
412
|
};
|
|
295
413
|
|
|
@@ -376,6 +494,19 @@ var EntityQueryBuilder = class {
|
|
|
376
494
|
this.queryParams.append(`related[${relationName}]`, ids);
|
|
377
495
|
return this;
|
|
378
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* Declaratively expand graph relations (Supabase-style join expansion)
|
|
499
|
+
* Example: .include('placed_by', 'payment', 'items')
|
|
500
|
+
*/
|
|
501
|
+
include(...relations) {
|
|
502
|
+
const existing = this.queryParams.get("include");
|
|
503
|
+
const existingList = existing ? existing.split(",").map((s) => s.trim()) : [];
|
|
504
|
+
const combined = Array.from(/* @__PURE__ */ new Set([...existingList, ...relations.map((s) => s.trim())])).filter(Boolean);
|
|
505
|
+
if (combined.length > 0) {
|
|
506
|
+
this.queryParams.set("include", combined.join(","));
|
|
507
|
+
}
|
|
508
|
+
return this;
|
|
509
|
+
}
|
|
379
510
|
// ----------------------------------------------------
|
|
380
511
|
// Sorting, Pagination & Modifiers
|
|
381
512
|
// ----------------------------------------------------
|
|
@@ -424,10 +555,21 @@ var EntityQueryBuilder = class {
|
|
|
424
555
|
return res.json();
|
|
425
556
|
}
|
|
426
557
|
/**
|
|
427
|
-
* Fetch a single entity by ID
|
|
558
|
+
* Fetch a single entity by ID with optional expansion and flattening
|
|
428
559
|
*/
|
|
429
|
-
async get(id) {
|
|
430
|
-
const
|
|
560
|
+
async get(id, options) {
|
|
561
|
+
const params = new URLSearchParams(this.queryParams);
|
|
562
|
+
if (options?.flat !== void 0) {
|
|
563
|
+
params.set("flat", options.flat ? "true" : "false");
|
|
564
|
+
}
|
|
565
|
+
if (options?.include && options.include.length > 0) {
|
|
566
|
+
const existing = params.get("include");
|
|
567
|
+
const existingList = existing ? existing.split(",").map((s) => s.trim()) : [];
|
|
568
|
+
const combined = Array.from(/* @__PURE__ */ new Set([...existingList, ...options.include.map((s) => s.trim())])).filter(Boolean);
|
|
569
|
+
params.set("include", combined.join(","));
|
|
570
|
+
}
|
|
571
|
+
const qs = params.toString();
|
|
572
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}${qs ? `?${qs}` : ""}`;
|
|
431
573
|
const res = await this.fetchFn(url, {
|
|
432
574
|
headers: this.getHeaders()
|
|
433
575
|
});
|
|
@@ -484,7 +626,194 @@ var EntityQueryBuilder = class {
|
|
|
484
626
|
}
|
|
485
627
|
return { success: true };
|
|
486
628
|
}
|
|
629
|
+
/**
|
|
630
|
+
* Fetch revision history for an entity record
|
|
631
|
+
*/
|
|
632
|
+
async revisions(id) {
|
|
633
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/revisions`;
|
|
634
|
+
const res = await this.fetchFn(url, {
|
|
635
|
+
headers: this.getHeaders()
|
|
636
|
+
});
|
|
637
|
+
if (!res.ok) {
|
|
638
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
639
|
+
throw new Error(err.message || `Failed to fetch revisions for ${this.typeName}/${id}`);
|
|
640
|
+
}
|
|
641
|
+
return res.json();
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Fetch all graph relations for this entity record
|
|
645
|
+
*/
|
|
646
|
+
async getRelations(id, lang) {
|
|
647
|
+
const qs = lang ? `?lang=${encodeURIComponent(lang)}` : "";
|
|
648
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations${qs}`;
|
|
649
|
+
const res = await this.fetchFn(url, {
|
|
650
|
+
headers: this.getHeaders()
|
|
651
|
+
});
|
|
652
|
+
if (!res.ok) {
|
|
653
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
654
|
+
throw new Error(err.message || `Failed to fetch relations for ${this.typeName}/${id}`);
|
|
655
|
+
}
|
|
656
|
+
return res.json();
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Link this record to another entity record
|
|
660
|
+
*/
|
|
661
|
+
async link(id, payload) {
|
|
662
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations`;
|
|
663
|
+
const res = await this.fetchFn(url, {
|
|
664
|
+
method: "POST",
|
|
665
|
+
headers: this.getHeaders(),
|
|
666
|
+
body: JSON.stringify(payload)
|
|
667
|
+
});
|
|
668
|
+
if (!res.ok) {
|
|
669
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
670
|
+
throw new Error(err.message || `Failed to create relation for ${this.typeName}/${id}`);
|
|
671
|
+
}
|
|
672
|
+
return res.json().catch(() => ({ success: true }));
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Replace the full set of relations of one relation name
|
|
676
|
+
*/
|
|
677
|
+
async setLinks(id, payload) {
|
|
678
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations`;
|
|
679
|
+
const res = await this.fetchFn(url, {
|
|
680
|
+
method: "PUT",
|
|
681
|
+
headers: this.getHeaders(),
|
|
682
|
+
body: JSON.stringify(payload)
|
|
683
|
+
});
|
|
684
|
+
if (!res.ok) {
|
|
685
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
686
|
+
throw new Error(err.message || `Failed to replace relations for ${this.typeName}/${id}`);
|
|
687
|
+
}
|
|
688
|
+
return res.json().catch(() => ({ success: true }));
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Remove one graph link between two records
|
|
692
|
+
*/
|
|
693
|
+
async unlink(id, relationName, targetId, targetTypeName) {
|
|
694
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations/${encodeURIComponent(relationName)}/${encodeURIComponent(targetId)}?targetTypeName=${encodeURIComponent(targetTypeName)}`;
|
|
695
|
+
const res = await this.fetchFn(url, {
|
|
696
|
+
method: "DELETE",
|
|
697
|
+
headers: this.getHeaders()
|
|
698
|
+
});
|
|
699
|
+
if (!res.ok) {
|
|
700
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
701
|
+
throw new Error(err.message || `Failed to delete relation ${relationName} for ${this.typeName}/${id}`);
|
|
702
|
+
}
|
|
703
|
+
return res.json().catch(() => ({ success: true }));
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Execute a type-level workflow plugin action (e.g. checkout, batch-process)
|
|
707
|
+
*/
|
|
708
|
+
async action(actionName, payload) {
|
|
709
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/actions/${actionName}`;
|
|
710
|
+
const res = await this.fetchFn(url, {
|
|
711
|
+
method: "POST",
|
|
712
|
+
headers: this.getHeaders(),
|
|
713
|
+
body: payload ? JSON.stringify(payload) : void 0
|
|
714
|
+
});
|
|
715
|
+
if (!res.ok) {
|
|
716
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
717
|
+
throw new Error(err.message || `Action ${actionName} failed on type ${this.typeName}`);
|
|
718
|
+
}
|
|
719
|
+
return res.json();
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Execute an instance-level workflow plugin action (e.g. cancel order, approve)
|
|
723
|
+
*/
|
|
724
|
+
async instanceAction(id, actionName, payload) {
|
|
725
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/actions/${actionName}`;
|
|
726
|
+
const res = await this.fetchFn(url, {
|
|
727
|
+
method: "POST",
|
|
728
|
+
headers: this.getHeaders(),
|
|
729
|
+
body: payload ? JSON.stringify(payload) : void 0
|
|
730
|
+
});
|
|
731
|
+
if (!res.ok) {
|
|
732
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
733
|
+
throw new Error(err.message || `Action ${actionName} failed on ${this.typeName}/${id}`);
|
|
734
|
+
}
|
|
735
|
+
return res.json();
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Export matching entity records to CSV format with active filters
|
|
739
|
+
*/
|
|
740
|
+
async exportCsv() {
|
|
741
|
+
const qs = this.queryParams.toString();
|
|
742
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/export/csv${qs ? `?${qs}` : ""}`;
|
|
743
|
+
const res = await this.fetchFn(url, {
|
|
744
|
+
headers: {
|
|
745
|
+
...this.getHeaders(),
|
|
746
|
+
"Accept": "text/csv"
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
if (!res.ok) {
|
|
750
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
751
|
+
throw new Error(err.message || `Failed to export CSV for ${this.typeName}`);
|
|
752
|
+
}
|
|
753
|
+
return res.text();
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
// src/schema.ts
|
|
758
|
+
var SchemaClient = class {
|
|
759
|
+
gatewayUrl;
|
|
760
|
+
tenantId;
|
|
761
|
+
getToken;
|
|
762
|
+
fetchFn;
|
|
763
|
+
constructor(options) {
|
|
764
|
+
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
765
|
+
this.tenantId = options.tenantId;
|
|
766
|
+
this.getToken = options.getToken;
|
|
767
|
+
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
768
|
+
}
|
|
769
|
+
getHeaders() {
|
|
770
|
+
const headers = {
|
|
771
|
+
"Content-Type": "application/json",
|
|
772
|
+
"x-tenant-id": this.tenantId
|
|
773
|
+
};
|
|
774
|
+
const token = this.getToken();
|
|
775
|
+
if (token) {
|
|
776
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
777
|
+
}
|
|
778
|
+
return headers;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Define a new JSON Schema or alter an existing schema for an entity type in real-time
|
|
782
|
+
*/
|
|
783
|
+
async define(definition) {
|
|
784
|
+
const url = `${this.gatewayUrl}/generic/${this.tenantId}/definition`;
|
|
785
|
+
const res = await this.fetchFn(url, {
|
|
786
|
+
method: "POST",
|
|
787
|
+
headers: this.getHeaders(),
|
|
788
|
+
body: JSON.stringify(definition)
|
|
789
|
+
});
|
|
790
|
+
if (!res.ok) {
|
|
791
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
792
|
+
throw new Error(err.message || `Failed to define schema for ${definition.typeName}`);
|
|
793
|
+
}
|
|
794
|
+
return res.json();
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// src/storage.ts
|
|
799
|
+
var MemoryStorage = class {
|
|
800
|
+
store = /* @__PURE__ */ new Map();
|
|
801
|
+
getItem(key) {
|
|
802
|
+
return this.store.get(key) ?? null;
|
|
803
|
+
}
|
|
804
|
+
setItem(key, value) {
|
|
805
|
+
this.store.set(key, value);
|
|
806
|
+
}
|
|
807
|
+
removeItem(key) {
|
|
808
|
+
this.store.delete(key);
|
|
809
|
+
}
|
|
487
810
|
};
|
|
811
|
+
function getDefaultStorage() {
|
|
812
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
813
|
+
return window.localStorage;
|
|
814
|
+
}
|
|
815
|
+
return new MemoryStorage();
|
|
816
|
+
}
|
|
488
817
|
|
|
489
818
|
// src/client.ts
|
|
490
819
|
var Zone4CodeClient = class {
|
|
@@ -538,6 +867,27 @@ var Zone4CodeClient = class {
|
|
|
538
867
|
entities(typeName) {
|
|
539
868
|
return this.from(typeName);
|
|
540
869
|
}
|
|
870
|
+
/**
|
|
871
|
+
* Get current authenticated user profile and platform wallet
|
|
872
|
+
*/
|
|
873
|
+
async getMe() {
|
|
874
|
+
const token = this.auth.getToken();
|
|
875
|
+
if (!token) {
|
|
876
|
+
throw new Error("Not authenticated: please call login() or setToken() first");
|
|
877
|
+
}
|
|
878
|
+
const res = await this.fetchFn(`${this.gatewayUrl}/generic/${this.tenantId}/me`, {
|
|
879
|
+
headers: {
|
|
880
|
+
"Content-Type": "application/json",
|
|
881
|
+
"Authorization": `Bearer ${token}`,
|
|
882
|
+
"x-tenant-id": this.tenantId
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
if (!res.ok) {
|
|
886
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
887
|
+
throw new Error(err.message || `Failed to fetch profile & wallet (HTTP ${res.status})`);
|
|
888
|
+
}
|
|
889
|
+
return res.json();
|
|
890
|
+
}
|
|
541
891
|
/**
|
|
542
892
|
* Check gateway connectivity & health
|
|
543
893
|
*/
|