@nocios/crudify-ui 1.1.0 → 1.2.1
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/CrudifyDataProvider-F6UCGYUF.mjs +14 -0
- package/dist/chunk-ZV5J7FRE.mjs +1166 -0
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +1419 -1313
- package/dist/index.mjs +280 -1388
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -28,6 +31,1211 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
31
|
));
|
|
29
32
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
33
|
|
|
34
|
+
// src/components/CrudifyLogin/utils/cookies.ts
|
|
35
|
+
var getCookie;
|
|
36
|
+
var init_cookies = __esm({
|
|
37
|
+
"src/components/CrudifyLogin/utils/cookies.ts"() {
|
|
38
|
+
"use strict";
|
|
39
|
+
getCookie = (name) => {
|
|
40
|
+
const match = document.cookie.match(new RegExp("(^|;)\\s*" + name + "=([^;]+)"));
|
|
41
|
+
return match ? match[2] : null;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// src/components/CrudifyLogin/utils/secureStorage.ts
|
|
47
|
+
var import_crypto_js, SecureStorage, secureSessionStorage, secureLocalStorage;
|
|
48
|
+
var init_secureStorage = __esm({
|
|
49
|
+
"src/components/CrudifyLogin/utils/secureStorage.ts"() {
|
|
50
|
+
"use strict";
|
|
51
|
+
import_crypto_js = __toESM(require("crypto-js"));
|
|
52
|
+
SecureStorage = class {
|
|
53
|
+
constructor(storageType = "sessionStorage") {
|
|
54
|
+
this.encryptionKey = this.generateEncryptionKey();
|
|
55
|
+
this.storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
56
|
+
}
|
|
57
|
+
generateEncryptionKey() {
|
|
58
|
+
const browserFingerprint = [
|
|
59
|
+
navigator.userAgent,
|
|
60
|
+
navigator.language,
|
|
61
|
+
(/* @__PURE__ */ new Date()).getTimezoneOffset(),
|
|
62
|
+
screen.colorDepth,
|
|
63
|
+
screen.width,
|
|
64
|
+
screen.height,
|
|
65
|
+
"crudify-login"
|
|
66
|
+
].join("|");
|
|
67
|
+
return import_crypto_js.default.SHA256(browserFingerprint).toString();
|
|
68
|
+
}
|
|
69
|
+
setItem(key, value, expiryMinutes) {
|
|
70
|
+
try {
|
|
71
|
+
const encrypted = import_crypto_js.default.AES.encrypt(value, this.encryptionKey).toString();
|
|
72
|
+
this.storage.setItem(key, encrypted);
|
|
73
|
+
if (expiryMinutes) {
|
|
74
|
+
const expiryTime = (/* @__PURE__ */ new Date()).getTime() + expiryMinutes * 60 * 1e3;
|
|
75
|
+
this.storage.setItem(`${key}_expiry`, expiryTime.toString());
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error("Failed to encrypt and store data:", error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
getItem(key) {
|
|
82
|
+
try {
|
|
83
|
+
const expiryKey = `${key}_expiry`;
|
|
84
|
+
const expiry = this.storage.getItem(expiryKey);
|
|
85
|
+
if (expiry) {
|
|
86
|
+
const expiryTime = parseInt(expiry, 10);
|
|
87
|
+
if ((/* @__PURE__ */ new Date()).getTime() > expiryTime) {
|
|
88
|
+
this.removeItem(key);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const encrypted = this.storage.getItem(key);
|
|
93
|
+
if (!encrypted) return null;
|
|
94
|
+
const decrypted = import_crypto_js.default.AES.decrypt(encrypted, this.encryptionKey);
|
|
95
|
+
const result = decrypted.toString(import_crypto_js.default.enc.Utf8);
|
|
96
|
+
if (!result) {
|
|
97
|
+
console.warn("Failed to decrypt stored data - may be corrupted");
|
|
98
|
+
this.removeItem(key);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error("Failed to decrypt data:", error);
|
|
104
|
+
this.removeItem(key);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
removeItem(key) {
|
|
109
|
+
this.storage.removeItem(key);
|
|
110
|
+
this.storage.removeItem(`${key}_expiry`);
|
|
111
|
+
}
|
|
112
|
+
setToken(token) {
|
|
113
|
+
try {
|
|
114
|
+
const parts = token.split(".");
|
|
115
|
+
if (parts.length === 3) {
|
|
116
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
117
|
+
if (payload.exp) {
|
|
118
|
+
const expiryTime = payload.exp * 1e3;
|
|
119
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
120
|
+
const minutesUntilExpiry = Math.floor((expiryTime - now) / (60 * 1e3));
|
|
121
|
+
if (minutesUntilExpiry > 0) {
|
|
122
|
+
this.setItem("authToken", token, minutesUntilExpiry);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.warn("Failed to parse token expiry, using default expiry");
|
|
129
|
+
}
|
|
130
|
+
this.setItem("authToken", token, 24 * 60);
|
|
131
|
+
}
|
|
132
|
+
getToken() {
|
|
133
|
+
const token = this.getItem("authToken");
|
|
134
|
+
if (token) {
|
|
135
|
+
try {
|
|
136
|
+
const parts = token.split(".");
|
|
137
|
+
if (parts.length === 3) {
|
|
138
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
139
|
+
if (payload.exp) {
|
|
140
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
141
|
+
if (payload.exp < now) {
|
|
142
|
+
this.removeItem("authToken");
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.warn("Failed to validate token expiry");
|
|
149
|
+
this.removeItem("authToken");
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return token;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
secureSessionStorage = new SecureStorage("sessionStorage");
|
|
157
|
+
secureLocalStorage = new SecureStorage("localStorage");
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// src/core/ConfigurationManager.ts
|
|
162
|
+
var _ConfigurationManager, ConfigurationManager, configurationManager;
|
|
163
|
+
var init_ConfigurationManager = __esm({
|
|
164
|
+
"src/core/ConfigurationManager.ts"() {
|
|
165
|
+
"use strict";
|
|
166
|
+
init_cookies();
|
|
167
|
+
_ConfigurationManager = class _ConfigurationManager {
|
|
168
|
+
constructor() {
|
|
169
|
+
this.resolvedConfig = null;
|
|
170
|
+
this.configError = null;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Singleton pattern to ensure consistent configuration across the app
|
|
174
|
+
*/
|
|
175
|
+
static getInstance() {
|
|
176
|
+
if (!_ConfigurationManager.instance) {
|
|
177
|
+
_ConfigurationManager.instance = new _ConfigurationManager();
|
|
178
|
+
}
|
|
179
|
+
return _ConfigurationManager.instance;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Reset the singleton instance (useful for testing)
|
|
183
|
+
*/
|
|
184
|
+
static resetInstance() {
|
|
185
|
+
_ConfigurationManager.instance = null;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Resolve configuration from all sources with proper priority
|
|
189
|
+
*/
|
|
190
|
+
resolveConfig(propsConfig = {}) {
|
|
191
|
+
if (this.resolvedConfig && this.isConfigStillValid(propsConfig)) {
|
|
192
|
+
return this.resolvedConfig;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
this.configError = null;
|
|
196
|
+
const envConfig = this.getEnvConfig();
|
|
197
|
+
const cookieConfig = this.getCookieConfig();
|
|
198
|
+
const configSource = {
|
|
199
|
+
env: "default",
|
|
200
|
+
publicApiKey: "default",
|
|
201
|
+
loginActions: "default",
|
|
202
|
+
appName: "default",
|
|
203
|
+
logo: "default",
|
|
204
|
+
colors: "default"
|
|
205
|
+
};
|
|
206
|
+
const env = this.resolveValue("env", propsConfig.env, envConfig.env, cookieConfig.env, "prod", configSource);
|
|
207
|
+
const publicApiKey = this.resolveValue("publicApiKey", propsConfig.publicApiKey, envConfig.publicApiKey, cookieConfig.publicApiKey, void 0, configSource);
|
|
208
|
+
const loginActions = this.resolveValue("loginActions", propsConfig.loginActions, envConfig.loginActions, cookieConfig.loginActions, [], configSource);
|
|
209
|
+
const appName = this.resolveValue("appName", propsConfig.appName, envConfig.appName, cookieConfig.appName, "Crudify App", configSource);
|
|
210
|
+
const logo = this.resolveValue("logo", propsConfig.logo, envConfig.logo, cookieConfig.logo, "", configSource);
|
|
211
|
+
const colors = this.resolveValue("colors", propsConfig.colors, envConfig.colors, cookieConfig.colors, {}, configSource);
|
|
212
|
+
if (!publicApiKey) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
"publicApiKey is required. Provide it via:\n1. Props: <CrudifyDataProvider publicApiKey={...} />\n2. Environment: VITE_TEST_PUBLIC_API_KEY\n3. Cookie: publicApiKey"
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
this.resolvedConfig = {
|
|
218
|
+
env,
|
|
219
|
+
publicApiKey,
|
|
220
|
+
loginActions,
|
|
221
|
+
appName,
|
|
222
|
+
logo,
|
|
223
|
+
colors,
|
|
224
|
+
configSource,
|
|
225
|
+
rawConfig: {
|
|
226
|
+
props: propsConfig,
|
|
227
|
+
env: envConfig,
|
|
228
|
+
cookies: cookieConfig
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
console.log("\u{1F527} ConfigurationManager - Configuration resolved:", {
|
|
232
|
+
config: {
|
|
233
|
+
env: this.resolvedConfig.env,
|
|
234
|
+
publicApiKey: `${this.resolvedConfig.publicApiKey.substring(0, 8)}...`,
|
|
235
|
+
appName: this.resolvedConfig.appName,
|
|
236
|
+
loginActionsCount: this.resolvedConfig.loginActions.length
|
|
237
|
+
},
|
|
238
|
+
sources: this.resolvedConfig.configSource
|
|
239
|
+
});
|
|
240
|
+
return this.resolvedConfig;
|
|
241
|
+
} catch (error) {
|
|
242
|
+
this.configError = error instanceof Error ? error.message : "Unknown configuration error";
|
|
243
|
+
console.error("\u{1F527} ConfigurationManager - Configuration error:", this.configError);
|
|
244
|
+
this.resolvedConfig = {
|
|
245
|
+
env: "prod",
|
|
246
|
+
publicApiKey: "",
|
|
247
|
+
loginActions: [],
|
|
248
|
+
appName: "Crudify App",
|
|
249
|
+
logo: "",
|
|
250
|
+
colors: {},
|
|
251
|
+
configSource: {
|
|
252
|
+
env: "default",
|
|
253
|
+
publicApiKey: "default",
|
|
254
|
+
loginActions: "default",
|
|
255
|
+
appName: "default",
|
|
256
|
+
logo: "default",
|
|
257
|
+
colors: "default"
|
|
258
|
+
},
|
|
259
|
+
rawConfig: {
|
|
260
|
+
props: propsConfig,
|
|
261
|
+
env: {},
|
|
262
|
+
cookies: {},
|
|
263
|
+
error: this.configError
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
return this.resolvedConfig;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Check if current configuration is still valid for the given props
|
|
271
|
+
*/
|
|
272
|
+
isConfigStillValid(propsConfig) {
|
|
273
|
+
if (!this.resolvedConfig) return false;
|
|
274
|
+
const currentProps = this.resolvedConfig.rawConfig.props;
|
|
275
|
+
return JSON.stringify(currentProps) === JSON.stringify(propsConfig);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Resolve a single config value with priority and source tracking
|
|
279
|
+
*/
|
|
280
|
+
resolveValue(key, propsValue, envValue, cookieValue, defaultValue, configSource) {
|
|
281
|
+
if (propsValue !== void 0) {
|
|
282
|
+
configSource[key] = "props";
|
|
283
|
+
return propsValue;
|
|
284
|
+
}
|
|
285
|
+
if (envValue !== void 0) {
|
|
286
|
+
configSource[key] = "env";
|
|
287
|
+
return envValue;
|
|
288
|
+
}
|
|
289
|
+
if (cookieValue !== void 0) {
|
|
290
|
+
configSource[key] = "cookies";
|
|
291
|
+
return cookieValue;
|
|
292
|
+
}
|
|
293
|
+
configSource[key] = "default";
|
|
294
|
+
return defaultValue;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get configuration from environment variables
|
|
298
|
+
*/
|
|
299
|
+
getEnvConfig() {
|
|
300
|
+
const config = {};
|
|
301
|
+
try {
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.warn("\u{1F527} ConfigurationManager - Environment variables not available:", error);
|
|
304
|
+
}
|
|
305
|
+
return config;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Get configuration from cookies (multi-tenant support)
|
|
309
|
+
*/
|
|
310
|
+
getCookieConfig() {
|
|
311
|
+
const config = {};
|
|
312
|
+
try {
|
|
313
|
+
const env = getCookie("environment");
|
|
314
|
+
if (env && ["dev", "stg", "prod"].includes(env)) {
|
|
315
|
+
config.env = env;
|
|
316
|
+
}
|
|
317
|
+
const publicApiKey = getCookie("publicApiKey");
|
|
318
|
+
if (publicApiKey) {
|
|
319
|
+
config.publicApiKey = publicApiKey;
|
|
320
|
+
}
|
|
321
|
+
const appName = getCookie("appName");
|
|
322
|
+
if (appName) {
|
|
323
|
+
config.appName = appName;
|
|
324
|
+
}
|
|
325
|
+
const loginActions = getCookie("loginActions");
|
|
326
|
+
if (loginActions) {
|
|
327
|
+
config.loginActions = loginActions.split(",").map((action) => action.trim()).filter(Boolean);
|
|
328
|
+
}
|
|
329
|
+
const logo = getCookie("logo");
|
|
330
|
+
if (logo) {
|
|
331
|
+
config.logo = logo;
|
|
332
|
+
}
|
|
333
|
+
const colors = getCookie("colors");
|
|
334
|
+
if (colors) {
|
|
335
|
+
try {
|
|
336
|
+
config.colors = JSON.parse(colors);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.warn("\u{1F527} ConfigurationManager - Failed to parse colors from cookie:", error);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.warn("\u{1F527} ConfigurationManager - Error reading cookies:", error);
|
|
343
|
+
}
|
|
344
|
+
return config;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Get the current resolved configuration
|
|
348
|
+
*/
|
|
349
|
+
getConfig() {
|
|
350
|
+
return this.resolvedConfig;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Get any configuration errors
|
|
354
|
+
*/
|
|
355
|
+
getConfigError() {
|
|
356
|
+
return this.configError;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Check if configuration is valid (no errors and has required fields)
|
|
360
|
+
*/
|
|
361
|
+
isConfigured() {
|
|
362
|
+
return this.resolvedConfig !== null && this.configError === null && !!this.resolvedConfig.publicApiKey;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Clear the current configuration (useful for testing or reconfiguration)
|
|
366
|
+
*/
|
|
367
|
+
clearConfig() {
|
|
368
|
+
this.resolvedConfig = null;
|
|
369
|
+
this.configError = null;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
_ConfigurationManager.instance = null;
|
|
373
|
+
ConfigurationManager = _ConfigurationManager;
|
|
374
|
+
configurationManager = ConfigurationManager.getInstance();
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// src/core/CrudifyInitializer.ts
|
|
379
|
+
var import_crudify_browser2, _CrudifyInitializer, CrudifyInitializer, crudifyInitializer;
|
|
380
|
+
var init_CrudifyInitializer = __esm({
|
|
381
|
+
"src/core/CrudifyInitializer.ts"() {
|
|
382
|
+
"use strict";
|
|
383
|
+
import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
|
|
384
|
+
_CrudifyInitializer = class _CrudifyInitializer {
|
|
385
|
+
constructor() {
|
|
386
|
+
this.state = {
|
|
387
|
+
isInitialized: false,
|
|
388
|
+
isInitializing: false,
|
|
389
|
+
initializationError: null,
|
|
390
|
+
config: null,
|
|
391
|
+
initializationPromise: null
|
|
392
|
+
};
|
|
393
|
+
console.log("\u{1F680} CrudifyInitializer - Instance created");
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Singleton pattern to ensure global initialization coordination
|
|
397
|
+
*/
|
|
398
|
+
static getInstance() {
|
|
399
|
+
if (!_CrudifyInitializer.instance) {
|
|
400
|
+
_CrudifyInitializer.instance = new _CrudifyInitializer();
|
|
401
|
+
}
|
|
402
|
+
return _CrudifyInitializer.instance;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Reset the singleton instance (useful for testing)
|
|
406
|
+
*/
|
|
407
|
+
static resetInstance() {
|
|
408
|
+
_CrudifyInitializer.instance = null;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Initialize crudify with the given configuration
|
|
412
|
+
* This method is idempotent and thread-safe
|
|
413
|
+
*/
|
|
414
|
+
async initialize(config) {
|
|
415
|
+
if (this.state.isInitialized && this.isConfigurationSame(config)) {
|
|
416
|
+
console.log("\u{1F680} CrudifyInitializer - Already initialized with same config");
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (this.state.isInitializing && this.state.initializationPromise) {
|
|
420
|
+
console.log("\u{1F680} CrudifyInitializer - Waiting for ongoing initialization");
|
|
421
|
+
await this.state.initializationPromise;
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (this.state.isInitialized && !this.isConfigurationSame(config)) {
|
|
425
|
+
console.log("\u{1F680} CrudifyInitializer - Configuration changed, re-initializing");
|
|
426
|
+
this.reset();
|
|
427
|
+
}
|
|
428
|
+
this.state.isInitializing = true;
|
|
429
|
+
this.state.initializationError = null;
|
|
430
|
+
this.state.initializationPromise = this.performInitialization(config);
|
|
431
|
+
try {
|
|
432
|
+
await this.state.initializationPromise;
|
|
433
|
+
this.state.isInitialized = true;
|
|
434
|
+
this.state.config = { ...config };
|
|
435
|
+
console.log("\u{1F680} CrudifyInitializer - Initialization completed successfully");
|
|
436
|
+
} catch (error) {
|
|
437
|
+
this.state.initializationError = error instanceof Error ? error.message : "Unknown initialization error";
|
|
438
|
+
console.error("\u{1F680} CrudifyInitializer - Initialization failed:", this.state.initializationError);
|
|
439
|
+
throw error;
|
|
440
|
+
} finally {
|
|
441
|
+
this.state.isInitializing = false;
|
|
442
|
+
this.state.initializationPromise = null;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Perform the actual initialization process
|
|
447
|
+
*/
|
|
448
|
+
async performInitialization(config) {
|
|
449
|
+
if (!config.publicApiKey) {
|
|
450
|
+
throw new Error("publicApiKey is required for crudify initialization");
|
|
451
|
+
}
|
|
452
|
+
console.log("\u{1F680} CrudifyInitializer - Starting initialization with config:", {
|
|
453
|
+
env: config.env,
|
|
454
|
+
publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
|
|
455
|
+
appName: config.appName
|
|
456
|
+
});
|
|
457
|
+
try {
|
|
458
|
+
const environment = config.env || "prod";
|
|
459
|
+
console.log("\u{1F680} CrudifyInitializer - Step 1: Configuring environment:", environment);
|
|
460
|
+
await import_crudify_browser2.default.config(environment);
|
|
461
|
+
console.log("\u{1F680} CrudifyInitializer - Step 2: Initializing with API key");
|
|
462
|
+
await import_crudify_browser2.default.init(config.publicApiKey, "none");
|
|
463
|
+
console.log("\u{1F680} CrudifyInitializer - Step 3: Verifying initialization");
|
|
464
|
+
await this.verifyInitialization();
|
|
465
|
+
console.log("\u{1F680} CrudifyInitializer - All initialization steps completed");
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.error("\u{1F680} CrudifyInitializer - Initialization failed at step:", error);
|
|
468
|
+
throw new Error(
|
|
469
|
+
`Crudify initialization failed: ${error instanceof Error ? error.message : "Unknown error"}. Please check your configuration (env: ${config.env || "prod"}, publicApiKey: ${config.publicApiKey ? "provided" : "missing"})`
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Verify that crudify is properly initialized by checking core methods
|
|
475
|
+
*/
|
|
476
|
+
async verifyInitialization() {
|
|
477
|
+
const requiredMethods = ["readItems", "readItem", "createItem", "updateItem", "deleteItem", "login", "transaction"];
|
|
478
|
+
const missingMethods = [];
|
|
479
|
+
for (const method of requiredMethods) {
|
|
480
|
+
if (typeof import_crudify_browser2.default[method] !== "function") {
|
|
481
|
+
missingMethods.push(method);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (missingMethods.length > 0) {
|
|
485
|
+
throw new Error(
|
|
486
|
+
`Crudify initialization incomplete. Missing methods: ${missingMethods.join(", ")}. This usually indicates a configuration or network issue.`
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
console.log("\u{1F680} CrudifyInitializer - Verification successful (test call skipped for performance)");
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Check if the given configuration is the same as the current one
|
|
493
|
+
*/
|
|
494
|
+
isConfigurationSame(config) {
|
|
495
|
+
if (!this.state.config) return false;
|
|
496
|
+
return this.state.config.env === config.env && this.state.config.publicApiKey === config.publicApiKey;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Reset the initialization state (useful for testing or configuration changes)
|
|
500
|
+
*/
|
|
501
|
+
reset() {
|
|
502
|
+
console.log("\u{1F680} CrudifyInitializer - Resetting initialization state");
|
|
503
|
+
this.state = {
|
|
504
|
+
isInitialized: false,
|
|
505
|
+
isInitializing: false,
|
|
506
|
+
initializationError: null,
|
|
507
|
+
config: null,
|
|
508
|
+
initializationPromise: null
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get the current initialization status
|
|
513
|
+
*/
|
|
514
|
+
getStatus() {
|
|
515
|
+
return {
|
|
516
|
+
isInitialized: this.state.isInitialized,
|
|
517
|
+
isInitializing: this.state.isInitializing,
|
|
518
|
+
initializationError: this.state.initializationError,
|
|
519
|
+
config: this.state.config
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Check if crudify is ready to use
|
|
524
|
+
*/
|
|
525
|
+
isReady() {
|
|
526
|
+
return this.state.isInitialized && !this.state.initializationError;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Get the current initialization error, if any
|
|
530
|
+
*/
|
|
531
|
+
getError() {
|
|
532
|
+
return this.state.initializationError;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Force re-initialization (useful when configuration changes)
|
|
536
|
+
*/
|
|
537
|
+
async reinitialize(config) {
|
|
538
|
+
console.log("\u{1F680} CrudifyInitializer - Forcing re-initialization");
|
|
539
|
+
this.reset();
|
|
540
|
+
await this.initialize(config);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Check if initialization is currently in progress
|
|
544
|
+
*/
|
|
545
|
+
isInitializing() {
|
|
546
|
+
return this.state.isInitializing;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Wait for any ongoing initialization to complete
|
|
550
|
+
*/
|
|
551
|
+
async waitForInitialization() {
|
|
552
|
+
if (this.state.initializationPromise) {
|
|
553
|
+
await this.state.initializationPromise;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
_CrudifyInitializer.instance = null;
|
|
558
|
+
CrudifyInitializer = _CrudifyInitializer;
|
|
559
|
+
crudifyInitializer = CrudifyInitializer.getInstance();
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// src/utils/jwtUtils.ts
|
|
564
|
+
var decodeJwtSafely, getCurrentUserEmail, isTokenExpired;
|
|
565
|
+
var init_jwtUtils = __esm({
|
|
566
|
+
"src/utils/jwtUtils.ts"() {
|
|
567
|
+
"use strict";
|
|
568
|
+
decodeJwtSafely = (token) => {
|
|
569
|
+
try {
|
|
570
|
+
const parts = token.split(".");
|
|
571
|
+
if (parts.length !== 3) {
|
|
572
|
+
console.warn("Invalid JWT format: token must have 3 parts");
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
const payload = parts[1];
|
|
576
|
+
const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
|
|
577
|
+
const decodedPayload = JSON.parse(atob(paddedPayload));
|
|
578
|
+
return decodedPayload;
|
|
579
|
+
} catch (error) {
|
|
580
|
+
console.warn("Failed to decode JWT token:", error);
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
getCurrentUserEmail = () => {
|
|
585
|
+
try {
|
|
586
|
+
let token = null;
|
|
587
|
+
token = sessionStorage.getItem("authToken");
|
|
588
|
+
console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
|
|
589
|
+
if (!token) {
|
|
590
|
+
token = sessionStorage.getItem("token");
|
|
591
|
+
console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
|
|
592
|
+
}
|
|
593
|
+
if (!token) {
|
|
594
|
+
token = localStorage.getItem("authToken") || localStorage.getItem("token");
|
|
595
|
+
console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
|
|
596
|
+
}
|
|
597
|
+
if (!token) {
|
|
598
|
+
console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
const payload = decodeJwtSafely(token);
|
|
602
|
+
if (!payload) {
|
|
603
|
+
console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
const email = payload.email || payload["cognito:username"] || null;
|
|
607
|
+
console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
|
|
608
|
+
return email;
|
|
609
|
+
} catch (error) {
|
|
610
|
+
console.warn("Failed to get current user email:", error);
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
isTokenExpired = (token) => {
|
|
615
|
+
try {
|
|
616
|
+
const payload = decodeJwtSafely(token);
|
|
617
|
+
if (!payload || !payload.exp) return true;
|
|
618
|
+
const currentTime = Math.floor(Date.now() / 1e3);
|
|
619
|
+
return payload.exp < currentTime;
|
|
620
|
+
} catch {
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// src/core/TokenManager.ts
|
|
628
|
+
var import_crudify_browser3, _TokenManager, TokenManager, tokenManager;
|
|
629
|
+
var init_TokenManager = __esm({
|
|
630
|
+
"src/core/TokenManager.ts"() {
|
|
631
|
+
"use strict";
|
|
632
|
+
import_crudify_browser3 = __toESM(require("@nocios/crudify-browser"));
|
|
633
|
+
init_secureStorage();
|
|
634
|
+
init_jwtUtils();
|
|
635
|
+
_TokenManager = class _TokenManager {
|
|
636
|
+
constructor() {
|
|
637
|
+
this.TOKEN_KEY = "authToken";
|
|
638
|
+
// Compatible with crudia-ui
|
|
639
|
+
this.tokenCache = null;
|
|
640
|
+
this.parsedTokenCache = null;
|
|
641
|
+
this.expirationCheckInterval = null;
|
|
642
|
+
this.storageEventListener = null;
|
|
643
|
+
this.initializeTokenManager();
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Singleton pattern to ensure consistent token management
|
|
647
|
+
*/
|
|
648
|
+
static getInstance() {
|
|
649
|
+
if (!_TokenManager.instance) {
|
|
650
|
+
_TokenManager.instance = new _TokenManager();
|
|
651
|
+
}
|
|
652
|
+
return _TokenManager.instance;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Reset the singleton instance (useful for testing)
|
|
656
|
+
*/
|
|
657
|
+
static resetInstance() {
|
|
658
|
+
if (_TokenManager.instance) {
|
|
659
|
+
_TokenManager.instance.cleanup();
|
|
660
|
+
}
|
|
661
|
+
_TokenManager.instance = null;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Initialize the token manager with storage synchronization
|
|
665
|
+
*/
|
|
666
|
+
initializeTokenManager() {
|
|
667
|
+
console.log("\u{1F510} TokenManager - Initializing token management");
|
|
668
|
+
this.migrateFromLocalStorage();
|
|
669
|
+
this.loadTokenFromStorage();
|
|
670
|
+
this.setupExpirationCheck();
|
|
671
|
+
this.setupStorageListener();
|
|
672
|
+
console.log("\u{1F510} TokenManager - Initialization complete");
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Migrate tokens from localStorage to sessionStorage for better security
|
|
676
|
+
* This ensures compatibility with older implementations
|
|
677
|
+
*/
|
|
678
|
+
migrateFromLocalStorage() {
|
|
679
|
+
try {
|
|
680
|
+
const legacyKeys = ["authToken", "token", "jwt", "jwtToken"];
|
|
681
|
+
for (const key of legacyKeys) {
|
|
682
|
+
const token = localStorage.getItem(key);
|
|
683
|
+
if (token && !secureSessionStorage.getToken()) {
|
|
684
|
+
console.log(`\u{1F510} TokenManager - Migrating token from localStorage key: ${key}`);
|
|
685
|
+
secureSessionStorage.setToken(token);
|
|
686
|
+
localStorage.removeItem(key);
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
} catch (error) {
|
|
691
|
+
console.warn("\u{1F510} TokenManager - Token migration failed:", error);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Load token from storage and synchronize with crudify
|
|
696
|
+
*/
|
|
697
|
+
loadTokenFromStorage() {
|
|
698
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Entry point - loading token from storage");
|
|
699
|
+
try {
|
|
700
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure session storage");
|
|
701
|
+
const storedToken = secureSessionStorage.getToken();
|
|
702
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists:", !!storedToken);
|
|
703
|
+
if (storedToken && this.isTokenValid(storedToken)) {
|
|
704
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token is valid, updating cache");
|
|
705
|
+
this.tokenCache = storedToken;
|
|
706
|
+
this.parsedTokenCache = this.parseToken(storedToken);
|
|
707
|
+
this.syncTokenWithCrudify(storedToken);
|
|
708
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Token loaded from storage and synchronized");
|
|
709
|
+
} else if (storedToken) {
|
|
710
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists but is invalid/expired, clearing");
|
|
711
|
+
this.clearToken();
|
|
712
|
+
} else {
|
|
713
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: No stored token found");
|
|
714
|
+
}
|
|
715
|
+
} catch (error) {
|
|
716
|
+
console.warn("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Error loading token from storage:", error);
|
|
717
|
+
this.clearToken();
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Set up automatic token expiration checking
|
|
722
|
+
*/
|
|
723
|
+
setupExpirationCheck() {
|
|
724
|
+
this.expirationCheckInterval = window.setInterval(() => {
|
|
725
|
+
if (this.tokenCache && !this.isTokenValid(this.tokenCache)) {
|
|
726
|
+
console.log("\u{1F510} TokenManager - Token expired, clearing automatically");
|
|
727
|
+
this.clearToken();
|
|
728
|
+
}
|
|
729
|
+
}, 3e4);
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Set up storage event listener for cross-tab synchronization
|
|
733
|
+
*/
|
|
734
|
+
setupStorageListener() {
|
|
735
|
+
this.storageEventListener = (event) => {
|
|
736
|
+
if (event.key === this.TOKEN_KEY) {
|
|
737
|
+
console.log("\u{1F510} TokenManager - Token change detected from another tab");
|
|
738
|
+
this.loadTokenFromStorage();
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
window.addEventListener("storage", this.storageEventListener);
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Set a new JWT token with automatic synchronization
|
|
745
|
+
*/
|
|
746
|
+
setToken(token) {
|
|
747
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: Entry point - setting token:", token ? "provided" : "null");
|
|
748
|
+
try {
|
|
749
|
+
if (!token) {
|
|
750
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: No token provided, clearing token");
|
|
751
|
+
this.clearToken();
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: Validating token before setting");
|
|
755
|
+
if (!this.isTokenValid(token)) {
|
|
756
|
+
console.warn("\u{1F510} TokenManager - SET_TOKEN: Attempted to set invalid or expired token");
|
|
757
|
+
this.clearToken();
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: Token is valid, updating cache");
|
|
761
|
+
this.tokenCache = token;
|
|
762
|
+
this.parsedTokenCache = this.parseToken(token);
|
|
763
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: Storing token in secure storage");
|
|
764
|
+
secureSessionStorage.setToken(token);
|
|
765
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: Synchronizing with crudify");
|
|
766
|
+
this.syncTokenWithCrudify(token);
|
|
767
|
+
console.log("\u{1F510} TokenManager - SET_TOKEN: Token set and synchronized successfully");
|
|
768
|
+
} catch (error) {
|
|
769
|
+
console.error("\u{1F510} TokenManager - SET_TOKEN: Error setting token:", error);
|
|
770
|
+
this.clearToken();
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Get the current JWT token
|
|
775
|
+
*/
|
|
776
|
+
getToken() {
|
|
777
|
+
console.log("\u{1F510} TokenManager - GET_TOKEN: Entry point - checking cache");
|
|
778
|
+
if (this.tokenCache) {
|
|
779
|
+
console.log("\u{1F510} TokenManager - GET_TOKEN: Cache exists, validating token");
|
|
780
|
+
if (this.isTokenValid(this.tokenCache)) {
|
|
781
|
+
console.log("\u{1F510} TokenManager - GET_TOKEN: Cache valid, returning cached token");
|
|
782
|
+
return this.tokenCache;
|
|
783
|
+
} else {
|
|
784
|
+
console.log("\u{1F510} TokenManager - GET_TOKEN: Cache invalid, clearing cache");
|
|
785
|
+
this.tokenCache = null;
|
|
786
|
+
}
|
|
787
|
+
} else {
|
|
788
|
+
console.log("\u{1F510} TokenManager - GET_TOKEN: No cache, loading from storage");
|
|
789
|
+
}
|
|
790
|
+
console.log("\u{1F510} TokenManager - GET_TOKEN: Loading from storage");
|
|
791
|
+
this.loadTokenFromStorage();
|
|
792
|
+
console.log("\u{1F510} TokenManager - GET_TOKEN: Returning final token:", !!this.tokenCache);
|
|
793
|
+
return this.tokenCache;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Parse the current JWT token
|
|
797
|
+
*/
|
|
798
|
+
parseToken(token) {
|
|
799
|
+
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Entry point - parsing token");
|
|
800
|
+
const targetToken = token !== void 0 ? token : this.tokenCache;
|
|
801
|
+
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Target token exists:", !!targetToken);
|
|
802
|
+
if (!targetToken) {
|
|
803
|
+
console.log("\u{1F510} TokenManager - PARSE_TOKEN: No target token, returning null");
|
|
804
|
+
return null;
|
|
805
|
+
}
|
|
806
|
+
if (this.tokenCache === targetToken && this.parsedTokenCache) {
|
|
807
|
+
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Returning cached parsed token");
|
|
808
|
+
return this.parsedTokenCache;
|
|
809
|
+
}
|
|
810
|
+
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Cache miss, parsing token with decodeJwtSafely");
|
|
811
|
+
const parsed = decodeJwtSafely(targetToken);
|
|
812
|
+
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Token parsed successfully:", !!parsed);
|
|
813
|
+
if (targetToken === this.tokenCache) {
|
|
814
|
+
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Updating parsed token cache");
|
|
815
|
+
this.parsedTokenCache = parsed;
|
|
816
|
+
}
|
|
817
|
+
return parsed;
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Check if a token is valid (properly formatted and not expired)
|
|
821
|
+
*/
|
|
822
|
+
isTokenValid(token) {
|
|
823
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Entry point - checking token validity");
|
|
824
|
+
const targetToken = token !== void 0 ? token : this.tokenCache;
|
|
825
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Target token exists:", !!targetToken);
|
|
826
|
+
if (!targetToken) {
|
|
827
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: No token, returning false");
|
|
828
|
+
return false;
|
|
829
|
+
}
|
|
830
|
+
try {
|
|
831
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Checking if token is expired");
|
|
832
|
+
if (isTokenExpired(targetToken)) {
|
|
833
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token is expired, returning false");
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
836
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token not expired, checking if can be parsed");
|
|
837
|
+
const parsed = decodeJwtSafely(targetToken);
|
|
838
|
+
const isValid = parsed !== null;
|
|
839
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token parsing result:", isValid);
|
|
840
|
+
return isValid;
|
|
841
|
+
} catch (error) {
|
|
842
|
+
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Error validating token:", error);
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Get token expiration time as Date object
|
|
848
|
+
*/
|
|
849
|
+
getTokenExpiration() {
|
|
850
|
+
const token = this.getToken();
|
|
851
|
+
if (!token) return null;
|
|
852
|
+
const parsed = this.parseToken(token);
|
|
853
|
+
if (!parsed?.exp) return null;
|
|
854
|
+
return new Date(parsed.exp * 1e3);
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Clear the current token from all storages and crudify
|
|
858
|
+
*/
|
|
859
|
+
clearToken() {
|
|
860
|
+
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Entry point - clearing all tokens");
|
|
861
|
+
try {
|
|
862
|
+
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing cache");
|
|
863
|
+
this.tokenCache = null;
|
|
864
|
+
this.parsedTokenCache = null;
|
|
865
|
+
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from secure storage");
|
|
866
|
+
secureSessionStorage.removeItem(this.TOKEN_KEY);
|
|
867
|
+
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from crudify");
|
|
868
|
+
import_crudify_browser3.default.setToken("");
|
|
869
|
+
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Token cleared from all storages successfully");
|
|
870
|
+
} catch (error) {
|
|
871
|
+
console.warn("\u{1F510} TokenManager - CLEAR_TOKEN: Error clearing token:", error);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Synchronize token with crudify library
|
|
876
|
+
*/
|
|
877
|
+
syncTokenWithCrudify(token) {
|
|
878
|
+
try {
|
|
879
|
+
import_crudify_browser3.default.setToken(token);
|
|
880
|
+
console.log("\u{1F510} TokenManager - Token synchronized with crudify");
|
|
881
|
+
} catch (error) {
|
|
882
|
+
console.warn("\u{1F510} TokenManager - Failed to sync token with crudify:", error);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Refresh token (placeholder for future implementation)
|
|
887
|
+
*/
|
|
888
|
+
async refreshToken() {
|
|
889
|
+
throw new Error("Token refresh not yet implemented");
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Get user information from the current token
|
|
893
|
+
*/
|
|
894
|
+
getUserInfo() {
|
|
895
|
+
const parsed = this.parseToken();
|
|
896
|
+
if (!parsed) {
|
|
897
|
+
return {
|
|
898
|
+
email: null,
|
|
899
|
+
userId: null,
|
|
900
|
+
userIdentifier: null,
|
|
901
|
+
username: null
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
return {
|
|
905
|
+
email: parsed.email || null,
|
|
906
|
+
userId: parsed.sub || null,
|
|
907
|
+
userIdentifier: parsed["cognito:username"] || parsed.email || parsed.sub || null,
|
|
908
|
+
username: parsed["cognito:username"] || null
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Check if user is currently authenticated
|
|
913
|
+
*/
|
|
914
|
+
isAuthenticated() {
|
|
915
|
+
return this.isTokenValid();
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Get time until token expires in minutes
|
|
919
|
+
*/
|
|
920
|
+
getTimeUntilExpiration() {
|
|
921
|
+
const expiration = this.getTokenExpiration();
|
|
922
|
+
if (!expiration) return null;
|
|
923
|
+
const now = /* @__PURE__ */ new Date();
|
|
924
|
+
const minutesUntilExpiry = Math.floor((expiration.getTime() - now.getTime()) / (60 * 1e3));
|
|
925
|
+
return Math.max(0, minutesUntilExpiry);
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Cleanup resources (call when the component unmounts)
|
|
929
|
+
*/
|
|
930
|
+
cleanup() {
|
|
931
|
+
if (this.expirationCheckInterval) {
|
|
932
|
+
window.clearInterval(this.expirationCheckInterval);
|
|
933
|
+
this.expirationCheckInterval = null;
|
|
934
|
+
}
|
|
935
|
+
if (this.storageEventListener) {
|
|
936
|
+
window.removeEventListener("storage", this.storageEventListener);
|
|
937
|
+
this.storageEventListener = null;
|
|
938
|
+
}
|
|
939
|
+
console.log("\u{1F510} TokenManager - Cleanup completed");
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Get debug information about the current token state
|
|
943
|
+
*/
|
|
944
|
+
getDebugInfo() {
|
|
945
|
+
const token = this.getToken();
|
|
946
|
+
const parsed = this.parseToken();
|
|
947
|
+
const expiration = this.getTokenExpiration();
|
|
948
|
+
return {
|
|
949
|
+
hasToken: !!token,
|
|
950
|
+
tokenLength: token?.length || 0,
|
|
951
|
+
isValid: this.isTokenValid(),
|
|
952
|
+
isAuthenticated: this.isAuthenticated(),
|
|
953
|
+
expiration: expiration?.toISOString() || null,
|
|
954
|
+
minutesUntilExpiry: this.getTimeUntilExpiration(),
|
|
955
|
+
userInfo: this.getUserInfo(),
|
|
956
|
+
parsedTokenKeys: parsed ? Object.keys(parsed) : []
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
_TokenManager.instance = null;
|
|
961
|
+
TokenManager = _TokenManager;
|
|
962
|
+
tokenManager = TokenManager.getInstance();
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
// src/providers/CrudifyDataProvider.tsx
|
|
967
|
+
var CrudifyDataProvider_exports = {};
|
|
968
|
+
__export(CrudifyDataProvider_exports, {
|
|
969
|
+
CrudifyDataProvider: () => CrudifyDataProvider,
|
|
970
|
+
configurationManager: () => configurationManager,
|
|
971
|
+
crudifyInitializer: () => crudifyInitializer,
|
|
972
|
+
tokenManager: () => tokenManager,
|
|
973
|
+
useCrudifyDataContext: () => useCrudifyDataContext
|
|
974
|
+
});
|
|
975
|
+
var import_react5, import_jsx_runtime4, CrudifyDataContext, CrudifyDataProvider, useCrudifyDataContext;
|
|
976
|
+
var init_CrudifyDataProvider = __esm({
|
|
977
|
+
"src/providers/CrudifyDataProvider.tsx"() {
|
|
978
|
+
"use strict";
|
|
979
|
+
import_react5 = require("react");
|
|
980
|
+
init_ConfigurationManager();
|
|
981
|
+
init_CrudifyInitializer();
|
|
982
|
+
init_TokenManager();
|
|
983
|
+
import_jsx_runtime4 = require("react/jsx-runtime");
|
|
984
|
+
CrudifyDataContext = (0, import_react5.createContext)(null);
|
|
985
|
+
CrudifyDataProvider = ({
|
|
986
|
+
children,
|
|
987
|
+
env,
|
|
988
|
+
publicApiKey,
|
|
989
|
+
loginActions,
|
|
990
|
+
appName,
|
|
991
|
+
logo,
|
|
992
|
+
colors
|
|
993
|
+
}) => {
|
|
994
|
+
const [config, setConfig] = (0, import_react5.useState)(null);
|
|
995
|
+
const [isConfigured, setIsConfigured] = (0, import_react5.useState)(false);
|
|
996
|
+
const [configError, setConfigError] = (0, import_react5.useState)(null);
|
|
997
|
+
const [isInitialized, setIsInitialized] = (0, import_react5.useState)(false);
|
|
998
|
+
const [isInitializing, setIsInitializing] = (0, import_react5.useState)(false);
|
|
999
|
+
const [initializationError, setInitializationError] = (0, import_react5.useState)(null);
|
|
1000
|
+
const [isAuthenticated, setIsAuthenticated] = (0, import_react5.useState)(false);
|
|
1001
|
+
const [token, setTokenState] = (0, import_react5.useState)(null);
|
|
1002
|
+
const [user, setUser] = (0, import_react5.useState)(null);
|
|
1003
|
+
const [tokenExpiration, setTokenExpiration] = (0, import_react5.useState)(null);
|
|
1004
|
+
const initializeConfiguration = (0, import_react5.useCallback)(() => {
|
|
1005
|
+
try {
|
|
1006
|
+
console.log("\u{1F30D} CrudifyDataProvider - Initializing configuration");
|
|
1007
|
+
const propsConfig = {
|
|
1008
|
+
env,
|
|
1009
|
+
publicApiKey,
|
|
1010
|
+
loginActions,
|
|
1011
|
+
appName,
|
|
1012
|
+
logo,
|
|
1013
|
+
colors
|
|
1014
|
+
};
|
|
1015
|
+
const resolvedConfig = configurationManager.resolveConfig(propsConfig);
|
|
1016
|
+
const error = configurationManager.getConfigError();
|
|
1017
|
+
setConfig(resolvedConfig);
|
|
1018
|
+
setConfigError(error);
|
|
1019
|
+
setIsConfigured(configurationManager.isConfigured());
|
|
1020
|
+
console.log("\u{1F30D} CrudifyDataProvider - Configuration initialized:", {
|
|
1021
|
+
isConfigured: configurationManager.isConfigured(),
|
|
1022
|
+
error,
|
|
1023
|
+
sources: resolvedConfig.configSource
|
|
1024
|
+
});
|
|
1025
|
+
return resolvedConfig;
|
|
1026
|
+
} catch (error) {
|
|
1027
|
+
const errorMessage = error instanceof Error ? error.message : "Configuration initialization failed";
|
|
1028
|
+
console.error("\u{1F30D} CrudifyDataProvider - Configuration error:", errorMessage);
|
|
1029
|
+
setConfigError(errorMessage);
|
|
1030
|
+
setIsConfigured(false);
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
}, [env, publicApiKey, loginActions, appName, logo, colors]);
|
|
1034
|
+
const initializeCrudify = (0, import_react5.useCallback)(async (resolvedConfig) => {
|
|
1035
|
+
if (!resolvedConfig || !resolvedConfig.publicApiKey) {
|
|
1036
|
+
setInitializationError("Cannot initialize crudify without valid configuration");
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
try {
|
|
1040
|
+
setIsInitializing(true);
|
|
1041
|
+
setInitializationError(null);
|
|
1042
|
+
console.log("\u{1F680} CrudifyDataProvider - Starting crudify initialization");
|
|
1043
|
+
await crudifyInitializer.initialize({
|
|
1044
|
+
env: resolvedConfig.env,
|
|
1045
|
+
publicApiKey: resolvedConfig.publicApiKey,
|
|
1046
|
+
loginActions: resolvedConfig.loginActions,
|
|
1047
|
+
appName: resolvedConfig.appName,
|
|
1048
|
+
logo: resolvedConfig.logo,
|
|
1049
|
+
colors: resolvedConfig.colors
|
|
1050
|
+
});
|
|
1051
|
+
setIsInitialized(true);
|
|
1052
|
+
console.log("\u{1F680} CrudifyDataProvider - Crudify initialization completed");
|
|
1053
|
+
} catch (error) {
|
|
1054
|
+
const errorMessage = error instanceof Error ? error.message : "Crudify initialization failed";
|
|
1055
|
+
console.error("\u{1F680} CrudifyDataProvider - Initialization error:", errorMessage);
|
|
1056
|
+
setInitializationError(errorMessage);
|
|
1057
|
+
setIsInitialized(false);
|
|
1058
|
+
} finally {
|
|
1059
|
+
setIsInitializing(false);
|
|
1060
|
+
}
|
|
1061
|
+
}, []);
|
|
1062
|
+
const updateAuthenticationState = (0, import_react5.useCallback)(() => {
|
|
1063
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Starting authentication state update");
|
|
1064
|
+
try {
|
|
1065
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting token from TokenManager");
|
|
1066
|
+
const currentToken = tokenManager.getToken();
|
|
1067
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token retrieved:", !!currentToken);
|
|
1068
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Parsing token");
|
|
1069
|
+
const parsedUser = tokenManager.parseToken();
|
|
1070
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token parsed:", !!parsedUser);
|
|
1071
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting expiration");
|
|
1072
|
+
const expiration = tokenManager.getTokenExpiration();
|
|
1073
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Expiration retrieved:", !!expiration);
|
|
1074
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Checking authentication");
|
|
1075
|
+
const authenticated = tokenManager.isAuthenticated();
|
|
1076
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication checked:", authenticated);
|
|
1077
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Updating state variables");
|
|
1078
|
+
setTokenState(currentToken);
|
|
1079
|
+
setUser(parsedUser);
|
|
1080
|
+
setTokenExpiration(expiration);
|
|
1081
|
+
setIsAuthenticated(authenticated);
|
|
1082
|
+
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication state updated successfully:", {
|
|
1083
|
+
hasToken: !!currentToken,
|
|
1084
|
+
isAuthenticated: authenticated,
|
|
1085
|
+
userEmail: parsedUser?.email || null,
|
|
1086
|
+
expiration: expiration?.toISOString() || null
|
|
1087
|
+
});
|
|
1088
|
+
} catch (error) {
|
|
1089
|
+
console.error("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Error updating authentication state:", error);
|
|
1090
|
+
}
|
|
1091
|
+
}, []);
|
|
1092
|
+
const setToken = (0, import_react5.useCallback)((newToken) => {
|
|
1093
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: ===== STARTING TOKEN SET =====");
|
|
1094
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: New token:", newToken ? `${newToken.substring(0, 20)}...` : "null");
|
|
1095
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Setting token in TokenManager...");
|
|
1096
|
+
tokenManager.setToken(newToken);
|
|
1097
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Updating state using newToken directly");
|
|
1098
|
+
if (newToken) {
|
|
1099
|
+
const parsedUser = tokenManager.parseToken(newToken);
|
|
1100
|
+
const expiration = tokenManager.getTokenExpiration();
|
|
1101
|
+
const authenticated = tokenManager.isTokenValid(newToken);
|
|
1102
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Setting state values:");
|
|
1103
|
+
console.log(" - setTokenState:", newToken ? `${newToken.substring(0, 20)}...` : "null");
|
|
1104
|
+
console.log(" - setUser:", parsedUser?.email || "null");
|
|
1105
|
+
console.log(" - setIsAuthenticated:", authenticated);
|
|
1106
|
+
setTokenState(newToken);
|
|
1107
|
+
setUser(parsedUser);
|
|
1108
|
+
setTokenExpiration(expiration);
|
|
1109
|
+
setIsAuthenticated(authenticated);
|
|
1110
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: \u2705 Token set, state updated", {
|
|
1111
|
+
hasToken: true,
|
|
1112
|
+
isAuthenticated: authenticated,
|
|
1113
|
+
userEmail: parsedUser?.email || null
|
|
1114
|
+
});
|
|
1115
|
+
} else {
|
|
1116
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Clearing all states");
|
|
1117
|
+
setTokenState(null);
|
|
1118
|
+
setUser(null);
|
|
1119
|
+
setTokenExpiration(null);
|
|
1120
|
+
setIsAuthenticated(false);
|
|
1121
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: \u2705 Token cleared, state reset");
|
|
1122
|
+
}
|
|
1123
|
+
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: ===== TOKEN SET COMPLETE =====");
|
|
1124
|
+
}, []);
|
|
1125
|
+
const logout = (0, import_react5.useCallback)(() => {
|
|
1126
|
+
console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Logging out user");
|
|
1127
|
+
tokenManager.clearToken();
|
|
1128
|
+
console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Updating state directly");
|
|
1129
|
+
setTokenState(null);
|
|
1130
|
+
setUser(null);
|
|
1131
|
+
setTokenExpiration(null);
|
|
1132
|
+
setIsAuthenticated(false);
|
|
1133
|
+
console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: User logged out, state cleared");
|
|
1134
|
+
}, []);
|
|
1135
|
+
const refreshConfig = (0, import_react5.useCallback)(() => {
|
|
1136
|
+
console.log("\u{1F30D} CrudifyDataProvider - Refreshing configuration");
|
|
1137
|
+
configurationManager.clearConfig();
|
|
1138
|
+
const newConfig = initializeConfiguration();
|
|
1139
|
+
if (newConfig && newConfig.publicApiKey) {
|
|
1140
|
+
initializeCrudify(newConfig);
|
|
1141
|
+
}
|
|
1142
|
+
}, [initializeConfiguration, initializeCrudify]);
|
|
1143
|
+
const reinitialize = (0, import_react5.useCallback)(async () => {
|
|
1144
|
+
if (!config || !config.publicApiKey) {
|
|
1145
|
+
console.warn("\u{1F680} CrudifyDataProvider - Cannot reinitialize without valid configuration");
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
console.log("\u{1F680} CrudifyDataProvider - Force reinitializing crudify");
|
|
1149
|
+
crudifyInitializer.reset();
|
|
1150
|
+
await initializeCrudify(config);
|
|
1151
|
+
}, [config, initializeCrudify]);
|
|
1152
|
+
const getDebugInfo = (0, import_react5.useCallback)(() => {
|
|
1153
|
+
return {
|
|
1154
|
+
provider: {
|
|
1155
|
+
isConfigured,
|
|
1156
|
+
configError,
|
|
1157
|
+
isInitialized,
|
|
1158
|
+
isInitializing,
|
|
1159
|
+
initializationError,
|
|
1160
|
+
isAuthenticated
|
|
1161
|
+
},
|
|
1162
|
+
configuration: {
|
|
1163
|
+
config: config ? {
|
|
1164
|
+
env: config.env,
|
|
1165
|
+
publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
|
|
1166
|
+
appName: config.appName,
|
|
1167
|
+
loginActionsCount: config.loginActions.length,
|
|
1168
|
+
hasLogo: !!config.logo,
|
|
1169
|
+
colorsCount: Object.keys(config.colors).length
|
|
1170
|
+
} : null,
|
|
1171
|
+
sources: config?.configSource || null,
|
|
1172
|
+
rawConfig: config?.rawConfig || null
|
|
1173
|
+
},
|
|
1174
|
+
authentication: {
|
|
1175
|
+
hasToken: !!token,
|
|
1176
|
+
tokenLength: token?.length || 0,
|
|
1177
|
+
userEmail: user?.email || null,
|
|
1178
|
+
userId: user?.sub || null,
|
|
1179
|
+
expiration: tokenExpiration?.toISOString() || null,
|
|
1180
|
+
minutesUntilExpiry: tokenManager.getTimeUntilExpiration()
|
|
1181
|
+
},
|
|
1182
|
+
tokenManager: tokenManager.getDebugInfo(),
|
|
1183
|
+
crudifyInitializer: crudifyInitializer.getStatus()
|
|
1184
|
+
};
|
|
1185
|
+
}, [isConfigured, configError, isInitialized, isInitializing, initializationError, isAuthenticated, config, token, user, tokenExpiration]);
|
|
1186
|
+
(0, import_react5.useEffect)(() => {
|
|
1187
|
+
console.log("\u{1F30D} CrudifyDataProvider - Provider mounting, starting initialization");
|
|
1188
|
+
const resolvedConfig = initializeConfiguration();
|
|
1189
|
+
updateAuthenticationState();
|
|
1190
|
+
if (resolvedConfig && resolvedConfig.publicApiKey) {
|
|
1191
|
+
initializeCrudify(resolvedConfig);
|
|
1192
|
+
}
|
|
1193
|
+
return () => {
|
|
1194
|
+
console.log("\u{1F30D} CrudifyDataProvider - Provider unmounting, cleaning up");
|
|
1195
|
+
tokenManager.cleanup();
|
|
1196
|
+
};
|
|
1197
|
+
}, []);
|
|
1198
|
+
(0, import_react5.useEffect)(() => {
|
|
1199
|
+
console.log("\u{1F510} CrudifyDataProvider - INITIAL_AUTH_EFFECT: Loading initial authentication state");
|
|
1200
|
+
updateAuthenticationState();
|
|
1201
|
+
}, []);
|
|
1202
|
+
const contextValue = {
|
|
1203
|
+
// Configuration
|
|
1204
|
+
config,
|
|
1205
|
+
isConfigured,
|
|
1206
|
+
configError,
|
|
1207
|
+
configSource: config ? JSON.stringify(config.configSource) : "none",
|
|
1208
|
+
// Initialization
|
|
1209
|
+
isInitialized,
|
|
1210
|
+
isInitializing,
|
|
1211
|
+
initializationError,
|
|
1212
|
+
// Authentication
|
|
1213
|
+
isAuthenticated,
|
|
1214
|
+
token,
|
|
1215
|
+
user,
|
|
1216
|
+
tokenExpiration,
|
|
1217
|
+
// Actions
|
|
1218
|
+
setToken,
|
|
1219
|
+
logout,
|
|
1220
|
+
refreshConfig,
|
|
1221
|
+
reinitialize,
|
|
1222
|
+
// Debug
|
|
1223
|
+
getDebugInfo
|
|
1224
|
+
};
|
|
1225
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CrudifyDataContext.Provider, { value: contextValue, children });
|
|
1226
|
+
};
|
|
1227
|
+
useCrudifyDataContext = () => {
|
|
1228
|
+
const context = (0, import_react5.useContext)(CrudifyDataContext);
|
|
1229
|
+
if (!context) {
|
|
1230
|
+
throw new Error(
|
|
1231
|
+
"useCrudifyDataContext must be used within a CrudifyDataProvider. Make sure to wrap your app with <CrudifyDataProvider>."
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
return context;
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
|
|
31
1239
|
// src/index.ts
|
|
32
1240
|
var index_exports = {};
|
|
33
1241
|
__export(index_exports, {
|
|
@@ -41,6 +1249,8 @@ __export(index_exports, {
|
|
|
41
1249
|
crudifyInitializer: () => crudifyInitializer,
|
|
42
1250
|
decodeJwtSafely: () => decodeJwtSafely,
|
|
43
1251
|
getCookie: () => getCookie,
|
|
1252
|
+
getCrudifyInstanceAsync: () => getCrudifyInstanceAsync,
|
|
1253
|
+
getCrudifyInstanceSync: () => getCrudifyInstanceSync,
|
|
44
1254
|
getCurrentUserEmail: () => getCurrentUserEmail,
|
|
45
1255
|
getErrorMessage: () => getErrorMessage,
|
|
46
1256
|
handleCrudifyError: () => handleCrudifyError,
|
|
@@ -218,14 +1428,7 @@ var useCrudify = () => {
|
|
|
218
1428
|
|
|
219
1429
|
// src/components/CrudifyLogin/context/LoginStateProvider.tsx
|
|
220
1430
|
var import_react4 = require("react");
|
|
221
|
-
|
|
222
|
-
// src/components/CrudifyLogin/utils/cookies.ts
|
|
223
|
-
var getCookie = (name) => {
|
|
224
|
-
const match = document.cookie.match(new RegExp("(^|;)\\s*" + name + "=([^;]+)"));
|
|
225
|
-
return match ? match[2] : null;
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
// src/components/CrudifyLogin/context/LoginStateProvider.tsx
|
|
1431
|
+
init_cookies();
|
|
229
1432
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
230
1433
|
var initialState = {
|
|
231
1434
|
currentScreen: "login",
|
|
@@ -450,115 +1653,7 @@ var useLoginState = () => {
|
|
|
450
1653
|
// src/components/CrudifyLogin/Forms/LoginForm.tsx
|
|
451
1654
|
var import_react6 = require("react");
|
|
452
1655
|
var import_material = require("@mui/material");
|
|
453
|
-
|
|
454
|
-
// src/components/CrudifyLogin/utils/secureStorage.ts
|
|
455
|
-
var import_crypto_js = __toESM(require("crypto-js"));
|
|
456
|
-
var SecureStorage = class {
|
|
457
|
-
constructor(storageType = "sessionStorage") {
|
|
458
|
-
this.encryptionKey = this.generateEncryptionKey();
|
|
459
|
-
this.storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
|
|
460
|
-
}
|
|
461
|
-
generateEncryptionKey() {
|
|
462
|
-
const browserFingerprint = [
|
|
463
|
-
navigator.userAgent,
|
|
464
|
-
navigator.language,
|
|
465
|
-
(/* @__PURE__ */ new Date()).getTimezoneOffset(),
|
|
466
|
-
screen.colorDepth,
|
|
467
|
-
screen.width,
|
|
468
|
-
screen.height,
|
|
469
|
-
"crudify-login"
|
|
470
|
-
].join("|");
|
|
471
|
-
return import_crypto_js.default.SHA256(browserFingerprint).toString();
|
|
472
|
-
}
|
|
473
|
-
setItem(key, value, expiryMinutes) {
|
|
474
|
-
try {
|
|
475
|
-
const encrypted = import_crypto_js.default.AES.encrypt(value, this.encryptionKey).toString();
|
|
476
|
-
this.storage.setItem(key, encrypted);
|
|
477
|
-
if (expiryMinutes) {
|
|
478
|
-
const expiryTime = (/* @__PURE__ */ new Date()).getTime() + expiryMinutes * 60 * 1e3;
|
|
479
|
-
this.storage.setItem(`${key}_expiry`, expiryTime.toString());
|
|
480
|
-
}
|
|
481
|
-
} catch (error) {
|
|
482
|
-
console.error("Failed to encrypt and store data:", error);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
getItem(key) {
|
|
486
|
-
try {
|
|
487
|
-
const expiryKey = `${key}_expiry`;
|
|
488
|
-
const expiry = this.storage.getItem(expiryKey);
|
|
489
|
-
if (expiry) {
|
|
490
|
-
const expiryTime = parseInt(expiry, 10);
|
|
491
|
-
if ((/* @__PURE__ */ new Date()).getTime() > expiryTime) {
|
|
492
|
-
this.removeItem(key);
|
|
493
|
-
return null;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
const encrypted = this.storage.getItem(key);
|
|
497
|
-
if (!encrypted) return null;
|
|
498
|
-
const decrypted = import_crypto_js.default.AES.decrypt(encrypted, this.encryptionKey);
|
|
499
|
-
const result = decrypted.toString(import_crypto_js.default.enc.Utf8);
|
|
500
|
-
if (!result) {
|
|
501
|
-
console.warn("Failed to decrypt stored data - may be corrupted");
|
|
502
|
-
this.removeItem(key);
|
|
503
|
-
return null;
|
|
504
|
-
}
|
|
505
|
-
return result;
|
|
506
|
-
} catch (error) {
|
|
507
|
-
console.error("Failed to decrypt data:", error);
|
|
508
|
-
this.removeItem(key);
|
|
509
|
-
return null;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
removeItem(key) {
|
|
513
|
-
this.storage.removeItem(key);
|
|
514
|
-
this.storage.removeItem(`${key}_expiry`);
|
|
515
|
-
}
|
|
516
|
-
setToken(token) {
|
|
517
|
-
try {
|
|
518
|
-
const parts = token.split(".");
|
|
519
|
-
if (parts.length === 3) {
|
|
520
|
-
const payload = JSON.parse(atob(parts[1]));
|
|
521
|
-
if (payload.exp) {
|
|
522
|
-
const expiryTime = payload.exp * 1e3;
|
|
523
|
-
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
524
|
-
const minutesUntilExpiry = Math.floor((expiryTime - now) / (60 * 1e3));
|
|
525
|
-
if (minutesUntilExpiry > 0) {
|
|
526
|
-
this.setItem("authToken", token, minutesUntilExpiry);
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
} catch (error) {
|
|
532
|
-
console.warn("Failed to parse token expiry, using default expiry");
|
|
533
|
-
}
|
|
534
|
-
this.setItem("authToken", token, 24 * 60);
|
|
535
|
-
}
|
|
536
|
-
getToken() {
|
|
537
|
-
const token = this.getItem("authToken");
|
|
538
|
-
if (token) {
|
|
539
|
-
try {
|
|
540
|
-
const parts = token.split(".");
|
|
541
|
-
if (parts.length === 3) {
|
|
542
|
-
const payload = JSON.parse(atob(parts[1]));
|
|
543
|
-
if (payload.exp) {
|
|
544
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
545
|
-
if (payload.exp < now) {
|
|
546
|
-
this.removeItem("authToken");
|
|
547
|
-
return null;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
} catch (error) {
|
|
552
|
-
console.warn("Failed to validate token expiry");
|
|
553
|
-
this.removeItem("authToken");
|
|
554
|
-
return null;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
return token;
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
var secureSessionStorage = new SecureStorage("sessionStorage");
|
|
561
|
-
var secureLocalStorage = new SecureStorage("localStorage");
|
|
1656
|
+
init_secureStorage();
|
|
562
1657
|
|
|
563
1658
|
// src/utils/errorHandler.ts
|
|
564
1659
|
var ERROR_CODES = {
|
|
@@ -673,1202 +1768,165 @@ function parseApiError(response) {
|
|
|
673
1768
|
messages.forEach((msg) => {
|
|
674
1769
|
if (typeof msg === "string") {
|
|
675
1770
|
const errorCode = isValidErrorCode(msg) ? msg : ERROR_CODES.BAD_REQUEST;
|
|
676
|
-
errors.push({
|
|
677
|
-
code: errorCode,
|
|
678
|
-
message: getErrorMessage(errorCode),
|
|
679
|
-
severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
} else {
|
|
684
|
-
errors.push({
|
|
685
|
-
code: ERROR_CODES.FIELD_ERROR,
|
|
686
|
-
message: typeof messages[0] === "string" ? messages[0] : "Validation error",
|
|
687
|
-
severity: "warning",
|
|
688
|
-
field
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
if (errors.length === 0 && apiResponse.success === false) {
|
|
696
|
-
errors.push({
|
|
697
|
-
code: ERROR_CODES.BAD_REQUEST,
|
|
698
|
-
message: "Request failed",
|
|
699
|
-
severity: "warning"
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
} catch (error) {
|
|
703
|
-
errors.push({
|
|
704
|
-
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
705
|
-
message: "Failed to parse error response",
|
|
706
|
-
severity: "error",
|
|
707
|
-
details: { originalError: error }
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
return errors.length > 0 ? errors : [
|
|
711
|
-
{
|
|
712
|
-
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
713
|
-
message: "Unknown error occurred",
|
|
714
|
-
severity: "error"
|
|
715
|
-
}
|
|
716
|
-
];
|
|
717
|
-
}
|
|
718
|
-
function parseTransactionError(response) {
|
|
719
|
-
try {
|
|
720
|
-
const transactionResponse = response;
|
|
721
|
-
if (transactionResponse.data && Array.isArray(transactionResponse.data)) {
|
|
722
|
-
const errors = [];
|
|
723
|
-
transactionResponse.data.forEach((item, index) => {
|
|
724
|
-
if (item.response?.status === "TOO_MANY_REQUESTS") {
|
|
725
|
-
errors.push({
|
|
726
|
-
code: ERROR_CODES.TOO_MANY_REQUESTS,
|
|
727
|
-
message: getErrorMessage(ERROR_CODES.TOO_MANY_REQUESTS),
|
|
728
|
-
severity: "warning",
|
|
729
|
-
details: { transactionIndex: index }
|
|
730
|
-
});
|
|
731
|
-
} else if (!item.response || item.response.status !== "OK") {
|
|
732
|
-
errors.push({
|
|
733
|
-
code: ERROR_CODES.BAD_REQUEST,
|
|
734
|
-
message: "Transaction failed",
|
|
735
|
-
severity: "warning",
|
|
736
|
-
details: { transactionIndex: index, response: item.response }
|
|
737
|
-
});
|
|
738
|
-
}
|
|
739
|
-
});
|
|
740
|
-
return errors;
|
|
741
|
-
}
|
|
742
|
-
return parseApiError(response);
|
|
743
|
-
} catch (error) {
|
|
744
|
-
return [
|
|
745
|
-
{
|
|
746
|
-
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
747
|
-
message: "Failed to parse transaction error",
|
|
748
|
-
severity: "error",
|
|
749
|
-
details: { originalError: error }
|
|
750
|
-
}
|
|
751
|
-
];
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
function isValidErrorCode(code) {
|
|
755
|
-
return Object.values(ERROR_CODES).includes(code);
|
|
756
|
-
}
|
|
757
|
-
function getErrorMessage(code) {
|
|
758
|
-
const messages = {
|
|
759
|
-
[ERROR_CODES.INVALID_CREDENTIALS]: "Invalid email or password",
|
|
760
|
-
[ERROR_CODES.UNAUTHORIZED]: "You are not authorized to perform this action",
|
|
761
|
-
[ERROR_CODES.INVALID_API_KEY]: "Invalid API key",
|
|
762
|
-
[ERROR_CODES.USER_NOT_FOUND]: "User not found",
|
|
763
|
-
[ERROR_CODES.USER_NOT_ACTIVE]: "User account is not active",
|
|
764
|
-
[ERROR_CODES.NO_PERMISSION]: "You do not have permission to perform this action",
|
|
765
|
-
[ERROR_CODES.ITEM_NOT_FOUND]: "Item not found",
|
|
766
|
-
[ERROR_CODES.NOT_FOUND]: "Resource not found",
|
|
767
|
-
[ERROR_CODES.IN_USE]: "Resource is currently in use",
|
|
768
|
-
[ERROR_CODES.FIELD_ERROR]: "Validation error",
|
|
769
|
-
[ERROR_CODES.BAD_REQUEST]: "Invalid request",
|
|
770
|
-
[ERROR_CODES.INVALID_EMAIL]: "Please enter a valid email address",
|
|
771
|
-
[ERROR_CODES.INVALID_CODE]: "Invalid or expired code",
|
|
772
|
-
[ERROR_CODES.INTERNAL_SERVER_ERROR]: "Internal server error",
|
|
773
|
-
[ERROR_CODES.DATABASE_CONNECTION_ERROR]: "Database connection error",
|
|
774
|
-
[ERROR_CODES.INVALID_CONFIGURATION]: "Invalid configuration",
|
|
775
|
-
[ERROR_CODES.UNKNOWN_OPERATION]: "Unknown operation",
|
|
776
|
-
[ERROR_CODES.TOO_MANY_REQUESTS]: "Too many requests. Please try again later.",
|
|
777
|
-
[ERROR_CODES.NETWORK_ERROR]: "Network error. Please check your connection.",
|
|
778
|
-
[ERROR_CODES.TIMEOUT_ERROR]: "Request timed out. Please try again."
|
|
779
|
-
};
|
|
780
|
-
return messages[code] || "An unknown error occurred";
|
|
781
|
-
}
|
|
782
|
-
function parseJavaScriptError(error) {
|
|
783
|
-
if (error instanceof Error) {
|
|
784
|
-
if (error.name === "AbortError") {
|
|
785
|
-
return {
|
|
786
|
-
code: ERROR_CODES.TIMEOUT_ERROR,
|
|
787
|
-
message: "Request was cancelled",
|
|
788
|
-
severity: "info"
|
|
789
|
-
};
|
|
790
|
-
}
|
|
791
|
-
if (error.message.includes("NetworkError") || error.message.includes("Failed to fetch")) {
|
|
792
|
-
return {
|
|
793
|
-
code: ERROR_CODES.NETWORK_ERROR,
|
|
794
|
-
message: getErrorMessage(ERROR_CODES.NETWORK_ERROR),
|
|
795
|
-
severity: "error"
|
|
796
|
-
};
|
|
797
|
-
}
|
|
798
|
-
return {
|
|
799
|
-
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
800
|
-
message: error.message || "An unexpected error occurred",
|
|
801
|
-
severity: "error",
|
|
802
|
-
details: { originalError: error }
|
|
803
|
-
};
|
|
804
|
-
}
|
|
805
|
-
return {
|
|
806
|
-
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
807
|
-
message: "An unknown error occurred",
|
|
808
|
-
severity: "error",
|
|
809
|
-
details: { originalError: error }
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
function handleCrudifyError(error) {
|
|
813
|
-
if (error instanceof Error) {
|
|
814
|
-
return [parseJavaScriptError(error)];
|
|
815
|
-
}
|
|
816
|
-
if (typeof error === "object" && error !== null) {
|
|
817
|
-
const response = error;
|
|
818
|
-
if (response.data && Array.isArray(response.data)) {
|
|
819
|
-
return parseTransactionError(error);
|
|
820
|
-
}
|
|
821
|
-
return parseApiError(error);
|
|
822
|
-
}
|
|
823
|
-
return [
|
|
824
|
-
{
|
|
825
|
-
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
826
|
-
message: "An unknown error occurred",
|
|
827
|
-
severity: "error",
|
|
828
|
-
details: { originalError: error }
|
|
829
|
-
}
|
|
830
|
-
];
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// src/providers/CrudifyDataProvider.tsx
|
|
834
|
-
var import_react5 = require("react");
|
|
835
|
-
|
|
836
|
-
// src/core/ConfigurationManager.ts
|
|
837
|
-
var _ConfigurationManager = class _ConfigurationManager {
|
|
838
|
-
constructor() {
|
|
839
|
-
this.resolvedConfig = null;
|
|
840
|
-
this.configError = null;
|
|
841
|
-
}
|
|
842
|
-
/**
|
|
843
|
-
* Singleton pattern to ensure consistent configuration across the app
|
|
844
|
-
*/
|
|
845
|
-
static getInstance() {
|
|
846
|
-
if (!_ConfigurationManager.instance) {
|
|
847
|
-
_ConfigurationManager.instance = new _ConfigurationManager();
|
|
848
|
-
}
|
|
849
|
-
return _ConfigurationManager.instance;
|
|
850
|
-
}
|
|
851
|
-
/**
|
|
852
|
-
* Reset the singleton instance (useful for testing)
|
|
853
|
-
*/
|
|
854
|
-
static resetInstance() {
|
|
855
|
-
_ConfigurationManager.instance = null;
|
|
856
|
-
}
|
|
857
|
-
/**
|
|
858
|
-
* Resolve configuration from all sources with proper priority
|
|
859
|
-
*/
|
|
860
|
-
resolveConfig(propsConfig = {}) {
|
|
861
|
-
if (this.resolvedConfig && this.isConfigStillValid(propsConfig)) {
|
|
862
|
-
return this.resolvedConfig;
|
|
863
|
-
}
|
|
864
|
-
try {
|
|
865
|
-
this.configError = null;
|
|
866
|
-
const envConfig = this.getEnvConfig();
|
|
867
|
-
const cookieConfig = this.getCookieConfig();
|
|
868
|
-
const configSource = {
|
|
869
|
-
env: "default",
|
|
870
|
-
publicApiKey: "default",
|
|
871
|
-
loginActions: "default",
|
|
872
|
-
appName: "default",
|
|
873
|
-
logo: "default",
|
|
874
|
-
colors: "default"
|
|
875
|
-
};
|
|
876
|
-
const env = this.resolveValue("env", propsConfig.env, envConfig.env, cookieConfig.env, "prod", configSource);
|
|
877
|
-
const publicApiKey = this.resolveValue("publicApiKey", propsConfig.publicApiKey, envConfig.publicApiKey, cookieConfig.publicApiKey, void 0, configSource);
|
|
878
|
-
const loginActions = this.resolveValue("loginActions", propsConfig.loginActions, envConfig.loginActions, cookieConfig.loginActions, [], configSource);
|
|
879
|
-
const appName = this.resolveValue("appName", propsConfig.appName, envConfig.appName, cookieConfig.appName, "Crudify App", configSource);
|
|
880
|
-
const logo = this.resolveValue("logo", propsConfig.logo, envConfig.logo, cookieConfig.logo, "", configSource);
|
|
881
|
-
const colors = this.resolveValue("colors", propsConfig.colors, envConfig.colors, cookieConfig.colors, {}, configSource);
|
|
882
|
-
if (!publicApiKey) {
|
|
883
|
-
throw new Error(
|
|
884
|
-
"publicApiKey is required. Provide it via:\n1. Props: <CrudifyDataProvider publicApiKey={...} />\n2. Environment: VITE_TEST_PUBLIC_API_KEY\n3. Cookie: publicApiKey"
|
|
885
|
-
);
|
|
886
|
-
}
|
|
887
|
-
this.resolvedConfig = {
|
|
888
|
-
env,
|
|
889
|
-
publicApiKey,
|
|
890
|
-
loginActions,
|
|
891
|
-
appName,
|
|
892
|
-
logo,
|
|
893
|
-
colors,
|
|
894
|
-
configSource,
|
|
895
|
-
rawConfig: {
|
|
896
|
-
props: propsConfig,
|
|
897
|
-
env: envConfig,
|
|
898
|
-
cookies: cookieConfig
|
|
899
|
-
}
|
|
900
|
-
};
|
|
901
|
-
console.log("\u{1F527} ConfigurationManager - Configuration resolved:", {
|
|
902
|
-
config: {
|
|
903
|
-
env: this.resolvedConfig.env,
|
|
904
|
-
publicApiKey: `${this.resolvedConfig.publicApiKey.substring(0, 8)}...`,
|
|
905
|
-
appName: this.resolvedConfig.appName,
|
|
906
|
-
loginActionsCount: this.resolvedConfig.loginActions.length
|
|
907
|
-
},
|
|
908
|
-
sources: this.resolvedConfig.configSource
|
|
909
|
-
});
|
|
910
|
-
return this.resolvedConfig;
|
|
911
|
-
} catch (error) {
|
|
912
|
-
this.configError = error instanceof Error ? error.message : "Unknown configuration error";
|
|
913
|
-
console.error("\u{1F527} ConfigurationManager - Configuration error:", this.configError);
|
|
914
|
-
this.resolvedConfig = {
|
|
915
|
-
env: "prod",
|
|
916
|
-
publicApiKey: "",
|
|
917
|
-
loginActions: [],
|
|
918
|
-
appName: "Crudify App",
|
|
919
|
-
logo: "",
|
|
920
|
-
colors: {},
|
|
921
|
-
configSource: {
|
|
922
|
-
env: "default",
|
|
923
|
-
publicApiKey: "default",
|
|
924
|
-
loginActions: "default",
|
|
925
|
-
appName: "default",
|
|
926
|
-
logo: "default",
|
|
927
|
-
colors: "default"
|
|
928
|
-
},
|
|
929
|
-
rawConfig: {
|
|
930
|
-
props: propsConfig,
|
|
931
|
-
env: {},
|
|
932
|
-
cookies: {},
|
|
933
|
-
error: this.configError
|
|
934
|
-
}
|
|
935
|
-
};
|
|
936
|
-
return this.resolvedConfig;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
/**
|
|
940
|
-
* Check if current configuration is still valid for the given props
|
|
941
|
-
*/
|
|
942
|
-
isConfigStillValid(propsConfig) {
|
|
943
|
-
if (!this.resolvedConfig) return false;
|
|
944
|
-
const currentProps = this.resolvedConfig.rawConfig.props;
|
|
945
|
-
return JSON.stringify(currentProps) === JSON.stringify(propsConfig);
|
|
946
|
-
}
|
|
947
|
-
/**
|
|
948
|
-
* Resolve a single config value with priority and source tracking
|
|
949
|
-
*/
|
|
950
|
-
resolveValue(key, propsValue, envValue, cookieValue, defaultValue, configSource) {
|
|
951
|
-
if (propsValue !== void 0) {
|
|
952
|
-
configSource[key] = "props";
|
|
953
|
-
return propsValue;
|
|
954
|
-
}
|
|
955
|
-
if (envValue !== void 0) {
|
|
956
|
-
configSource[key] = "env";
|
|
957
|
-
return envValue;
|
|
958
|
-
}
|
|
959
|
-
if (cookieValue !== void 0) {
|
|
960
|
-
configSource[key] = "cookies";
|
|
961
|
-
return cookieValue;
|
|
962
|
-
}
|
|
963
|
-
configSource[key] = "default";
|
|
964
|
-
return defaultValue;
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* Get configuration from environment variables
|
|
968
|
-
*/
|
|
969
|
-
getEnvConfig() {
|
|
970
|
-
const config = {};
|
|
971
|
-
try {
|
|
972
|
-
} catch (error) {
|
|
973
|
-
console.warn("\u{1F527} ConfigurationManager - Environment variables not available:", error);
|
|
974
|
-
}
|
|
975
|
-
return config;
|
|
976
|
-
}
|
|
977
|
-
/**
|
|
978
|
-
* Get configuration from cookies (multi-tenant support)
|
|
979
|
-
*/
|
|
980
|
-
getCookieConfig() {
|
|
981
|
-
const config = {};
|
|
982
|
-
try {
|
|
983
|
-
const env = getCookie("environment");
|
|
984
|
-
if (env && ["dev", "stg", "prod"].includes(env)) {
|
|
985
|
-
config.env = env;
|
|
986
|
-
}
|
|
987
|
-
const publicApiKey = getCookie("publicApiKey");
|
|
988
|
-
if (publicApiKey) {
|
|
989
|
-
config.publicApiKey = publicApiKey;
|
|
990
|
-
}
|
|
991
|
-
const appName = getCookie("appName");
|
|
992
|
-
if (appName) {
|
|
993
|
-
config.appName = appName;
|
|
994
|
-
}
|
|
995
|
-
const loginActions = getCookie("loginActions");
|
|
996
|
-
if (loginActions) {
|
|
997
|
-
config.loginActions = loginActions.split(",").map((action) => action.trim()).filter(Boolean);
|
|
998
|
-
}
|
|
999
|
-
const logo = getCookie("logo");
|
|
1000
|
-
if (logo) {
|
|
1001
|
-
config.logo = logo;
|
|
1002
|
-
}
|
|
1003
|
-
const colors = getCookie("colors");
|
|
1004
|
-
if (colors) {
|
|
1005
|
-
try {
|
|
1006
|
-
config.colors = JSON.parse(colors);
|
|
1007
|
-
} catch (error) {
|
|
1008
|
-
console.warn("\u{1F527} ConfigurationManager - Failed to parse colors from cookie:", error);
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
} catch (error) {
|
|
1012
|
-
console.warn("\u{1F527} ConfigurationManager - Error reading cookies:", error);
|
|
1013
|
-
}
|
|
1014
|
-
return config;
|
|
1015
|
-
}
|
|
1016
|
-
/**
|
|
1017
|
-
* Get the current resolved configuration
|
|
1018
|
-
*/
|
|
1019
|
-
getConfig() {
|
|
1020
|
-
return this.resolvedConfig;
|
|
1021
|
-
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Get any configuration errors
|
|
1024
|
-
*/
|
|
1025
|
-
getConfigError() {
|
|
1026
|
-
return this.configError;
|
|
1027
|
-
}
|
|
1028
|
-
/**
|
|
1029
|
-
* Check if configuration is valid (no errors and has required fields)
|
|
1030
|
-
*/
|
|
1031
|
-
isConfigured() {
|
|
1032
|
-
return this.resolvedConfig !== null && this.configError === null && !!this.resolvedConfig.publicApiKey;
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* Clear the current configuration (useful for testing or reconfiguration)
|
|
1036
|
-
*/
|
|
1037
|
-
clearConfig() {
|
|
1038
|
-
this.resolvedConfig = null;
|
|
1039
|
-
this.configError = null;
|
|
1040
|
-
}
|
|
1041
|
-
};
|
|
1042
|
-
_ConfigurationManager.instance = null;
|
|
1043
|
-
var ConfigurationManager = _ConfigurationManager;
|
|
1044
|
-
var configurationManager = ConfigurationManager.getInstance();
|
|
1045
|
-
|
|
1046
|
-
// src/core/CrudifyInitializer.ts
|
|
1047
|
-
var import_crudify_browser2 = __toESM(require("@nocios/crudify-browser"));
|
|
1048
|
-
var _CrudifyInitializer = class _CrudifyInitializer {
|
|
1049
|
-
constructor() {
|
|
1050
|
-
this.state = {
|
|
1051
|
-
isInitialized: false,
|
|
1052
|
-
isInitializing: false,
|
|
1053
|
-
initializationError: null,
|
|
1054
|
-
config: null,
|
|
1055
|
-
initializationPromise: null
|
|
1056
|
-
};
|
|
1057
|
-
console.log("\u{1F680} CrudifyInitializer - Instance created");
|
|
1058
|
-
}
|
|
1059
|
-
/**
|
|
1060
|
-
* Singleton pattern to ensure global initialization coordination
|
|
1061
|
-
*/
|
|
1062
|
-
static getInstance() {
|
|
1063
|
-
if (!_CrudifyInitializer.instance) {
|
|
1064
|
-
_CrudifyInitializer.instance = new _CrudifyInitializer();
|
|
1065
|
-
}
|
|
1066
|
-
return _CrudifyInitializer.instance;
|
|
1067
|
-
}
|
|
1068
|
-
/**
|
|
1069
|
-
* Reset the singleton instance (useful for testing)
|
|
1070
|
-
*/
|
|
1071
|
-
static resetInstance() {
|
|
1072
|
-
_CrudifyInitializer.instance = null;
|
|
1073
|
-
}
|
|
1074
|
-
/**
|
|
1075
|
-
* Initialize crudify with the given configuration
|
|
1076
|
-
* This method is idempotent and thread-safe
|
|
1077
|
-
*/
|
|
1078
|
-
async initialize(config) {
|
|
1079
|
-
if (this.state.isInitialized && this.isConfigurationSame(config)) {
|
|
1080
|
-
console.log("\u{1F680} CrudifyInitializer - Already initialized with same config");
|
|
1081
|
-
return;
|
|
1082
|
-
}
|
|
1083
|
-
if (this.state.isInitializing && this.state.initializationPromise) {
|
|
1084
|
-
console.log("\u{1F680} CrudifyInitializer - Waiting for ongoing initialization");
|
|
1085
|
-
await this.state.initializationPromise;
|
|
1086
|
-
return;
|
|
1087
|
-
}
|
|
1088
|
-
if (this.state.isInitialized && !this.isConfigurationSame(config)) {
|
|
1089
|
-
console.log("\u{1F680} CrudifyInitializer - Configuration changed, re-initializing");
|
|
1090
|
-
this.reset();
|
|
1091
|
-
}
|
|
1092
|
-
this.state.isInitializing = true;
|
|
1093
|
-
this.state.initializationError = null;
|
|
1094
|
-
this.state.initializationPromise = this.performInitialization(config);
|
|
1095
|
-
try {
|
|
1096
|
-
await this.state.initializationPromise;
|
|
1097
|
-
this.state.isInitialized = true;
|
|
1098
|
-
this.state.config = { ...config };
|
|
1099
|
-
console.log("\u{1F680} CrudifyInitializer - Initialization completed successfully");
|
|
1100
|
-
} catch (error) {
|
|
1101
|
-
this.state.initializationError = error instanceof Error ? error.message : "Unknown initialization error";
|
|
1102
|
-
console.error("\u{1F680} CrudifyInitializer - Initialization failed:", this.state.initializationError);
|
|
1103
|
-
throw error;
|
|
1104
|
-
} finally {
|
|
1105
|
-
this.state.isInitializing = false;
|
|
1106
|
-
this.state.initializationPromise = null;
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
/**
|
|
1110
|
-
* Perform the actual initialization process
|
|
1111
|
-
*/
|
|
1112
|
-
async performInitialization(config) {
|
|
1113
|
-
if (!config.publicApiKey) {
|
|
1114
|
-
throw new Error("publicApiKey is required for crudify initialization");
|
|
1115
|
-
}
|
|
1116
|
-
console.log("\u{1F680} CrudifyInitializer - Starting initialization with config:", {
|
|
1117
|
-
env: config.env,
|
|
1118
|
-
publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
|
|
1119
|
-
appName: config.appName
|
|
1120
|
-
});
|
|
1121
|
-
try {
|
|
1122
|
-
const environment = config.env || "prod";
|
|
1123
|
-
console.log("\u{1F680} CrudifyInitializer - Step 1: Configuring environment:", environment);
|
|
1124
|
-
await import_crudify_browser2.default.config(environment);
|
|
1125
|
-
console.log("\u{1F680} CrudifyInitializer - Step 2: Initializing with API key");
|
|
1126
|
-
await import_crudify_browser2.default.init(config.publicApiKey, "none");
|
|
1127
|
-
console.log("\u{1F680} CrudifyInitializer - Step 3: Verifying initialization");
|
|
1128
|
-
await this.verifyInitialization();
|
|
1129
|
-
console.log("\u{1F680} CrudifyInitializer - All initialization steps completed");
|
|
1130
|
-
} catch (error) {
|
|
1131
|
-
console.error("\u{1F680} CrudifyInitializer - Initialization failed at step:", error);
|
|
1132
|
-
throw new Error(
|
|
1133
|
-
`Crudify initialization failed: ${error instanceof Error ? error.message : "Unknown error"}. Please check your configuration (env: ${config.env || "prod"}, publicApiKey: ${config.publicApiKey ? "provided" : "missing"})`
|
|
1134
|
-
);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
/**
|
|
1138
|
-
* Verify that crudify is properly initialized by checking core methods
|
|
1139
|
-
*/
|
|
1140
|
-
async verifyInitialization() {
|
|
1141
|
-
const requiredMethods = ["readItems", "readItem", "createItem", "updateItem", "deleteItem", "login", "transaction"];
|
|
1142
|
-
const missingMethods = [];
|
|
1143
|
-
for (const method of requiredMethods) {
|
|
1144
|
-
if (typeof import_crudify_browser2.default[method] !== "function") {
|
|
1145
|
-
missingMethods.push(method);
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
if (missingMethods.length > 0) {
|
|
1149
|
-
throw new Error(
|
|
1150
|
-
`Crudify initialization incomplete. Missing methods: ${missingMethods.join(", ")}. This usually indicates a configuration or network issue.`
|
|
1151
|
-
);
|
|
1152
|
-
}
|
|
1153
|
-
console.log("\u{1F680} CrudifyInitializer - Verification successful (test call skipped for performance)");
|
|
1154
|
-
}
|
|
1155
|
-
/**
|
|
1156
|
-
* Check if the given configuration is the same as the current one
|
|
1157
|
-
*/
|
|
1158
|
-
isConfigurationSame(config) {
|
|
1159
|
-
if (!this.state.config) return false;
|
|
1160
|
-
return this.state.config.env === config.env && this.state.config.publicApiKey === config.publicApiKey;
|
|
1161
|
-
}
|
|
1162
|
-
/**
|
|
1163
|
-
* Reset the initialization state (useful for testing or configuration changes)
|
|
1164
|
-
*/
|
|
1165
|
-
reset() {
|
|
1166
|
-
console.log("\u{1F680} CrudifyInitializer - Resetting initialization state");
|
|
1167
|
-
this.state = {
|
|
1168
|
-
isInitialized: false,
|
|
1169
|
-
isInitializing: false,
|
|
1170
|
-
initializationError: null,
|
|
1171
|
-
config: null,
|
|
1172
|
-
initializationPromise: null
|
|
1173
|
-
};
|
|
1174
|
-
}
|
|
1175
|
-
/**
|
|
1176
|
-
* Get the current initialization status
|
|
1177
|
-
*/
|
|
1178
|
-
getStatus() {
|
|
1179
|
-
return {
|
|
1180
|
-
isInitialized: this.state.isInitialized,
|
|
1181
|
-
isInitializing: this.state.isInitializing,
|
|
1182
|
-
initializationError: this.state.initializationError,
|
|
1183
|
-
config: this.state.config
|
|
1184
|
-
};
|
|
1185
|
-
}
|
|
1186
|
-
/**
|
|
1187
|
-
* Check if crudify is ready to use
|
|
1188
|
-
*/
|
|
1189
|
-
isReady() {
|
|
1190
|
-
return this.state.isInitialized && !this.state.initializationError;
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Get the current initialization error, if any
|
|
1194
|
-
*/
|
|
1195
|
-
getError() {
|
|
1196
|
-
return this.state.initializationError;
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Force re-initialization (useful when configuration changes)
|
|
1200
|
-
*/
|
|
1201
|
-
async reinitialize(config) {
|
|
1202
|
-
console.log("\u{1F680} CrudifyInitializer - Forcing re-initialization");
|
|
1203
|
-
this.reset();
|
|
1204
|
-
await this.initialize(config);
|
|
1205
|
-
}
|
|
1206
|
-
/**
|
|
1207
|
-
* Check if initialization is currently in progress
|
|
1208
|
-
*/
|
|
1209
|
-
isInitializing() {
|
|
1210
|
-
return this.state.isInitializing;
|
|
1211
|
-
}
|
|
1212
|
-
/**
|
|
1213
|
-
* Wait for any ongoing initialization to complete
|
|
1214
|
-
*/
|
|
1215
|
-
async waitForInitialization() {
|
|
1216
|
-
if (this.state.initializationPromise) {
|
|
1217
|
-
await this.state.initializationPromise;
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
};
|
|
1221
|
-
_CrudifyInitializer.instance = null;
|
|
1222
|
-
var CrudifyInitializer = _CrudifyInitializer;
|
|
1223
|
-
var crudifyInitializer = CrudifyInitializer.getInstance();
|
|
1224
|
-
|
|
1225
|
-
// src/core/TokenManager.ts
|
|
1226
|
-
var import_crudify_browser3 = __toESM(require("@nocios/crudify-browser"));
|
|
1227
|
-
|
|
1228
|
-
// src/utils/jwtUtils.ts
|
|
1229
|
-
var decodeJwtSafely = (token) => {
|
|
1230
|
-
try {
|
|
1231
|
-
const parts = token.split(".");
|
|
1232
|
-
if (parts.length !== 3) {
|
|
1233
|
-
console.warn("Invalid JWT format: token must have 3 parts");
|
|
1234
|
-
return null;
|
|
1235
|
-
}
|
|
1236
|
-
const payload = parts[1];
|
|
1237
|
-
const paddedPayload = payload + "=".repeat((4 - payload.length % 4) % 4);
|
|
1238
|
-
const decodedPayload = JSON.parse(atob(paddedPayload));
|
|
1239
|
-
return decodedPayload;
|
|
1240
|
-
} catch (error) {
|
|
1241
|
-
console.warn("Failed to decode JWT token:", error);
|
|
1242
|
-
return null;
|
|
1243
|
-
}
|
|
1244
|
-
};
|
|
1245
|
-
var getCurrentUserEmail = () => {
|
|
1246
|
-
try {
|
|
1247
|
-
let token = null;
|
|
1248
|
-
token = sessionStorage.getItem("authToken");
|
|
1249
|
-
console.log("\u{1F50D} getCurrentUserEmail - authToken:", token ? `${token.substring(0, 20)}...` : null);
|
|
1250
|
-
if (!token) {
|
|
1251
|
-
token = sessionStorage.getItem("token");
|
|
1252
|
-
console.log("\u{1F50D} getCurrentUserEmail - token:", token ? `${token.substring(0, 20)}...` : null);
|
|
1253
|
-
}
|
|
1254
|
-
if (!token) {
|
|
1255
|
-
token = localStorage.getItem("authToken") || localStorage.getItem("token");
|
|
1256
|
-
console.log("\u{1F50D} getCurrentUserEmail - localStorage:", token ? `${token.substring(0, 20)}...` : null);
|
|
1257
|
-
}
|
|
1258
|
-
if (!token) {
|
|
1259
|
-
console.warn("\u{1F50D} getCurrentUserEmail - No token found in any storage");
|
|
1260
|
-
return null;
|
|
1261
|
-
}
|
|
1262
|
-
const payload = decodeJwtSafely(token);
|
|
1263
|
-
if (!payload) {
|
|
1264
|
-
console.warn("\u{1F50D} getCurrentUserEmail - Failed to decode token");
|
|
1265
|
-
return null;
|
|
1266
|
-
}
|
|
1267
|
-
const email = payload.email || payload["cognito:username"] || null;
|
|
1268
|
-
console.log("\u{1F50D} getCurrentUserEmail - Extracted email:", email);
|
|
1269
|
-
return email;
|
|
1270
|
-
} catch (error) {
|
|
1271
|
-
console.warn("Failed to get current user email:", error);
|
|
1272
|
-
return null;
|
|
1273
|
-
}
|
|
1274
|
-
};
|
|
1275
|
-
var isTokenExpired = (token) => {
|
|
1276
|
-
try {
|
|
1277
|
-
const payload = decodeJwtSafely(token);
|
|
1278
|
-
if (!payload || !payload.exp) return true;
|
|
1279
|
-
const currentTime = Math.floor(Date.now() / 1e3);
|
|
1280
|
-
return payload.exp < currentTime;
|
|
1281
|
-
} catch {
|
|
1282
|
-
return true;
|
|
1283
|
-
}
|
|
1284
|
-
};
|
|
1285
|
-
|
|
1286
|
-
// src/core/TokenManager.ts
|
|
1287
|
-
var _TokenManager = class _TokenManager {
|
|
1288
|
-
constructor() {
|
|
1289
|
-
this.TOKEN_KEY = "authToken";
|
|
1290
|
-
// Compatible with crudia-ui
|
|
1291
|
-
this.tokenCache = null;
|
|
1292
|
-
this.parsedTokenCache = null;
|
|
1293
|
-
this.expirationCheckInterval = null;
|
|
1294
|
-
this.storageEventListener = null;
|
|
1295
|
-
this.initializeTokenManager();
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* Singleton pattern to ensure consistent token management
|
|
1299
|
-
*/
|
|
1300
|
-
static getInstance() {
|
|
1301
|
-
if (!_TokenManager.instance) {
|
|
1302
|
-
_TokenManager.instance = new _TokenManager();
|
|
1303
|
-
}
|
|
1304
|
-
return _TokenManager.instance;
|
|
1305
|
-
}
|
|
1306
|
-
/**
|
|
1307
|
-
* Reset the singleton instance (useful for testing)
|
|
1308
|
-
*/
|
|
1309
|
-
static resetInstance() {
|
|
1310
|
-
if (_TokenManager.instance) {
|
|
1311
|
-
_TokenManager.instance.cleanup();
|
|
1312
|
-
}
|
|
1313
|
-
_TokenManager.instance = null;
|
|
1314
|
-
}
|
|
1315
|
-
/**
|
|
1316
|
-
* Initialize the token manager with storage synchronization
|
|
1317
|
-
*/
|
|
1318
|
-
initializeTokenManager() {
|
|
1319
|
-
console.log("\u{1F510} TokenManager - Initializing token management");
|
|
1320
|
-
this.migrateFromLocalStorage();
|
|
1321
|
-
this.loadTokenFromStorage();
|
|
1322
|
-
this.setupExpirationCheck();
|
|
1323
|
-
this.setupStorageListener();
|
|
1324
|
-
console.log("\u{1F510} TokenManager - Initialization complete");
|
|
1325
|
-
}
|
|
1326
|
-
/**
|
|
1327
|
-
* Migrate tokens from localStorage to sessionStorage for better security
|
|
1328
|
-
* This ensures compatibility with older implementations
|
|
1329
|
-
*/
|
|
1330
|
-
migrateFromLocalStorage() {
|
|
1331
|
-
try {
|
|
1332
|
-
const legacyKeys = ["authToken", "token", "jwt", "jwtToken"];
|
|
1333
|
-
for (const key of legacyKeys) {
|
|
1334
|
-
const token = localStorage.getItem(key);
|
|
1335
|
-
if (token && !secureSessionStorage.getToken()) {
|
|
1336
|
-
console.log(`\u{1F510} TokenManager - Migrating token from localStorage key: ${key}`);
|
|
1337
|
-
secureSessionStorage.setToken(token);
|
|
1338
|
-
localStorage.removeItem(key);
|
|
1339
|
-
break;
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
} catch (error) {
|
|
1343
|
-
console.warn("\u{1F510} TokenManager - Token migration failed:", error);
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
/**
|
|
1347
|
-
* Load token from storage and synchronize with crudify
|
|
1348
|
-
*/
|
|
1349
|
-
loadTokenFromStorage() {
|
|
1350
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Entry point - loading token from storage");
|
|
1351
|
-
try {
|
|
1352
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure session storage");
|
|
1353
|
-
const storedToken = secureSessionStorage.getToken();
|
|
1354
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists:", !!storedToken);
|
|
1355
|
-
if (storedToken && this.isTokenValid(storedToken)) {
|
|
1356
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token is valid, updating cache");
|
|
1357
|
-
this.tokenCache = storedToken;
|
|
1358
|
-
this.parsedTokenCache = this.parseToken(storedToken);
|
|
1359
|
-
this.syncTokenWithCrudify(storedToken);
|
|
1360
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Token loaded from storage and synchronized");
|
|
1361
|
-
} else if (storedToken) {
|
|
1362
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists but is invalid/expired, clearing");
|
|
1363
|
-
this.clearToken();
|
|
1364
|
-
} else {
|
|
1365
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: No stored token found");
|
|
1366
|
-
}
|
|
1367
|
-
} catch (error) {
|
|
1368
|
-
console.warn("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Error loading token from storage:", error);
|
|
1369
|
-
this.clearToken();
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
/**
|
|
1373
|
-
* Set up automatic token expiration checking
|
|
1374
|
-
*/
|
|
1375
|
-
setupExpirationCheck() {
|
|
1376
|
-
this.expirationCheckInterval = window.setInterval(() => {
|
|
1377
|
-
if (this.tokenCache && !this.isTokenValid(this.tokenCache)) {
|
|
1378
|
-
console.log("\u{1F510} TokenManager - Token expired, clearing automatically");
|
|
1379
|
-
this.clearToken();
|
|
1380
|
-
}
|
|
1381
|
-
}, 3e4);
|
|
1382
|
-
}
|
|
1383
|
-
/**
|
|
1384
|
-
* Set up storage event listener for cross-tab synchronization
|
|
1385
|
-
*/
|
|
1386
|
-
setupStorageListener() {
|
|
1387
|
-
this.storageEventListener = (event) => {
|
|
1388
|
-
if (event.key === this.TOKEN_KEY) {
|
|
1389
|
-
console.log("\u{1F510} TokenManager - Token change detected from another tab");
|
|
1390
|
-
this.loadTokenFromStorage();
|
|
1391
|
-
}
|
|
1392
|
-
};
|
|
1393
|
-
window.addEventListener("storage", this.storageEventListener);
|
|
1394
|
-
}
|
|
1395
|
-
/**
|
|
1396
|
-
* Set a new JWT token with automatic synchronization
|
|
1397
|
-
*/
|
|
1398
|
-
setToken(token) {
|
|
1399
|
-
console.log("\u{1F510} TokenManager - SET_TOKEN: Entry point - setting token:", token ? "provided" : "null");
|
|
1400
|
-
try {
|
|
1401
|
-
if (!token) {
|
|
1402
|
-
console.log("\u{1F510} TokenManager - SET_TOKEN: No token provided, clearing token");
|
|
1403
|
-
this.clearToken();
|
|
1404
|
-
return;
|
|
1405
|
-
}
|
|
1406
|
-
console.log("\u{1F510} TokenManager - SET_TOKEN: Validating token before setting");
|
|
1407
|
-
if (!this.isTokenValid(token)) {
|
|
1408
|
-
console.warn("\u{1F510} TokenManager - SET_TOKEN: Attempted to set invalid or expired token");
|
|
1409
|
-
this.clearToken();
|
|
1410
|
-
return;
|
|
1771
|
+
errors.push({
|
|
1772
|
+
code: errorCode,
|
|
1773
|
+
message: getErrorMessage(errorCode),
|
|
1774
|
+
severity: ERROR_SEVERITY_MAP[errorCode] || "warning"
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
});
|
|
1778
|
+
} else {
|
|
1779
|
+
errors.push({
|
|
1780
|
+
code: ERROR_CODES.FIELD_ERROR,
|
|
1781
|
+
message: typeof messages[0] === "string" ? messages[0] : "Validation error",
|
|
1782
|
+
severity: "warning",
|
|
1783
|
+
field
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
});
|
|
1411
1788
|
}
|
|
1412
|
-
console.log("\u{1F510} TokenManager - SET_TOKEN: Token is valid, updating cache");
|
|
1413
|
-
this.tokenCache = token;
|
|
1414
|
-
this.parsedTokenCache = this.parseToken(token);
|
|
1415
|
-
console.log("\u{1F510} TokenManager - SET_TOKEN: Storing token in secure storage");
|
|
1416
|
-
secureSessionStorage.setToken(token);
|
|
1417
|
-
console.log("\u{1F510} TokenManager - SET_TOKEN: Synchronizing with crudify");
|
|
1418
|
-
this.syncTokenWithCrudify(token);
|
|
1419
|
-
console.log("\u{1F510} TokenManager - SET_TOKEN: Token set and synchronized successfully");
|
|
1420
|
-
} catch (error) {
|
|
1421
|
-
console.error("\u{1F510} TokenManager - SET_TOKEN: Error setting token:", error);
|
|
1422
|
-
this.clearToken();
|
|
1423
1789
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
if (this.tokenCache) {
|
|
1431
|
-
console.log("\u{1F510} TokenManager - GET_TOKEN: Cache exists, validating token");
|
|
1432
|
-
if (this.isTokenValid(this.tokenCache)) {
|
|
1433
|
-
console.log("\u{1F510} TokenManager - GET_TOKEN: Cache valid, returning cached token");
|
|
1434
|
-
return this.tokenCache;
|
|
1435
|
-
} else {
|
|
1436
|
-
console.log("\u{1F510} TokenManager - GET_TOKEN: Cache invalid, clearing cache");
|
|
1437
|
-
this.tokenCache = null;
|
|
1438
|
-
}
|
|
1439
|
-
} else {
|
|
1440
|
-
console.log("\u{1F510} TokenManager - GET_TOKEN: No cache, loading from storage");
|
|
1790
|
+
if (errors.length === 0 && apiResponse.success === false) {
|
|
1791
|
+
errors.push({
|
|
1792
|
+
code: ERROR_CODES.BAD_REQUEST,
|
|
1793
|
+
message: "Request failed",
|
|
1794
|
+
severity: "warning"
|
|
1795
|
+
});
|
|
1441
1796
|
}
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
*/
|
|
1450
|
-
parseToken(token) {
|
|
1451
|
-
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Entry point - parsing token");
|
|
1452
|
-
const targetToken = token !== void 0 ? token : this.tokenCache;
|
|
1453
|
-
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Target token exists:", !!targetToken);
|
|
1454
|
-
if (!targetToken) {
|
|
1455
|
-
console.log("\u{1F510} TokenManager - PARSE_TOKEN: No target token, returning null");
|
|
1456
|
-
return null;
|
|
1457
|
-
}
|
|
1458
|
-
if (this.tokenCache === targetToken && this.parsedTokenCache) {
|
|
1459
|
-
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Returning cached parsed token");
|
|
1460
|
-
return this.parsedTokenCache;
|
|
1461
|
-
}
|
|
1462
|
-
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Cache miss, parsing token with decodeJwtSafely");
|
|
1463
|
-
const parsed = decodeJwtSafely(targetToken);
|
|
1464
|
-
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Token parsed successfully:", !!parsed);
|
|
1465
|
-
if (targetToken === this.tokenCache) {
|
|
1466
|
-
console.log("\u{1F510} TokenManager - PARSE_TOKEN: Updating parsed token cache");
|
|
1467
|
-
this.parsedTokenCache = parsed;
|
|
1468
|
-
}
|
|
1469
|
-
return parsed;
|
|
1797
|
+
} catch (error) {
|
|
1798
|
+
errors.push({
|
|
1799
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
1800
|
+
message: "Failed to parse error response",
|
|
1801
|
+
severity: "error",
|
|
1802
|
+
details: { originalError: error }
|
|
1803
|
+
});
|
|
1470
1804
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
const targetToken = token !== void 0 ? token : this.tokenCache;
|
|
1477
|
-
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Target token exists:", !!targetToken);
|
|
1478
|
-
if (!targetToken) {
|
|
1479
|
-
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: No token, returning false");
|
|
1480
|
-
return false;
|
|
1481
|
-
}
|
|
1482
|
-
try {
|
|
1483
|
-
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Checking if token is expired");
|
|
1484
|
-
if (isTokenExpired(targetToken)) {
|
|
1485
|
-
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token is expired, returning false");
|
|
1486
|
-
return false;
|
|
1487
|
-
}
|
|
1488
|
-
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token not expired, checking if can be parsed");
|
|
1489
|
-
const parsed = decodeJwtSafely(targetToken);
|
|
1490
|
-
const isValid = parsed !== null;
|
|
1491
|
-
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Token parsing result:", isValid);
|
|
1492
|
-
return isValid;
|
|
1493
|
-
} catch (error) {
|
|
1494
|
-
console.log("\u{1F510} TokenManager - IS_TOKEN_VALID: Error validating token:", error);
|
|
1495
|
-
return false;
|
|
1805
|
+
return errors.length > 0 ? errors : [
|
|
1806
|
+
{
|
|
1807
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
1808
|
+
message: "Unknown error occurred",
|
|
1809
|
+
severity: "error"
|
|
1496
1810
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
} catch (error) {
|
|
1523
|
-
console.warn("\u{1F510} TokenManager - CLEAR_TOKEN: Error clearing token:", error);
|
|
1811
|
+
];
|
|
1812
|
+
}
|
|
1813
|
+
function parseTransactionError(response) {
|
|
1814
|
+
try {
|
|
1815
|
+
const transactionResponse = response;
|
|
1816
|
+
if (transactionResponse.data && Array.isArray(transactionResponse.data)) {
|
|
1817
|
+
const errors = [];
|
|
1818
|
+
transactionResponse.data.forEach((item, index) => {
|
|
1819
|
+
if (item.response?.status === "TOO_MANY_REQUESTS") {
|
|
1820
|
+
errors.push({
|
|
1821
|
+
code: ERROR_CODES.TOO_MANY_REQUESTS,
|
|
1822
|
+
message: getErrorMessage(ERROR_CODES.TOO_MANY_REQUESTS),
|
|
1823
|
+
severity: "warning",
|
|
1824
|
+
details: { transactionIndex: index }
|
|
1825
|
+
});
|
|
1826
|
+
} else if (!item.response || item.response.status !== "OK") {
|
|
1827
|
+
errors.push({
|
|
1828
|
+
code: ERROR_CODES.BAD_REQUEST,
|
|
1829
|
+
message: "Transaction failed",
|
|
1830
|
+
severity: "warning",
|
|
1831
|
+
details: { transactionIndex: index, response: item.response }
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
});
|
|
1835
|
+
return errors;
|
|
1524
1836
|
}
|
|
1837
|
+
return parseApiError(response);
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
return [
|
|
1840
|
+
{
|
|
1841
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
1842
|
+
message: "Failed to parse transaction error",
|
|
1843
|
+
severity: "error",
|
|
1844
|
+
details: { originalError: error }
|
|
1845
|
+
}
|
|
1846
|
+
];
|
|
1525
1847
|
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1848
|
+
}
|
|
1849
|
+
function isValidErrorCode(code) {
|
|
1850
|
+
return Object.values(ERROR_CODES).includes(code);
|
|
1851
|
+
}
|
|
1852
|
+
function getErrorMessage(code) {
|
|
1853
|
+
const messages = {
|
|
1854
|
+
[ERROR_CODES.INVALID_CREDENTIALS]: "Invalid email or password",
|
|
1855
|
+
[ERROR_CODES.UNAUTHORIZED]: "You are not authorized to perform this action",
|
|
1856
|
+
[ERROR_CODES.INVALID_API_KEY]: "Invalid API key",
|
|
1857
|
+
[ERROR_CODES.USER_NOT_FOUND]: "User not found",
|
|
1858
|
+
[ERROR_CODES.USER_NOT_ACTIVE]: "User account is not active",
|
|
1859
|
+
[ERROR_CODES.NO_PERMISSION]: "You do not have permission to perform this action",
|
|
1860
|
+
[ERROR_CODES.ITEM_NOT_FOUND]: "Item not found",
|
|
1861
|
+
[ERROR_CODES.NOT_FOUND]: "Resource not found",
|
|
1862
|
+
[ERROR_CODES.IN_USE]: "Resource is currently in use",
|
|
1863
|
+
[ERROR_CODES.FIELD_ERROR]: "Validation error",
|
|
1864
|
+
[ERROR_CODES.BAD_REQUEST]: "Invalid request",
|
|
1865
|
+
[ERROR_CODES.INVALID_EMAIL]: "Please enter a valid email address",
|
|
1866
|
+
[ERROR_CODES.INVALID_CODE]: "Invalid or expired code",
|
|
1867
|
+
[ERROR_CODES.INTERNAL_SERVER_ERROR]: "Internal server error",
|
|
1868
|
+
[ERROR_CODES.DATABASE_CONNECTION_ERROR]: "Database connection error",
|
|
1869
|
+
[ERROR_CODES.INVALID_CONFIGURATION]: "Invalid configuration",
|
|
1870
|
+
[ERROR_CODES.UNKNOWN_OPERATION]: "Unknown operation",
|
|
1871
|
+
[ERROR_CODES.TOO_MANY_REQUESTS]: "Too many requests. Please try again later.",
|
|
1872
|
+
[ERROR_CODES.NETWORK_ERROR]: "Network error. Please check your connection.",
|
|
1873
|
+
[ERROR_CODES.TIMEOUT_ERROR]: "Request timed out. Please try again."
|
|
1874
|
+
};
|
|
1875
|
+
return messages[code] || "An unknown error occurred";
|
|
1876
|
+
}
|
|
1877
|
+
function parseJavaScriptError(error) {
|
|
1878
|
+
if (error instanceof Error) {
|
|
1879
|
+
if (error.name === "AbortError") {
|
|
1880
|
+
return {
|
|
1881
|
+
code: ERROR_CODES.TIMEOUT_ERROR,
|
|
1882
|
+
message: "Request was cancelled",
|
|
1883
|
+
severity: "info"
|
|
1884
|
+
};
|
|
1535
1885
|
}
|
|
1536
|
-
|
|
1537
|
-
/**
|
|
1538
|
-
* Refresh token (placeholder for future implementation)
|
|
1539
|
-
*/
|
|
1540
|
-
async refreshToken() {
|
|
1541
|
-
throw new Error("Token refresh not yet implemented");
|
|
1542
|
-
}
|
|
1543
|
-
/**
|
|
1544
|
-
* Get user information from the current token
|
|
1545
|
-
*/
|
|
1546
|
-
getUserInfo() {
|
|
1547
|
-
const parsed = this.parseToken();
|
|
1548
|
-
if (!parsed) {
|
|
1886
|
+
if (error.message.includes("NetworkError") || error.message.includes("Failed to fetch")) {
|
|
1549
1887
|
return {
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
username: null
|
|
1888
|
+
code: ERROR_CODES.NETWORK_ERROR,
|
|
1889
|
+
message: getErrorMessage(ERROR_CODES.NETWORK_ERROR),
|
|
1890
|
+
severity: "error"
|
|
1554
1891
|
};
|
|
1555
1892
|
}
|
|
1556
1893
|
return {
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1894
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
1895
|
+
message: error.message || "An unexpected error occurred",
|
|
1896
|
+
severity: "error",
|
|
1897
|
+
details: { originalError: error }
|
|
1561
1898
|
};
|
|
1562
1899
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
const expiration = this.getTokenExpiration();
|
|
1574
|
-
if (!expiration) return null;
|
|
1575
|
-
const now = /* @__PURE__ */ new Date();
|
|
1576
|
-
const minutesUntilExpiry = Math.floor((expiration.getTime() - now.getTime()) / (60 * 1e3));
|
|
1577
|
-
return Math.max(0, minutesUntilExpiry);
|
|
1578
|
-
}
|
|
1579
|
-
/**
|
|
1580
|
-
* Cleanup resources (call when the component unmounts)
|
|
1581
|
-
*/
|
|
1582
|
-
cleanup() {
|
|
1583
|
-
if (this.expirationCheckInterval) {
|
|
1584
|
-
window.clearInterval(this.expirationCheckInterval);
|
|
1585
|
-
this.expirationCheckInterval = null;
|
|
1586
|
-
}
|
|
1587
|
-
if (this.storageEventListener) {
|
|
1588
|
-
window.removeEventListener("storage", this.storageEventListener);
|
|
1589
|
-
this.storageEventListener = null;
|
|
1590
|
-
}
|
|
1591
|
-
console.log("\u{1F510} TokenManager - Cleanup completed");
|
|
1592
|
-
}
|
|
1593
|
-
/**
|
|
1594
|
-
* Get debug information about the current token state
|
|
1595
|
-
*/
|
|
1596
|
-
getDebugInfo() {
|
|
1597
|
-
const token = this.getToken();
|
|
1598
|
-
const parsed = this.parseToken();
|
|
1599
|
-
const expiration = this.getTokenExpiration();
|
|
1600
|
-
return {
|
|
1601
|
-
hasToken: !!token,
|
|
1602
|
-
tokenLength: token?.length || 0,
|
|
1603
|
-
isValid: this.isTokenValid(),
|
|
1604
|
-
isAuthenticated: this.isAuthenticated(),
|
|
1605
|
-
expiration: expiration?.toISOString() || null,
|
|
1606
|
-
minutesUntilExpiry: this.getTimeUntilExpiration(),
|
|
1607
|
-
userInfo: this.getUserInfo(),
|
|
1608
|
-
parsedTokenKeys: parsed ? Object.keys(parsed) : []
|
|
1609
|
-
};
|
|
1900
|
+
return {
|
|
1901
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
1902
|
+
message: "An unknown error occurred",
|
|
1903
|
+
severity: "error",
|
|
1904
|
+
details: { originalError: error }
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
function handleCrudifyError(error) {
|
|
1908
|
+
if (error instanceof Error) {
|
|
1909
|
+
return [parseJavaScriptError(error)];
|
|
1610
1910
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
// src/providers/CrudifyDataProvider.tsx
|
|
1617
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1618
|
-
var CrudifyDataContext = (0, import_react5.createContext)(null);
|
|
1619
|
-
var CrudifyDataProvider = ({
|
|
1620
|
-
children,
|
|
1621
|
-
env,
|
|
1622
|
-
publicApiKey,
|
|
1623
|
-
loginActions,
|
|
1624
|
-
appName,
|
|
1625
|
-
logo,
|
|
1626
|
-
colors
|
|
1627
|
-
}) => {
|
|
1628
|
-
const [config, setConfig] = (0, import_react5.useState)(null);
|
|
1629
|
-
const [isConfigured, setIsConfigured] = (0, import_react5.useState)(false);
|
|
1630
|
-
const [configError, setConfigError] = (0, import_react5.useState)(null);
|
|
1631
|
-
const [isInitialized, setIsInitialized] = (0, import_react5.useState)(false);
|
|
1632
|
-
const [isInitializing, setIsInitializing] = (0, import_react5.useState)(false);
|
|
1633
|
-
const [initializationError, setInitializationError] = (0, import_react5.useState)(null);
|
|
1634
|
-
const [isAuthenticated, setIsAuthenticated] = (0, import_react5.useState)(false);
|
|
1635
|
-
const [token, setTokenState] = (0, import_react5.useState)(null);
|
|
1636
|
-
const [user, setUser] = (0, import_react5.useState)(null);
|
|
1637
|
-
const [tokenExpiration, setTokenExpiration] = (0, import_react5.useState)(null);
|
|
1638
|
-
const initializeConfiguration = (0, import_react5.useCallback)(() => {
|
|
1639
|
-
try {
|
|
1640
|
-
console.log("\u{1F30D} CrudifyDataProvider - Initializing configuration");
|
|
1641
|
-
const propsConfig = {
|
|
1642
|
-
env,
|
|
1643
|
-
publicApiKey,
|
|
1644
|
-
loginActions,
|
|
1645
|
-
appName,
|
|
1646
|
-
logo,
|
|
1647
|
-
colors
|
|
1648
|
-
};
|
|
1649
|
-
const resolvedConfig = configurationManager.resolveConfig(propsConfig);
|
|
1650
|
-
const error = configurationManager.getConfigError();
|
|
1651
|
-
setConfig(resolvedConfig);
|
|
1652
|
-
setConfigError(error);
|
|
1653
|
-
setIsConfigured(configurationManager.isConfigured());
|
|
1654
|
-
console.log("\u{1F30D} CrudifyDataProvider - Configuration initialized:", {
|
|
1655
|
-
isConfigured: configurationManager.isConfigured(),
|
|
1656
|
-
error,
|
|
1657
|
-
sources: resolvedConfig.configSource
|
|
1658
|
-
});
|
|
1659
|
-
return resolvedConfig;
|
|
1660
|
-
} catch (error) {
|
|
1661
|
-
const errorMessage = error instanceof Error ? error.message : "Configuration initialization failed";
|
|
1662
|
-
console.error("\u{1F30D} CrudifyDataProvider - Configuration error:", errorMessage);
|
|
1663
|
-
setConfigError(errorMessage);
|
|
1664
|
-
setIsConfigured(false);
|
|
1665
|
-
return null;
|
|
1666
|
-
}
|
|
1667
|
-
}, [env, publicApiKey, loginActions, appName, logo, colors]);
|
|
1668
|
-
const initializeCrudify = (0, import_react5.useCallback)(async (resolvedConfig) => {
|
|
1669
|
-
if (!resolvedConfig || !resolvedConfig.publicApiKey) {
|
|
1670
|
-
setInitializationError("Cannot initialize crudify without valid configuration");
|
|
1671
|
-
return;
|
|
1672
|
-
}
|
|
1673
|
-
try {
|
|
1674
|
-
setIsInitializing(true);
|
|
1675
|
-
setInitializationError(null);
|
|
1676
|
-
console.log("\u{1F680} CrudifyDataProvider - Starting crudify initialization");
|
|
1677
|
-
await crudifyInitializer.initialize({
|
|
1678
|
-
env: resolvedConfig.env,
|
|
1679
|
-
publicApiKey: resolvedConfig.publicApiKey,
|
|
1680
|
-
loginActions: resolvedConfig.loginActions,
|
|
1681
|
-
appName: resolvedConfig.appName,
|
|
1682
|
-
logo: resolvedConfig.logo,
|
|
1683
|
-
colors: resolvedConfig.colors
|
|
1684
|
-
});
|
|
1685
|
-
setIsInitialized(true);
|
|
1686
|
-
console.log("\u{1F680} CrudifyDataProvider - Crudify initialization completed");
|
|
1687
|
-
} catch (error) {
|
|
1688
|
-
const errorMessage = error instanceof Error ? error.message : "Crudify initialization failed";
|
|
1689
|
-
console.error("\u{1F680} CrudifyDataProvider - Initialization error:", errorMessage);
|
|
1690
|
-
setInitializationError(errorMessage);
|
|
1691
|
-
setIsInitialized(false);
|
|
1692
|
-
} finally {
|
|
1693
|
-
setIsInitializing(false);
|
|
1694
|
-
}
|
|
1695
|
-
}, []);
|
|
1696
|
-
const updateAuthenticationState = (0, import_react5.useCallback)(() => {
|
|
1697
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Starting authentication state update");
|
|
1698
|
-
try {
|
|
1699
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting token from TokenManager");
|
|
1700
|
-
const currentToken = tokenManager.getToken();
|
|
1701
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token retrieved:", !!currentToken);
|
|
1702
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Parsing token");
|
|
1703
|
-
const parsedUser = tokenManager.parseToken();
|
|
1704
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Token parsed:", !!parsedUser);
|
|
1705
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Getting expiration");
|
|
1706
|
-
const expiration = tokenManager.getTokenExpiration();
|
|
1707
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Expiration retrieved:", !!expiration);
|
|
1708
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Checking authentication");
|
|
1709
|
-
const authenticated = tokenManager.isAuthenticated();
|
|
1710
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication checked:", authenticated);
|
|
1711
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Updating state variables");
|
|
1712
|
-
setTokenState(currentToken);
|
|
1713
|
-
setUser(parsedUser);
|
|
1714
|
-
setTokenExpiration(expiration);
|
|
1715
|
-
setIsAuthenticated(authenticated);
|
|
1716
|
-
console.log("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Authentication state updated successfully:", {
|
|
1717
|
-
hasToken: !!currentToken,
|
|
1718
|
-
isAuthenticated: authenticated,
|
|
1719
|
-
userEmail: parsedUser?.email || null,
|
|
1720
|
-
expiration: expiration?.toISOString() || null
|
|
1721
|
-
});
|
|
1722
|
-
} catch (error) {
|
|
1723
|
-
console.error("\u{1F510} CrudifyDataProvider - UPDATE_AUTH_STATE: Error updating authentication state:", error);
|
|
1724
|
-
}
|
|
1725
|
-
}, []);
|
|
1726
|
-
const setToken = (0, import_react5.useCallback)((newToken) => {
|
|
1727
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: ===== STARTING TOKEN SET =====");
|
|
1728
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: New token:", newToken ? `${newToken.substring(0, 20)}...` : "null");
|
|
1729
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Setting token in TokenManager...");
|
|
1730
|
-
tokenManager.setToken(newToken);
|
|
1731
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Updating state using newToken directly");
|
|
1732
|
-
if (newToken) {
|
|
1733
|
-
const parsedUser = tokenManager.parseToken(newToken);
|
|
1734
|
-
const expiration = tokenManager.getTokenExpiration();
|
|
1735
|
-
const authenticated = tokenManager.isTokenValid(newToken);
|
|
1736
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Setting state values:");
|
|
1737
|
-
console.log(" - setTokenState:", newToken ? `${newToken.substring(0, 20)}...` : "null");
|
|
1738
|
-
console.log(" - setUser:", parsedUser?.email || "null");
|
|
1739
|
-
console.log(" - setIsAuthenticated:", authenticated);
|
|
1740
|
-
setTokenState(newToken);
|
|
1741
|
-
setUser(parsedUser);
|
|
1742
|
-
setTokenExpiration(expiration);
|
|
1743
|
-
setIsAuthenticated(authenticated);
|
|
1744
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: \u2705 Token set, state updated", {
|
|
1745
|
-
hasToken: true,
|
|
1746
|
-
isAuthenticated: authenticated,
|
|
1747
|
-
userEmail: parsedUser?.email || null
|
|
1748
|
-
});
|
|
1749
|
-
} else {
|
|
1750
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: Clearing all states");
|
|
1751
|
-
setTokenState(null);
|
|
1752
|
-
setUser(null);
|
|
1753
|
-
setTokenExpiration(null);
|
|
1754
|
-
setIsAuthenticated(false);
|
|
1755
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: \u2705 Token cleared, state reset");
|
|
1756
|
-
}
|
|
1757
|
-
console.log("\u{1F510} CrudifyDataProvider - SET_TOKEN_CALLBACK: ===== TOKEN SET COMPLETE =====");
|
|
1758
|
-
}, []);
|
|
1759
|
-
const logout = (0, import_react5.useCallback)(() => {
|
|
1760
|
-
console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Logging out user");
|
|
1761
|
-
tokenManager.clearToken();
|
|
1762
|
-
console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: Updating state directly");
|
|
1763
|
-
setTokenState(null);
|
|
1764
|
-
setUser(null);
|
|
1765
|
-
setTokenExpiration(null);
|
|
1766
|
-
setIsAuthenticated(false);
|
|
1767
|
-
console.log("\u{1F510} CrudifyDataProvider - LOGOUT_CALLBACK: User logged out, state cleared");
|
|
1768
|
-
}, []);
|
|
1769
|
-
const refreshConfig = (0, import_react5.useCallback)(() => {
|
|
1770
|
-
console.log("\u{1F30D} CrudifyDataProvider - Refreshing configuration");
|
|
1771
|
-
configurationManager.clearConfig();
|
|
1772
|
-
const newConfig = initializeConfiguration();
|
|
1773
|
-
if (newConfig && newConfig.publicApiKey) {
|
|
1774
|
-
initializeCrudify(newConfig);
|
|
1775
|
-
}
|
|
1776
|
-
}, [initializeConfiguration, initializeCrudify]);
|
|
1777
|
-
const reinitialize = (0, import_react5.useCallback)(async () => {
|
|
1778
|
-
if (!config || !config.publicApiKey) {
|
|
1779
|
-
console.warn("\u{1F680} CrudifyDataProvider - Cannot reinitialize without valid configuration");
|
|
1780
|
-
return;
|
|
1781
|
-
}
|
|
1782
|
-
console.log("\u{1F680} CrudifyDataProvider - Force reinitializing crudify");
|
|
1783
|
-
crudifyInitializer.reset();
|
|
1784
|
-
await initializeCrudify(config);
|
|
1785
|
-
}, [config, initializeCrudify]);
|
|
1786
|
-
const getDebugInfo = (0, import_react5.useCallback)(() => {
|
|
1787
|
-
return {
|
|
1788
|
-
provider: {
|
|
1789
|
-
isConfigured,
|
|
1790
|
-
configError,
|
|
1791
|
-
isInitialized,
|
|
1792
|
-
isInitializing,
|
|
1793
|
-
initializationError,
|
|
1794
|
-
isAuthenticated
|
|
1795
|
-
},
|
|
1796
|
-
configuration: {
|
|
1797
|
-
config: config ? {
|
|
1798
|
-
env: config.env,
|
|
1799
|
-
publicApiKey: `${config.publicApiKey.substring(0, 8)}...`,
|
|
1800
|
-
appName: config.appName,
|
|
1801
|
-
loginActionsCount: config.loginActions.length,
|
|
1802
|
-
hasLogo: !!config.logo,
|
|
1803
|
-
colorsCount: Object.keys(config.colors).length
|
|
1804
|
-
} : null,
|
|
1805
|
-
sources: config?.configSource || null,
|
|
1806
|
-
rawConfig: config?.rawConfig || null
|
|
1807
|
-
},
|
|
1808
|
-
authentication: {
|
|
1809
|
-
hasToken: !!token,
|
|
1810
|
-
tokenLength: token?.length || 0,
|
|
1811
|
-
userEmail: user?.email || null,
|
|
1812
|
-
userId: user?.sub || null,
|
|
1813
|
-
expiration: tokenExpiration?.toISOString() || null,
|
|
1814
|
-
minutesUntilExpiry: tokenManager.getTimeUntilExpiration()
|
|
1815
|
-
},
|
|
1816
|
-
tokenManager: tokenManager.getDebugInfo(),
|
|
1817
|
-
crudifyInitializer: crudifyInitializer.getStatus()
|
|
1818
|
-
};
|
|
1819
|
-
}, [isConfigured, configError, isInitialized, isInitializing, initializationError, isAuthenticated, config, token, user, tokenExpiration]);
|
|
1820
|
-
(0, import_react5.useEffect)(() => {
|
|
1821
|
-
console.log("\u{1F30D} CrudifyDataProvider - Provider mounting, starting initialization");
|
|
1822
|
-
const resolvedConfig = initializeConfiguration();
|
|
1823
|
-
updateAuthenticationState();
|
|
1824
|
-
if (resolvedConfig && resolvedConfig.publicApiKey) {
|
|
1825
|
-
initializeCrudify(resolvedConfig);
|
|
1911
|
+
if (typeof error === "object" && error !== null) {
|
|
1912
|
+
const response = error;
|
|
1913
|
+
if (response.data && Array.isArray(response.data)) {
|
|
1914
|
+
return parseTransactionError(error);
|
|
1826
1915
|
}
|
|
1827
|
-
return ()
|
|
1828
|
-
console.log("\u{1F30D} CrudifyDataProvider - Provider unmounting, cleaning up");
|
|
1829
|
-
tokenManager.cleanup();
|
|
1830
|
-
};
|
|
1831
|
-
}, []);
|
|
1832
|
-
(0, import_react5.useEffect)(() => {
|
|
1833
|
-
console.log("\u{1F510} CrudifyDataProvider - INITIAL_AUTH_EFFECT: Loading initial authentication state");
|
|
1834
|
-
updateAuthenticationState();
|
|
1835
|
-
}, []);
|
|
1836
|
-
const contextValue = {
|
|
1837
|
-
// Configuration
|
|
1838
|
-
config,
|
|
1839
|
-
isConfigured,
|
|
1840
|
-
configError,
|
|
1841
|
-
configSource: config ? JSON.stringify(config.configSource) : "none",
|
|
1842
|
-
// Initialization
|
|
1843
|
-
isInitialized,
|
|
1844
|
-
isInitializing,
|
|
1845
|
-
initializationError,
|
|
1846
|
-
// Authentication
|
|
1847
|
-
isAuthenticated,
|
|
1848
|
-
token,
|
|
1849
|
-
user,
|
|
1850
|
-
tokenExpiration,
|
|
1851
|
-
// Actions
|
|
1852
|
-
setToken,
|
|
1853
|
-
logout,
|
|
1854
|
-
refreshConfig,
|
|
1855
|
-
reinitialize,
|
|
1856
|
-
// Debug
|
|
1857
|
-
getDebugInfo
|
|
1858
|
-
};
|
|
1859
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CrudifyDataContext.Provider, { value: contextValue, children });
|
|
1860
|
-
};
|
|
1861
|
-
var useCrudifyDataContext = () => {
|
|
1862
|
-
const context = (0, import_react5.useContext)(CrudifyDataContext);
|
|
1863
|
-
if (!context) {
|
|
1864
|
-
throw new Error(
|
|
1865
|
-
"useCrudifyDataContext must be used within a CrudifyDataProvider. Make sure to wrap your app with <CrudifyDataProvider>."
|
|
1866
|
-
);
|
|
1916
|
+
return parseApiError(error);
|
|
1867
1917
|
}
|
|
1868
|
-
return
|
|
1869
|
-
|
|
1918
|
+
return [
|
|
1919
|
+
{
|
|
1920
|
+
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
|
|
1921
|
+
message: "An unknown error occurred",
|
|
1922
|
+
severity: "error",
|
|
1923
|
+
details: { originalError: error }
|
|
1924
|
+
}
|
|
1925
|
+
];
|
|
1926
|
+
}
|
|
1870
1927
|
|
|
1871
1928
|
// src/hooks/useCrudifyAuth.ts
|
|
1929
|
+
init_CrudifyDataProvider();
|
|
1872
1930
|
var useCrudifyAuth = () => {
|
|
1873
1931
|
const {
|
|
1874
1932
|
isAuthenticated,
|
|
@@ -2718,6 +2776,7 @@ var CrudifyInitializer2 = ({ children, fallback }) => {
|
|
|
2718
2776
|
|
|
2719
2777
|
// src/components/CrudifyLogin/hooks/useCrudifyLogin.ts
|
|
2720
2778
|
var import_react10 = require("react");
|
|
2779
|
+
init_cookies();
|
|
2721
2780
|
var useCrudifyLogin = (config, _options = {}) => {
|
|
2722
2781
|
const finalConfig = (0, import_react10.useMemo)(() => {
|
|
2723
2782
|
const publicApiKey = config.publicApiKey || getCookie("publicApiKey") || null;
|
|
@@ -2844,6 +2903,7 @@ var import_icons_material = require("@mui/icons-material");
|
|
|
2844
2903
|
// src/hooks/useUserProfile.ts
|
|
2845
2904
|
var import_react11 = require("react");
|
|
2846
2905
|
var import_crudify_browser4 = __toESM(require("@nocios/crudify-browser"));
|
|
2906
|
+
init_jwtUtils();
|
|
2847
2907
|
var useUserProfile = (options = {}) => {
|
|
2848
2908
|
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
2849
2909
|
const [userProfile, setUserProfile] = (0, import_react11.useState)(null);
|
|
@@ -3144,9 +3204,13 @@ var UserProfileDisplay = ({
|
|
|
3144
3204
|
};
|
|
3145
3205
|
var UserProfileDisplay_default = UserProfileDisplay;
|
|
3146
3206
|
|
|
3207
|
+
// src/index.ts
|
|
3208
|
+
init_CrudifyDataProvider();
|
|
3209
|
+
|
|
3147
3210
|
// src/hooks/useCrudifyUser.ts
|
|
3148
3211
|
var import_react13 = require("react");
|
|
3149
3212
|
var import_crudify_browser5 = __toESM(require("@nocios/crudify-browser"));
|
|
3213
|
+
init_CrudifyDataProvider();
|
|
3150
3214
|
var useCrudifyUser = (options = {}) => {
|
|
3151
3215
|
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
3152
3216
|
const {
|
|
@@ -3351,6 +3415,7 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3351
3415
|
// src/hooks/useCrudifyData.ts
|
|
3352
3416
|
var import_react14 = require("react");
|
|
3353
3417
|
var import_crudify_browser6 = __toESM(require("@nocios/crudify-browser"));
|
|
3418
|
+
init_CrudifyDataProvider();
|
|
3354
3419
|
var useCrudifyData = () => {
|
|
3355
3420
|
const {
|
|
3356
3421
|
isInitialized,
|
|
@@ -3502,6 +3567,7 @@ var useCrudifyData = () => {
|
|
|
3502
3567
|
};
|
|
3503
3568
|
|
|
3504
3569
|
// src/hooks/useCrudifyConfig.ts
|
|
3570
|
+
init_CrudifyDataProvider();
|
|
3505
3571
|
var useCrudifyConfig = () => {
|
|
3506
3572
|
const {
|
|
3507
3573
|
config,
|
|
@@ -3525,6 +3591,7 @@ var useCrudifyConfig = () => {
|
|
|
3525
3591
|
// src/hooks/useCrudifyInstance.ts
|
|
3526
3592
|
var import_react15 = require("react");
|
|
3527
3593
|
var import_crudify_browser7 = __toESM(require("@nocios/crudify-browser"));
|
|
3594
|
+
init_CrudifyDataProvider();
|
|
3528
3595
|
var useCrudifyInstance = () => {
|
|
3529
3596
|
const {
|
|
3530
3597
|
isInitialized,
|
|
@@ -3533,28 +3600,32 @@ var useCrudifyInstance = () => {
|
|
|
3533
3600
|
} = useCrudifyDataContext();
|
|
3534
3601
|
const isReady = isInitialized && !initializationError && !isInitializing;
|
|
3535
3602
|
const waitForReady = (0, import_react15.useCallback)(async () => {
|
|
3536
|
-
|
|
3603
|
+
console.log("\u{1F504} useCrudifyInstance - waitForReady: Starting wait");
|
|
3604
|
+
console.log(" - isReady:", isReady);
|
|
3605
|
+
console.log(" - isInitialized:", isInitialized);
|
|
3606
|
+
console.log(" - isInitializing:", isInitializing);
|
|
3607
|
+
console.log(" - initializationError:", initializationError);
|
|
3608
|
+
if (isReady) {
|
|
3609
|
+
console.log("\u2705 useCrudifyInstance - waitForReady: Already ready, returning immediately");
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3537
3612
|
if (initializationError) {
|
|
3538
3613
|
throw new Error(`Crudify initialization failed: ${initializationError}`);
|
|
3539
3614
|
}
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
const
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
}
|
|
3555
|
-
};
|
|
3556
|
-
check();
|
|
3557
|
-
});
|
|
3615
|
+
try {
|
|
3616
|
+
console.log("\u{1F504} useCrudifyInstance - waitForReady: Using CrudifyInitializer.waitForInitialization()");
|
|
3617
|
+
const { crudifyInitializer: crudifyInitializer2 } = await Promise.resolve().then(() => (init_CrudifyDataProvider(), CrudifyDataProvider_exports));
|
|
3618
|
+
await crudifyInitializer2.waitForInitialization();
|
|
3619
|
+
console.log("\u2705 useCrudifyInstance - waitForReady: CrudifyInitializer completed");
|
|
3620
|
+
if (!crudifyInitializer2.isReady()) {
|
|
3621
|
+
const error = crudifyInitializer2.getError();
|
|
3622
|
+
throw new Error(`Crudify initialization failed: ${error || "Unknown error"}`);
|
|
3623
|
+
}
|
|
3624
|
+
console.log("\u2705 useCrudifyInstance - waitForReady: Verification successful");
|
|
3625
|
+
} catch (error) {
|
|
3626
|
+
console.error("\u274C useCrudifyInstance - waitForReady: Error during wait:", error);
|
|
3627
|
+
throw error;
|
|
3628
|
+
}
|
|
3558
3629
|
}, [isReady, initializationError, isInitialized, isInitializing]);
|
|
3559
3630
|
const ensureReady = (0, import_react15.useCallback)(async (operationName) => {
|
|
3560
3631
|
if (!isReady) {
|
|
@@ -3683,6 +3754,39 @@ var useCrudifyInstance = () => {
|
|
|
3683
3754
|
waitForReady
|
|
3684
3755
|
};
|
|
3685
3756
|
};
|
|
3757
|
+
var getCrudifyInstanceAsync = async () => {
|
|
3758
|
+
console.log("\u{1F504} getCrudifyInstanceAsync - Starting");
|
|
3759
|
+
const { crudifyInitializer: crudifyInitializer2 } = await Promise.resolve().then(() => (init_CrudifyDataProvider(), CrudifyDataProvider_exports));
|
|
3760
|
+
console.log("\u{1F504} getCrudifyInstanceAsync - Checking if ready");
|
|
3761
|
+
console.log(" - crudifyInitializer.isReady():", crudifyInitializer2.isReady());
|
|
3762
|
+
console.log(" - crudifyInitializer.getStatus():", crudifyInitializer2.getStatus());
|
|
3763
|
+
if (!crudifyInitializer2.isReady()) {
|
|
3764
|
+
console.log("\u{1F504} getCrudifyInstanceAsync - Waiting for crudify initialization...");
|
|
3765
|
+
await crudifyInitializer2.waitForInitialization();
|
|
3766
|
+
if (!crudifyInitializer2.isReady()) {
|
|
3767
|
+
const error = crudifyInitializer2.getError();
|
|
3768
|
+
throw new Error(`Crudify initialization failed: ${error || "Unknown error after waiting"}`);
|
|
3769
|
+
}
|
|
3770
|
+
console.log("\u2705 getCrudifyInstanceAsync - Crudify is ready after waiting");
|
|
3771
|
+
} else {
|
|
3772
|
+
console.log("\u2705 getCrudifyInstanceAsync - Already ready, no wait needed");
|
|
3773
|
+
}
|
|
3774
|
+
console.log("\u2705 getCrudifyInstanceAsync - Returning crudify instance");
|
|
3775
|
+
return import_crudify_browser7.default;
|
|
3776
|
+
};
|
|
3777
|
+
var getCrudifyInstanceSync = async () => {
|
|
3778
|
+
const { crudifyInitializer: crudifyInitializer2 } = await Promise.resolve().then(() => (init_CrudifyDataProvider(), CrudifyDataProvider_exports));
|
|
3779
|
+
if (!crudifyInitializer2.isReady()) {
|
|
3780
|
+
throw new Error("Crudify not ready. Use getCrudifyInstanceAsync() or call this from within a React component using useCrudifyInstance()");
|
|
3781
|
+
}
|
|
3782
|
+
return import_crudify_browser7.default;
|
|
3783
|
+
};
|
|
3784
|
+
|
|
3785
|
+
// src/index.ts
|
|
3786
|
+
init_CrudifyDataProvider();
|
|
3787
|
+
init_jwtUtils();
|
|
3788
|
+
init_cookies();
|
|
3789
|
+
init_secureStorage();
|
|
3686
3790
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3687
3791
|
0 && (module.exports = {
|
|
3688
3792
|
CrudifyDataProvider,
|
|
@@ -3695,6 +3799,8 @@ var useCrudifyInstance = () => {
|
|
|
3695
3799
|
crudifyInitializer,
|
|
3696
3800
|
decodeJwtSafely,
|
|
3697
3801
|
getCookie,
|
|
3802
|
+
getCrudifyInstanceAsync,
|
|
3803
|
+
getCrudifyInstanceSync,
|
|
3698
3804
|
getCurrentUserEmail,
|
|
3699
3805
|
getErrorMessage,
|
|
3700
3806
|
handleCrudifyError,
|