zone4code-sdk 1.0.5 → 1.0.6
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/dist/index.cjs +214 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -2
- package/dist/index.d.ts +51 -2
- package/dist/index.js +214 -93
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -50,6 +50,22 @@ function decodeJwtPayload(token) {
|
|
|
50
50
|
return null;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
function normalizeHeaders(headers) {
|
|
54
|
+
const result = {};
|
|
55
|
+
if (!headers) return result;
|
|
56
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
57
|
+
headers.forEach((value, key) => {
|
|
58
|
+
result[key] = value;
|
|
59
|
+
});
|
|
60
|
+
} else if (Array.isArray(headers)) {
|
|
61
|
+
for (const [key, value] of headers) {
|
|
62
|
+
result[key] = value;
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
Object.assign(result, headers);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
53
69
|
var AuthClient = class _AuthClient {
|
|
54
70
|
gatewayUrl;
|
|
55
71
|
tenantId;
|
|
@@ -59,26 +75,39 @@ var AuthClient = class _AuthClient {
|
|
|
59
75
|
token = null;
|
|
60
76
|
refreshTokenValue = null;
|
|
61
77
|
fetchFn;
|
|
78
|
+
autoRefresh;
|
|
79
|
+
tokenExpiryBuffer;
|
|
80
|
+
onSessionExpiredCallback;
|
|
81
|
+
sessionExpiredListeners = [];
|
|
82
|
+
activeRefreshPromise = null;
|
|
83
|
+
storageLoadedPromise;
|
|
62
84
|
static TOKEN_KEY_PREFIX = "z4c_token_";
|
|
63
85
|
constructor(options) {
|
|
86
|
+
const storage = options.storage;
|
|
87
|
+
const storageKey = options.storageKey || _AuthClient.TOKEN_KEY_PREFIX + options.tenantId;
|
|
88
|
+
const refreshStorageKey = storageKey + "_refresh";
|
|
64
89
|
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
65
90
|
this.tenantId = options.tenantId;
|
|
66
|
-
this.storage =
|
|
67
|
-
this.storageKey =
|
|
68
|
-
this.refreshStorageKey =
|
|
91
|
+
this.storage = storage;
|
|
92
|
+
this.storageKey = storageKey;
|
|
93
|
+
this.refreshStorageKey = refreshStorageKey;
|
|
69
94
|
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
this.autoRefresh = options.autoRefresh ?? true;
|
|
96
|
+
this.tokenExpiryBuffer = options.tokenExpiryBuffer ?? 30;
|
|
97
|
+
this.onSessionExpiredCallback = options.onSessionExpired;
|
|
98
|
+
this.storageLoadedPromise = (async () => {
|
|
99
|
+
if (options.initialToken) {
|
|
100
|
+
this.setToken(options.initialToken);
|
|
101
|
+
} else {
|
|
102
|
+
try {
|
|
103
|
+
const storedToken = await storage.getItem(storageKey);
|
|
104
|
+
if (storedToken) this.token = storedToken;
|
|
105
|
+
const storedRefresh = await storage.getItem(refreshStorageKey);
|
|
106
|
+
if (storedRefresh) this.refreshTokenValue = storedRefresh;
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
})();
|
|
82
111
|
}
|
|
83
112
|
getToken() {
|
|
84
113
|
return this.token;
|
|
@@ -105,6 +134,91 @@ var AuthClient = class _AuthClient {
|
|
|
105
134
|
isAuthenticated() {
|
|
106
135
|
return !!this.token;
|
|
107
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Check whether the current access token is expired or expiring within bufferSeconds
|
|
139
|
+
*/
|
|
140
|
+
isTokenExpired(bufferSeconds = this.tokenExpiryBuffer) {
|
|
141
|
+
if (!this.token) return true;
|
|
142
|
+
const payload = decodeJwtPayload(this.token);
|
|
143
|
+
if (!payload || typeof payload.exp !== "number") return false;
|
|
144
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
145
|
+
return nowSeconds >= payload.exp - bufferSeconds;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Returns a valid access token, proactively refreshing it if expired and autoRefresh is enabled
|
|
149
|
+
*/
|
|
150
|
+
async getValidToken() {
|
|
151
|
+
await this.storageLoadedPromise;
|
|
152
|
+
if (!this.token) return null;
|
|
153
|
+
if (!this.autoRefresh) return this.token;
|
|
154
|
+
if (this.isTokenExpired()) {
|
|
155
|
+
const refreshToken = this.getRefreshToken();
|
|
156
|
+
if (refreshToken) {
|
|
157
|
+
try {
|
|
158
|
+
const res = await this.refreshToken(refreshToken);
|
|
159
|
+
return res.token || this.token;
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
this.notifySessionExpired();
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return this.token;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Register a callback triggered when session has expired completely
|
|
172
|
+
*/
|
|
173
|
+
onSessionExpired(listener) {
|
|
174
|
+
this.sessionExpiredListeners.push(listener);
|
|
175
|
+
return () => {
|
|
176
|
+
this.sessionExpiredListeners = this.sessionExpiredListeners.filter((l) => l !== listener);
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
notifySessionExpired() {
|
|
180
|
+
this.logout();
|
|
181
|
+
for (const listener of this.sessionExpiredListeners) {
|
|
182
|
+
try {
|
|
183
|
+
listener();
|
|
184
|
+
} catch (e) {
|
|
185
|
+
console.error("Error in onSessionExpired listener:", e);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (this.onSessionExpiredCallback) {
|
|
189
|
+
try {
|
|
190
|
+
this.onSessionExpiredCallback();
|
|
191
|
+
} catch (e) {
|
|
192
|
+
console.error("Error in onSessionExpired callback:", e);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Perform an HTTP request with automatic Authorization injection, proactive refresh, and reactive 401 retry
|
|
198
|
+
*/
|
|
199
|
+
async fetchWithAuth(url, init = {}) {
|
|
200
|
+
await this.storageLoadedPromise;
|
|
201
|
+
const token = await this.getValidToken();
|
|
202
|
+
const headers = normalizeHeaders(init.headers);
|
|
203
|
+
if (!headers["x-tenant-id"] && !headers["X-Tenant-Id"]) {
|
|
204
|
+
headers["x-tenant-id"] = this.tenantId;
|
|
205
|
+
}
|
|
206
|
+
if (token && !headers["Authorization"] && !headers["authorization"]) {
|
|
207
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
208
|
+
}
|
|
209
|
+
let res = await this.fetchFn(url, { ...init, headers });
|
|
210
|
+
if (res.status === 401 && this.autoRefresh && this.getRefreshToken()) {
|
|
211
|
+
try {
|
|
212
|
+
const refreshed = await this.refreshToken();
|
|
213
|
+
if (refreshed?.token) {
|
|
214
|
+
headers["Authorization"] = `Bearer ${refreshed.token}`;
|
|
215
|
+
res = await this.fetchFn(url, { ...init, headers });
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return res;
|
|
221
|
+
}
|
|
108
222
|
/**
|
|
109
223
|
* Synchronously parse and return current authenticated user from JWT token
|
|
110
224
|
*/
|
|
@@ -260,36 +374,48 @@ var AuthClient = class _AuthClient {
|
|
|
260
374
|
async refreshToken(refreshToken) {
|
|
261
375
|
const tokenToUse = refreshToken || this.getRefreshToken();
|
|
262
376
|
if (!tokenToUse) {
|
|
377
|
+
this.notifySessionExpired();
|
|
263
378
|
throw new Error("No refresh token available");
|
|
264
379
|
}
|
|
265
|
-
|
|
266
|
-
|
|
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);
|
|
380
|
+
if (this.activeRefreshPromise) {
|
|
381
|
+
return this.activeRefreshPromise;
|
|
285
382
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
383
|
+
this.activeRefreshPromise = (async () => {
|
|
384
|
+
try {
|
|
385
|
+
const url = `${this.gatewayUrl}/auth/${this.tenantId}/refresh`;
|
|
386
|
+
const res = await this.fetchFn(url, {
|
|
387
|
+
method: "POST",
|
|
388
|
+
headers: {
|
|
389
|
+
"Content-Type": "application/json",
|
|
390
|
+
"x-tenant-id": this.tenantId
|
|
391
|
+
},
|
|
392
|
+
body: JSON.stringify({ refresh_token: tokenToUse })
|
|
393
|
+
});
|
|
394
|
+
if (!res.ok) {
|
|
395
|
+
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
396
|
+
this.notifySessionExpired();
|
|
397
|
+
throw new Error(err.message || err.error || `Token refresh failed with HTTP ${res.status}`);
|
|
398
|
+
}
|
|
399
|
+
const json = await res.json();
|
|
400
|
+
const token = json.token || json.access_token;
|
|
401
|
+
if (token) {
|
|
402
|
+
this.setToken(token);
|
|
403
|
+
}
|
|
404
|
+
if (json.refresh_token) {
|
|
405
|
+
this.setRefreshToken(json.refresh_token);
|
|
406
|
+
}
|
|
407
|
+
const user = this.getUser() || json.user;
|
|
408
|
+
return {
|
|
409
|
+
token: token || "",
|
|
410
|
+
refreshToken: json.refresh_token,
|
|
411
|
+
user,
|
|
412
|
+
...json
|
|
413
|
+
};
|
|
414
|
+
} finally {
|
|
415
|
+
this.activeRefreshPromise = null;
|
|
416
|
+
}
|
|
417
|
+
})();
|
|
418
|
+
return this.activeRefreshPromise;
|
|
293
419
|
}
|
|
294
420
|
/**
|
|
295
421
|
* Request password reset email
|
|
@@ -418,13 +544,15 @@ var EntityQueryBuilder = class {
|
|
|
418
544
|
typeName;
|
|
419
545
|
getToken;
|
|
420
546
|
fetchFn;
|
|
547
|
+
fetchWithAuth;
|
|
421
548
|
queryParams = new URLSearchParams();
|
|
422
549
|
constructor(options) {
|
|
423
550
|
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
424
551
|
this.tenantId = options.tenantId;
|
|
425
552
|
this.typeName = options.typeName;
|
|
426
|
-
this.getToken = options.getToken;
|
|
553
|
+
this.getToken = options.getToken || (() => null);
|
|
427
554
|
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
555
|
+
this.fetchWithAuth = options.fetchWithAuth;
|
|
428
556
|
}
|
|
429
557
|
getHeaders() {
|
|
430
558
|
const headers = {
|
|
@@ -437,6 +565,13 @@ var EntityQueryBuilder = class {
|
|
|
437
565
|
}
|
|
438
566
|
return headers;
|
|
439
567
|
}
|
|
568
|
+
async executeRequest(url, init = {}) {
|
|
569
|
+
if (this.fetchWithAuth) {
|
|
570
|
+
return this.fetchWithAuth(url, init);
|
|
571
|
+
}
|
|
572
|
+
const headers = { ...this.getHeaders(), ...init.headers || {} };
|
|
573
|
+
return this.fetchFn(url, { ...init, headers });
|
|
574
|
+
}
|
|
440
575
|
// ----------------------------------------------------
|
|
441
576
|
// Filter Operators
|
|
442
577
|
// ----------------------------------------------------
|
|
@@ -545,9 +680,7 @@ var EntityQueryBuilder = class {
|
|
|
545
680
|
async list() {
|
|
546
681
|
const qs = this.queryParams.toString();
|
|
547
682
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}${qs ? `?${qs}` : ""}`;
|
|
548
|
-
const res = await this.
|
|
549
|
-
headers: this.getHeaders()
|
|
550
|
-
});
|
|
683
|
+
const res = await this.executeRequest(url);
|
|
551
684
|
if (!res.ok) {
|
|
552
685
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
553
686
|
throw new Error(err.message || `Query failed with HTTP ${res.status}`);
|
|
@@ -570,9 +703,7 @@ var EntityQueryBuilder = class {
|
|
|
570
703
|
}
|
|
571
704
|
const qs = params.toString();
|
|
572
705
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}${qs ? `?${qs}` : ""}`;
|
|
573
|
-
const res = await this.
|
|
574
|
-
headers: this.getHeaders()
|
|
575
|
-
});
|
|
706
|
+
const res = await this.executeRequest(url);
|
|
576
707
|
if (!res.ok) {
|
|
577
708
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
578
709
|
throw new Error(err.message || `Failed to fetch ${this.typeName}/${id}`);
|
|
@@ -584,9 +715,8 @@ var EntityQueryBuilder = class {
|
|
|
584
715
|
*/
|
|
585
716
|
async create(data) {
|
|
586
717
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}`;
|
|
587
|
-
const res = await this.
|
|
718
|
+
const res = await this.executeRequest(url, {
|
|
588
719
|
method: "POST",
|
|
589
|
-
headers: this.getHeaders(),
|
|
590
720
|
body: JSON.stringify(data)
|
|
591
721
|
});
|
|
592
722
|
if (!res.ok) {
|
|
@@ -600,9 +730,8 @@ var EntityQueryBuilder = class {
|
|
|
600
730
|
*/
|
|
601
731
|
async update(id, partialData) {
|
|
602
732
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;
|
|
603
|
-
const res = await this.
|
|
733
|
+
const res = await this.executeRequest(url, {
|
|
604
734
|
method: "PATCH",
|
|
605
|
-
headers: this.getHeaders(),
|
|
606
735
|
body: JSON.stringify(partialData)
|
|
607
736
|
});
|
|
608
737
|
if (!res.ok) {
|
|
@@ -616,9 +745,8 @@ var EntityQueryBuilder = class {
|
|
|
616
745
|
*/
|
|
617
746
|
async delete(id) {
|
|
618
747
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}`;
|
|
619
|
-
const res = await this.
|
|
620
|
-
method: "DELETE"
|
|
621
|
-
headers: this.getHeaders()
|
|
748
|
+
const res = await this.executeRequest(url, {
|
|
749
|
+
method: "DELETE"
|
|
622
750
|
});
|
|
623
751
|
if (!res.ok) {
|
|
624
752
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
@@ -631,9 +759,7 @@ var EntityQueryBuilder = class {
|
|
|
631
759
|
*/
|
|
632
760
|
async revisions(id) {
|
|
633
761
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/revisions`;
|
|
634
|
-
const res = await this.
|
|
635
|
-
headers: this.getHeaders()
|
|
636
|
-
});
|
|
762
|
+
const res = await this.executeRequest(url);
|
|
637
763
|
if (!res.ok) {
|
|
638
764
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
639
765
|
throw new Error(err.message || `Failed to fetch revisions for ${this.typeName}/${id}`);
|
|
@@ -646,9 +772,7 @@ var EntityQueryBuilder = class {
|
|
|
646
772
|
async getRelations(id, lang) {
|
|
647
773
|
const qs = lang ? `?lang=${encodeURIComponent(lang)}` : "";
|
|
648
774
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations${qs}`;
|
|
649
|
-
const res = await this.
|
|
650
|
-
headers: this.getHeaders()
|
|
651
|
-
});
|
|
775
|
+
const res = await this.executeRequest(url);
|
|
652
776
|
if (!res.ok) {
|
|
653
777
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
654
778
|
throw new Error(err.message || `Failed to fetch relations for ${this.typeName}/${id}`);
|
|
@@ -686,9 +810,8 @@ var EntityQueryBuilder = class {
|
|
|
686
810
|
};
|
|
687
811
|
}
|
|
688
812
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations`;
|
|
689
|
-
const res = await this.
|
|
813
|
+
const res = await this.executeRequest(url, {
|
|
690
814
|
method: "POST",
|
|
691
|
-
headers: this.getHeaders(),
|
|
692
815
|
body: JSON.stringify(payload)
|
|
693
816
|
});
|
|
694
817
|
if (!res.ok) {
|
|
@@ -702,9 +825,8 @@ var EntityQueryBuilder = class {
|
|
|
702
825
|
*/
|
|
703
826
|
async setLinks(id, payload) {
|
|
704
827
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations`;
|
|
705
|
-
const res = await this.
|
|
828
|
+
const res = await this.executeRequest(url, {
|
|
706
829
|
method: "PUT",
|
|
707
|
-
headers: this.getHeaders(),
|
|
708
830
|
body: JSON.stringify(payload)
|
|
709
831
|
});
|
|
710
832
|
if (!res.ok) {
|
|
@@ -718,9 +840,8 @@ var EntityQueryBuilder = class {
|
|
|
718
840
|
*/
|
|
719
841
|
async unlink(id, relationName, targetId, targetTypeName) {
|
|
720
842
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/relations/${encodeURIComponent(relationName)}/${encodeURIComponent(targetId)}?targetTypeName=${encodeURIComponent(targetTypeName)}`;
|
|
721
|
-
const res = await this.
|
|
722
|
-
method: "DELETE"
|
|
723
|
-
headers: this.getHeaders()
|
|
843
|
+
const res = await this.executeRequest(url, {
|
|
844
|
+
method: "DELETE"
|
|
724
845
|
});
|
|
725
846
|
if (!res.ok) {
|
|
726
847
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
@@ -733,9 +854,8 @@ var EntityQueryBuilder = class {
|
|
|
733
854
|
*/
|
|
734
855
|
async action(actionName, payload) {
|
|
735
856
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/actions/${actionName}`;
|
|
736
|
-
const res = await this.
|
|
857
|
+
const res = await this.executeRequest(url, {
|
|
737
858
|
method: "POST",
|
|
738
|
-
headers: this.getHeaders(),
|
|
739
859
|
body: payload ? JSON.stringify(payload) : void 0
|
|
740
860
|
});
|
|
741
861
|
if (!res.ok) {
|
|
@@ -749,9 +869,8 @@ var EntityQueryBuilder = class {
|
|
|
749
869
|
*/
|
|
750
870
|
async instanceAction(id, actionName, payload) {
|
|
751
871
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/${id}/actions/${actionName}`;
|
|
752
|
-
const res = await this.
|
|
872
|
+
const res = await this.executeRequest(url, {
|
|
753
873
|
method: "POST",
|
|
754
|
-
headers: this.getHeaders(),
|
|
755
874
|
body: payload ? JSON.stringify(payload) : void 0
|
|
756
875
|
});
|
|
757
876
|
if (!res.ok) {
|
|
@@ -766,9 +885,8 @@ var EntityQueryBuilder = class {
|
|
|
766
885
|
async exportCsv() {
|
|
767
886
|
const qs = this.queryParams.toString();
|
|
768
887
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/${this.typeName}/export/csv${qs ? `?${qs}` : ""}`;
|
|
769
|
-
const res = await this.
|
|
888
|
+
const res = await this.executeRequest(url, {
|
|
770
889
|
headers: {
|
|
771
|
-
...this.getHeaders(),
|
|
772
890
|
"Accept": "text/csv"
|
|
773
891
|
}
|
|
774
892
|
});
|
|
@@ -786,11 +904,13 @@ var SchemaClient = class {
|
|
|
786
904
|
tenantId;
|
|
787
905
|
getToken;
|
|
788
906
|
fetchFn;
|
|
907
|
+
fetchWithAuth;
|
|
789
908
|
constructor(options) {
|
|
790
909
|
this.gatewayUrl = options.gatewayUrl.replace(/\/+$/, "");
|
|
791
910
|
this.tenantId = options.tenantId;
|
|
792
|
-
this.getToken = options.getToken;
|
|
911
|
+
this.getToken = options.getToken || (() => null);
|
|
793
912
|
this.fetchFn = options.fetchFn || (typeof fetch !== "undefined" ? fetch : globalThis.fetch);
|
|
913
|
+
this.fetchWithAuth = options.fetchWithAuth;
|
|
794
914
|
}
|
|
795
915
|
getHeaders() {
|
|
796
916
|
const headers = {
|
|
@@ -808,11 +928,11 @@ var SchemaClient = class {
|
|
|
808
928
|
*/
|
|
809
929
|
async define(definition) {
|
|
810
930
|
const url = `${this.gatewayUrl}/generic/${this.tenantId}/definition`;
|
|
811
|
-
const
|
|
931
|
+
const init = {
|
|
812
932
|
method: "POST",
|
|
813
|
-
headers: this.getHeaders(),
|
|
814
933
|
body: JSON.stringify(definition)
|
|
815
|
-
}
|
|
934
|
+
};
|
|
935
|
+
const res = this.fetchWithAuth ? await this.fetchWithAuth(url, init) : await this.fetchFn(url, { ...init, headers: this.getHeaders() });
|
|
816
936
|
if (!res.ok) {
|
|
817
937
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
818
938
|
throw new Error(err.message || `Failed to define schema for ${definition.typeName}`);
|
|
@@ -866,13 +986,17 @@ var Zone4CodeClient = class {
|
|
|
866
986
|
storage: this.storage,
|
|
867
987
|
storageKey: config.storageKey,
|
|
868
988
|
initialToken: config.token,
|
|
869
|
-
fetchFn: this.fetchFn
|
|
989
|
+
fetchFn: this.fetchFn,
|
|
990
|
+
autoRefresh: config.autoRefresh,
|
|
991
|
+
tokenExpiryBuffer: config.tokenExpiryBuffer,
|
|
992
|
+
onSessionExpired: config.onSessionExpired
|
|
870
993
|
});
|
|
871
994
|
this.schema = new SchemaClient({
|
|
872
995
|
gatewayUrl: this.gatewayUrl,
|
|
873
996
|
tenantId: this.tenantId,
|
|
874
997
|
getToken: () => this.auth.getToken(),
|
|
875
|
-
fetchFn: this.fetchFn
|
|
998
|
+
fetchFn: this.fetchFn,
|
|
999
|
+
fetchWithAuth: (url, init) => this.auth.fetchWithAuth(url, init)
|
|
876
1000
|
});
|
|
877
1001
|
}
|
|
878
1002
|
/**
|
|
@@ -884,7 +1008,8 @@ var Zone4CodeClient = class {
|
|
|
884
1008
|
tenantId: this.tenantId,
|
|
885
1009
|
typeName,
|
|
886
1010
|
getToken: () => this.auth.getToken(),
|
|
887
|
-
fetchFn: this.fetchFn
|
|
1011
|
+
fetchFn: this.fetchFn,
|
|
1012
|
+
fetchWithAuth: (url, init) => this.auth.fetchWithAuth(url, init)
|
|
888
1013
|
});
|
|
889
1014
|
}
|
|
890
1015
|
/**
|
|
@@ -893,21 +1018,17 @@ var Zone4CodeClient = class {
|
|
|
893
1018
|
entities(typeName) {
|
|
894
1019
|
return this.from(typeName);
|
|
895
1020
|
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Register a listener called whenever the session expires completely
|
|
1023
|
+
*/
|
|
1024
|
+
onSessionExpired(callback) {
|
|
1025
|
+
return this.auth.onSessionExpired(callback);
|
|
1026
|
+
}
|
|
896
1027
|
/**
|
|
897
1028
|
* Get current authenticated user profile and platform wallet
|
|
898
1029
|
*/
|
|
899
1030
|
async getMe() {
|
|
900
|
-
const
|
|
901
|
-
if (!token) {
|
|
902
|
-
throw new Error("Not authenticated: please call login() or setToken() first");
|
|
903
|
-
}
|
|
904
|
-
const res = await this.fetchFn(`${this.gatewayUrl}/generic/${this.tenantId}/me`, {
|
|
905
|
-
headers: {
|
|
906
|
-
"Content-Type": "application/json",
|
|
907
|
-
"Authorization": `Bearer ${token}`,
|
|
908
|
-
"x-tenant-id": this.tenantId
|
|
909
|
-
}
|
|
910
|
-
});
|
|
1031
|
+
const res = await this.auth.fetchWithAuth(`${this.gatewayUrl}/generic/${this.tenantId}/me`);
|
|
911
1032
|
if (!res.ok) {
|
|
912
1033
|
const err = await res.json().catch(() => ({ message: res.statusText }));
|
|
913
1034
|
throw new Error(err.message || `Failed to fetch profile & wallet (HTTP ${res.status})`);
|