@gandalan/weblibs 1.1.49 → 1.1.52
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/.eslintrc.cjs +6 -6
- package/api/fluentApi.js +116 -59
- package/package.json +1 -1
package/.eslintrc.cjs
CHANGED
|
@@ -29,20 +29,20 @@ module.exports = {
|
|
|
29
29
|
quotes: ["warn", "double"],
|
|
30
30
|
semi: ["off", "never"],
|
|
31
31
|
"no-multi-spaces": ["warn", { ignoreEOLComments: true }],
|
|
32
|
-
"curly": "
|
|
32
|
+
"curly": "off",
|
|
33
33
|
"comma-spacing": "warn",
|
|
34
|
-
"brace-style": ["
|
|
34
|
+
"brace-style": ["off"],
|
|
35
35
|
"no-var": "warn",
|
|
36
36
|
"key-spacing": "warn",
|
|
37
37
|
"keyword-spacing": "warn",
|
|
38
38
|
"space-infix-ops": "warn",
|
|
39
39
|
"arrow-spacing": "warn",
|
|
40
|
-
"no-trailing-spaces": "
|
|
40
|
+
"no-trailing-spaces": "off",
|
|
41
41
|
"space-before-blocks": "warn",
|
|
42
42
|
"no-unused-vars": ["warn", {
|
|
43
43
|
"args": "none",
|
|
44
44
|
}],
|
|
45
|
-
"no-console": "
|
|
45
|
+
"no-console": "off",
|
|
46
46
|
"no-extra-boolean-cast": "off",
|
|
47
47
|
"no-multiple-empty-lines": ["warn", { "max": 1, "maxBOF": 0 }],
|
|
48
48
|
"lines-between-class-members": ["warn", "always", { exceptAfterSingleLine: true }],
|
|
@@ -52,6 +52,6 @@ module.exports = {
|
|
|
52
52
|
"eol-last": ["warn", "always"],
|
|
53
53
|
"prefer-template": "warn",
|
|
54
54
|
"template-curly-spacing": ["warn", "never"],
|
|
55
|
-
"comma-dangle": ["
|
|
56
|
-
}
|
|
55
|
+
"comma-dangle": ["off"],
|
|
56
|
+
}
|
|
57
57
|
};
|
package/api/fluentApi.js
CHANGED
|
@@ -2,9 +2,12 @@ import { jwtDecode } from "jwt-decode";
|
|
|
2
2
|
|
|
3
3
|
const envs = {};
|
|
4
4
|
|
|
5
|
+
const JWT_SAFE_RENEWAL = 30; // seconds before token expiry to renew
|
|
6
|
+
|
|
5
7
|
export async function fetchEnv(env = "") {
|
|
6
8
|
if (!(env in envs)) {
|
|
7
9
|
const hubUrl = `https://connect.idas-cloudservices.net/api/Endpoints?env=${env}`;
|
|
10
|
+
console.log("fetching env", hubUrl);
|
|
8
11
|
const r = await fetch(hubUrl);
|
|
9
12
|
const data = await r.json();
|
|
10
13
|
envs[env] = data;
|
|
@@ -17,6 +20,20 @@ export function getRefreshToken(token) {
|
|
|
17
20
|
return decoded.refreshToken;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
export function isTokenValid(token)
|
|
24
|
+
{
|
|
25
|
+
try
|
|
26
|
+
{
|
|
27
|
+
const decoded = jwtDecode(token);
|
|
28
|
+
if (!decoded)
|
|
29
|
+
throw new Error("Invalid token");
|
|
30
|
+
return (decoded.exp - JWT_SAFE_RENEWAL > Date.now() / 1000);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
20
37
|
export function authBuilder() {
|
|
21
38
|
return {
|
|
22
39
|
authUrl: "",
|
|
@@ -27,38 +44,28 @@ export function authBuilder() {
|
|
|
27
44
|
useAppToken(appToken = "") {
|
|
28
45
|
this.appToken = appToken; return this;
|
|
29
46
|
},
|
|
47
|
+
|
|
30
48
|
useBaseUrl(authUrl = "") {
|
|
31
49
|
this.authUrl = authUrl; return this;
|
|
32
50
|
},
|
|
51
|
+
|
|
33
52
|
useToken(jwtToken = "") {
|
|
34
53
|
this.token = jwtToken; return this;
|
|
35
54
|
},
|
|
55
|
+
|
|
36
56
|
useRefreshToken(storedRefreshToken = "") {
|
|
37
57
|
this.refreshToken = storedRefreshToken; return this;
|
|
38
58
|
},
|
|
39
59
|
|
|
40
|
-
async authenticate(username = "", password = "")
|
|
60
|
+
async authenticate(username = "", password = "")
|
|
61
|
+
{
|
|
41
62
|
console.log("authenticating:", this.token ? `token set, exp: ${jwtDecode(this.token).exp - (Date.now() / 1000)}` : "no token,", this.refreshToken);
|
|
42
63
|
|
|
43
|
-
if (this.token)
|
|
44
|
-
|
|
45
|
-
const decoded = jwtDecode(this.token);
|
|
46
|
-
if (!decoded) {
|
|
47
|
-
throw new Error("Invalid token");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (decoded.exp - 60 > Date.now() / 1000) {
|
|
51
|
-
return this.token;
|
|
52
|
-
}
|
|
64
|
+
if (this.token && isTokenValid(this.token))
|
|
65
|
+
return this.token;
|
|
53
66
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
} catch (e) {
|
|
58
|
-
console.error("Error decoding token", e);
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
67
|
+
if (this.token && !this.refreshToken)
|
|
68
|
+
this.refreshToken = getRefreshToken(this.token);
|
|
62
69
|
|
|
63
70
|
if (this.refreshToken) {
|
|
64
71
|
try {
|
|
@@ -72,7 +79,6 @@ export function authBuilder() {
|
|
|
72
79
|
// - should still be valid for a while
|
|
73
80
|
}
|
|
74
81
|
return this.token;
|
|
75
|
-
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
if (username && password) {
|
|
@@ -90,7 +96,7 @@ export function authBuilder() {
|
|
|
90
96
|
},
|
|
91
97
|
|
|
92
98
|
async tryRefreshToken(refreshToken = "") {
|
|
93
|
-
const payload = { "Token": refreshToken };
|
|
99
|
+
const payload = { "Token": refreshToken };
|
|
94
100
|
const res = await fetch(`${this.authUrl}/LoginJwt/Refresh`,
|
|
95
101
|
{
|
|
96
102
|
method: "PUT",
|
|
@@ -102,6 +108,58 @@ export function authBuilder() {
|
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
|
|
111
|
+
export function restClient()
|
|
112
|
+
{
|
|
113
|
+
return {
|
|
114
|
+
baseUrl: "",
|
|
115
|
+
token: "",
|
|
116
|
+
|
|
117
|
+
useBaseUrl(url = "") {
|
|
118
|
+
this.baseUrl = url; return this;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
useToken(jwtToken = "") {
|
|
122
|
+
this.token = jwtToken; return this;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
async get(url = "", auth = true) {
|
|
126
|
+
const finalUrl = `${this.baseUrl}/${url}`;
|
|
127
|
+
const headers = this.token ? { "Authorization": `Bearer ${this.token}` } : {};
|
|
128
|
+
const res = await fetch(finalUrl, { method: "GET", headers });
|
|
129
|
+
if (res.ok)
|
|
130
|
+
return await res.json();
|
|
131
|
+
throw new Error(`GET ${finalUrl} failed: ${res.status} ${res.statusText}`);
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
async put(url = "", payload = {}) {
|
|
135
|
+
const finalUrl = `${this.baseUrl}/${url}`;
|
|
136
|
+
const headers = this.token ? { "Authorization": `Bearer ${this.token}`, "Content-Type": "application/json" } : {};
|
|
137
|
+
const res = await fetch(finalUrl, { method: "PUT", body: JSON.stringify(payload), headers });
|
|
138
|
+
if (res.ok)
|
|
139
|
+
return await res.json();
|
|
140
|
+
throw new Error(`PUT ${finalUrl} failed: ${res.status} ${res.statusText}`);
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
async post(url = "", payload = {}) {
|
|
144
|
+
const finalUrl = `${this.baseUrl}/${url}`;
|
|
145
|
+
const headers = this.token ? { "Authorization": `Bearer ${this.token}`, "Content-Type": "application/json" } : {};
|
|
146
|
+
const res = await fetch(finalUrl, { method: "POST", body: JSON.stringify(payload), headers });
|
|
147
|
+
if (res.ok)
|
|
148
|
+
return await res.json();
|
|
149
|
+
throw new Error(`POST ${finalUrl} failed: ${res.status} ${res.statusText}`);
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
async delete(url = "") {
|
|
153
|
+
const finalUrl = `${this.baseUrl}/${url}`;
|
|
154
|
+
const headers = this.token ? { "Authorization": `Bearer ${this.token}` } : {};
|
|
155
|
+
const res = await fetch(finalUrl, { method: "DELETE", headers });
|
|
156
|
+
if (res.ok)
|
|
157
|
+
return await res.json();
|
|
158
|
+
throw new Error(`DELETE ${finalUrl} failed: ${res.status} ${res.statusText}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
105
163
|
export function api() {
|
|
106
164
|
return {
|
|
107
165
|
baseUrl: "",
|
|
@@ -115,74 +173,68 @@ export function api() {
|
|
|
115
173
|
useEnvironment(env = "") {
|
|
116
174
|
this.env = env; return this;
|
|
117
175
|
},
|
|
176
|
+
|
|
118
177
|
useAppToken(newApptoken = "") {
|
|
119
178
|
this.appToken = newApptoken; return this;
|
|
120
179
|
},
|
|
180
|
+
|
|
121
181
|
useBaseUrl(url = "") {
|
|
122
182
|
this.baseUrl = url; return this;
|
|
123
183
|
},
|
|
184
|
+
|
|
124
185
|
useAuthUrl(url = "") {
|
|
125
186
|
this.authUrl = url; return this;
|
|
126
187
|
},
|
|
188
|
+
|
|
127
189
|
useToken(jwtToken = "") {
|
|
128
190
|
this.token = jwtToken; return this;
|
|
129
191
|
},
|
|
192
|
+
|
|
130
193
|
useRefreshToken(storedRefreshToken = "") {
|
|
131
194
|
this.refreshToken = storedRefreshToken; return this;
|
|
132
195
|
},
|
|
196
|
+
|
|
133
197
|
useGlobalAuth() {
|
|
134
198
|
// eslint-disable-next-line no-undef
|
|
135
|
-
this.token = globalThis.
|
|
199
|
+
this.token = globalThis.idasTokens.token; this.refreshToken = globalThis.idasTokens.refreshToken; return this;
|
|
136
200
|
},
|
|
137
201
|
|
|
138
|
-
async get(url = "") {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const res = await fetch(`${this.baseUrl}/${url}`, { method: "GET", headers });
|
|
143
|
-
return await res.json();
|
|
202
|
+
async get(url = "", auth = true) {
|
|
203
|
+
if (auth)
|
|
204
|
+
await this.ensureAuthenticated();
|
|
205
|
+
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).get(url);
|
|
144
206
|
},
|
|
145
207
|
|
|
146
|
-
async put(url = "", payload = {}) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const headers = this.token ? { "Authorization": `Bearer ${this.token}`, "Content-Type": "application/json" } : {};
|
|
151
|
-
const res = await fetch(`${this.baseUrl}/${url}`,
|
|
152
|
-
{ method: "PUT", body: JSON.stringify(payload), headers });
|
|
153
|
-
return await res.json();
|
|
208
|
+
async put(url = "", payload = {}, auth = true) {
|
|
209
|
+
if (auth)
|
|
210
|
+
await this.ensureAuthenticated();
|
|
211
|
+
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).put(url, payload);
|
|
154
212
|
},
|
|
155
213
|
|
|
156
|
-
async post(url = "", payload = {}) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const headers = this.token ? { "Authorization": `Bearer ${this.token}`, "Content-Type": "application/json" } : {};
|
|
161
|
-
const res = await fetch(`${this.baseUrl}/${url}`,
|
|
162
|
-
{ method: "POST", body: JSON.stringify(payload), headers });
|
|
163
|
-
return await res.json();
|
|
214
|
+
async post(url = "", payload = {}, auth = true) {
|
|
215
|
+
if (auth)
|
|
216
|
+
await this.ensureAuthenticated();
|
|
217
|
+
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).post(url, payload);
|
|
164
218
|
},
|
|
165
219
|
|
|
166
|
-
async delete(url = "") {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const headers = this.token ? { "Authorization": `Bearer ${this.token}` } : {};
|
|
171
|
-
const res = await fetch(`${this.baseUrl}/${url}`, { method: "DELETE", headers });
|
|
172
|
-
return await res.json();
|
|
220
|
+
async delete(url = "", auth = true) {
|
|
221
|
+
if (auth)
|
|
222
|
+
await this.ensureAuthenticated();
|
|
223
|
+
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).delete(url);
|
|
173
224
|
},
|
|
174
225
|
|
|
175
226
|
async ensureAuthenticated() {
|
|
176
|
-
|
|
177
|
-
if (!this.token && !this.refreshToken) {
|
|
227
|
+
if (this.token && isTokenValid(this.token))
|
|
178
228
|
return;
|
|
179
|
-
|
|
229
|
+
|
|
230
|
+
await this.ensureBaseUrlIsSet();
|
|
231
|
+
|
|
180
232
|
try {
|
|
181
233
|
const temptoken = await authBuilder()
|
|
182
|
-
.useToken(this.token)
|
|
183
|
-
.useRefreshToken(this.refreshToken)
|
|
184
234
|
.useAppToken(this.appToken)
|
|
185
235
|
.useBaseUrl(this.authUrl)
|
|
236
|
+
.useToken(this.token)
|
|
237
|
+
.useRefreshToken(this.refreshToken)
|
|
186
238
|
.authenticate() || "";
|
|
187
239
|
|
|
188
240
|
if (!temptoken) {
|
|
@@ -202,15 +254,20 @@ export function api() {
|
|
|
202
254
|
},
|
|
203
255
|
|
|
204
256
|
async ensureBaseUrlIsSet() {
|
|
205
|
-
if (this.env && !this.baseUrl) {
|
|
257
|
+
if (this.env && (!this.baseUrl || !this.authUrl)) {
|
|
206
258
|
const envInfo = await fetchEnv(this.env);
|
|
207
|
-
this.baseUrl = envInfo.idas;
|
|
208
|
-
this.authUrl = envInfo.idas;
|
|
259
|
+
this.baseUrl = this.baseUrl || envInfo.idas;
|
|
260
|
+
this.authUrl = this.authUrl || envInfo.idas;
|
|
261
|
+
console.log("envInfo", envInfo);
|
|
209
262
|
}
|
|
210
263
|
|
|
211
264
|
if (!this.baseUrl) {
|
|
212
265
|
throw new Error("apiBaseurl not set");
|
|
213
266
|
}
|
|
267
|
+
|
|
268
|
+
if (!this.authUrl) {
|
|
269
|
+
throw new Error("authUrl not set");
|
|
270
|
+
}
|
|
214
271
|
},
|
|
215
272
|
|
|
216
273
|
redirectToLogin(authPath = "") {
|