@nocios/crudify-ui 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -39
- package/README_DEPTH.md +400 -216
- package/dist/index.d.mts +26 -26
- package/dist/index.d.ts +26 -26
- package/dist/index.js +1982 -1982
- package/dist/index.mjs +1837 -1837
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3324,173 +3324,752 @@ var UserProfileDisplay = ({
|
|
|
3324
3324
|
};
|
|
3325
3325
|
var UserProfileDisplay_default = UserProfileDisplay;
|
|
3326
3326
|
|
|
3327
|
-
// src/
|
|
3328
|
-
|
|
3327
|
+
// src/components/PublicPolicies/Policies.tsx
|
|
3328
|
+
var import_react15 = require("react");
|
|
3329
|
+
var import_react_i18next3 = require("react-i18next");
|
|
3330
|
+
var import_material10 = require("@mui/material");
|
|
3331
|
+
var import_icons_material4 = require("@mui/icons-material");
|
|
3329
3332
|
|
|
3330
|
-
// src/
|
|
3333
|
+
// src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
|
|
3334
|
+
var import_react14 = require("react");
|
|
3335
|
+
var import_react_i18next2 = require("react-i18next");
|
|
3336
|
+
var import_material9 = require("@mui/material");
|
|
3337
|
+
var import_icons_material3 = require("@mui/icons-material");
|
|
3338
|
+
|
|
3339
|
+
// src/components/PublicPolicies/FieldSelector/FieldSelector.tsx
|
|
3331
3340
|
var import_react13 = require("react");
|
|
3332
|
-
var
|
|
3333
|
-
|
|
3334
|
-
var
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
const
|
|
3344
|
-
const
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
const
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
if (mountedRef.current) {
|
|
3359
|
-
setError("No user email available from JWT token");
|
|
3360
|
-
setLoading(false);
|
|
3361
|
-
}
|
|
3362
|
-
return;
|
|
3363
|
-
}
|
|
3364
|
-
if (!isInitialized) {
|
|
3365
|
-
if (mountedRef.current) {
|
|
3366
|
-
setError("Crudify not initialized");
|
|
3367
|
-
setLoading(false);
|
|
3368
|
-
}
|
|
3369
|
-
return;
|
|
3370
|
-
}
|
|
3371
|
-
if (abortControllerRef.current) {
|
|
3372
|
-
abortControllerRef.current.abort();
|
|
3341
|
+
var import_react_i18next = require("react-i18next");
|
|
3342
|
+
var import_material8 = require("@mui/material");
|
|
3343
|
+
var import_icons_material2 = require("@mui/icons-material");
|
|
3344
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3345
|
+
var FieldSelector = ({
|
|
3346
|
+
value,
|
|
3347
|
+
onChange,
|
|
3348
|
+
availableFields,
|
|
3349
|
+
error,
|
|
3350
|
+
disabled = false
|
|
3351
|
+
}) => {
|
|
3352
|
+
const { t } = (0, import_react_i18next.useTranslation)();
|
|
3353
|
+
const [mode, setMode] = (0, import_react13.useState)("custom");
|
|
3354
|
+
const isUpdatingRef = (0, import_react13.useRef)(false);
|
|
3355
|
+
(0, import_react13.useEffect)(() => {
|
|
3356
|
+
const current = value || { allow: [], owner_allow: [], deny: [] };
|
|
3357
|
+
const all = new Set(availableFields);
|
|
3358
|
+
const allow = (current.allow || []).filter((f) => all.has(f));
|
|
3359
|
+
const owner = (current.owner_allow || []).filter((f) => all.has(f));
|
|
3360
|
+
const deny = (current.deny || []).filter((f) => all.has(f));
|
|
3361
|
+
availableFields.forEach((f) => {
|
|
3362
|
+
if (!allow.includes(f) && !owner.includes(f) && !deny.includes(f)) deny.push(f);
|
|
3363
|
+
});
|
|
3364
|
+
const normalized = { allow, owner_allow: owner, deny };
|
|
3365
|
+
if (JSON.stringify(normalized) !== JSON.stringify(current)) {
|
|
3366
|
+
onChange(normalized);
|
|
3373
3367
|
}
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
}
|
|
3439
|
-
} catch (parseError) {
|
|
3440
|
-
console.error("\u{1F464} useCrudifyUser - Error parsing double-nested response data:", parseError);
|
|
3368
|
+
if (allow.length === availableFields.length) setMode("all");
|
|
3369
|
+
else if (deny.length === availableFields.length) setMode("none");
|
|
3370
|
+
else setMode("custom");
|
|
3371
|
+
}, [availableFields, value]);
|
|
3372
|
+
const setAllAllow = () => {
|
|
3373
|
+
isUpdatingRef.current = true;
|
|
3374
|
+
onChange({ allow: [...availableFields], owner_allow: [], deny: [] });
|
|
3375
|
+
setMode("all");
|
|
3376
|
+
setTimeout(() => {
|
|
3377
|
+
isUpdatingRef.current = false;
|
|
3378
|
+
}, 0);
|
|
3379
|
+
};
|
|
3380
|
+
const setAllDeny = () => {
|
|
3381
|
+
isUpdatingRef.current = true;
|
|
3382
|
+
onChange({ allow: [], owner_allow: [], deny: [...availableFields] });
|
|
3383
|
+
setMode("none");
|
|
3384
|
+
setTimeout(() => {
|
|
3385
|
+
isUpdatingRef.current = false;
|
|
3386
|
+
}, 0);
|
|
3387
|
+
};
|
|
3388
|
+
const getFieldState = (fieldName) => {
|
|
3389
|
+
if (value?.allow?.includes(fieldName)) return "allow";
|
|
3390
|
+
if (value?.owner_allow?.includes(fieldName)) return "owner_allow";
|
|
3391
|
+
return "deny";
|
|
3392
|
+
};
|
|
3393
|
+
const setFieldState = (fieldName, state) => {
|
|
3394
|
+
isUpdatingRef.current = true;
|
|
3395
|
+
const allow = new Set(value?.allow || []);
|
|
3396
|
+
const owner = new Set(value?.owner_allow || []);
|
|
3397
|
+
const deny = new Set(value?.deny || []);
|
|
3398
|
+
allow.delete(fieldName);
|
|
3399
|
+
owner.delete(fieldName);
|
|
3400
|
+
deny.delete(fieldName);
|
|
3401
|
+
if (state === "allow") allow.add(fieldName);
|
|
3402
|
+
if (state === "owner_allow") owner.add(fieldName);
|
|
3403
|
+
if (state === "deny") deny.add(fieldName);
|
|
3404
|
+
onChange({ allow: Array.from(allow), owner_allow: Array.from(owner), deny: Array.from(deny) });
|
|
3405
|
+
setMode("custom");
|
|
3406
|
+
setTimeout(() => {
|
|
3407
|
+
isUpdatingRef.current = false;
|
|
3408
|
+
}, 0);
|
|
3409
|
+
};
|
|
3410
|
+
if (availableFields.length === 0) {
|
|
3411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { children: [
|
|
3412
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
|
|
3413
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", color: "text.secondary", sx: { fontStyle: "italic" }, children: t("modules.form.publicPolicies.fields.conditions.noFieldsAvailable") }),
|
|
3414
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.FormHelperText, { error: true, sx: { mt: 1 }, children: error })
|
|
3415
|
+
] });
|
|
3416
|
+
}
|
|
3417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { children: [
|
|
3418
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
|
|
3419
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
|
|
3420
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3421
|
+
import_material8.Button,
|
|
3422
|
+
{
|
|
3423
|
+
variant: mode === "all" ? "contained" : "outlined",
|
|
3424
|
+
startIcon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material2.SelectAll, {}),
|
|
3425
|
+
onClick: setAllAllow,
|
|
3426
|
+
disabled,
|
|
3427
|
+
size: "small",
|
|
3428
|
+
sx: {
|
|
3429
|
+
minWidth: 120,
|
|
3430
|
+
...mode === "all" && {
|
|
3431
|
+
backgroundColor: "#16a34a",
|
|
3432
|
+
"&:hover": { backgroundColor: "#15803d" }
|
|
3441
3433
|
}
|
|
3442
|
-
}
|
|
3443
|
-
|
|
3444
|
-
if (userData2) {
|
|
3445
|
-
console.log("\u{1F464} useCrudifyUser - User data found:", userData2);
|
|
3446
|
-
setUserData(userData2);
|
|
3447
|
-
setError(null);
|
|
3448
|
-
retryCountRef.current = 0;
|
|
3449
|
-
console.log("\u{1F464} useCrudifyUser - Profile loaded successfully:", userData2);
|
|
3450
|
-
} else {
|
|
3451
|
-
setError("User profile not found in database");
|
|
3452
|
-
setUserData(null);
|
|
3453
|
-
console.warn("\u{1F464} useCrudifyUser - User not found for email:", userEmail);
|
|
3454
|
-
}
|
|
3455
|
-
}
|
|
3456
|
-
} catch (err) {
|
|
3457
|
-
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
3458
|
-
const error2 = err;
|
|
3459
|
-
console.error("\u{1F464} useCrudifyUser - Error fetching profile:", error2);
|
|
3460
|
-
if (error2.name === "AbortError") {
|
|
3461
|
-
return;
|
|
3434
|
+
},
|
|
3435
|
+
children: t("modules.form.publicPolicies.fields.conditions.allFields")
|
|
3462
3436
|
}
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3437
|
+
),
|
|
3438
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3439
|
+
import_material8.Button,
|
|
3440
|
+
{
|
|
3441
|
+
variant: mode === "none" ? "contained" : "outlined",
|
|
3442
|
+
startIcon: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material2.ClearAll, {}),
|
|
3443
|
+
onClick: setAllDeny,
|
|
3444
|
+
disabled,
|
|
3445
|
+
size: "small",
|
|
3446
|
+
sx: {
|
|
3447
|
+
minWidth: 120,
|
|
3448
|
+
...mode === "none" && {
|
|
3449
|
+
backgroundColor: "#cf222e",
|
|
3450
|
+
"&:hover": { backgroundColor: "#bc1f2c" }
|
|
3470
3451
|
}
|
|
3471
|
-
},
|
|
3472
|
-
|
|
3473
|
-
setError("Failed to load user profile from database");
|
|
3474
|
-
setUserData(null);
|
|
3452
|
+
},
|
|
3453
|
+
children: t("modules.form.publicPolicies.fields.conditions.noFields")
|
|
3475
3454
|
}
|
|
3476
|
-
|
|
3477
|
-
}
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3455
|
+
)
|
|
3456
|
+
] }),
|
|
3457
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Box, { sx: { p: 2, border: "1px solid #d1d9e0", borderRadius: 1, backgroundColor: "#f6f8fa" }, children: [
|
|
3458
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.help") }),
|
|
3459
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Stack, { spacing: 1, children: availableFields.map((fieldName) => {
|
|
3460
|
+
const fieldState = getFieldState(fieldName);
|
|
3461
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
|
|
3462
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.Typography, { variant: "body2", sx: { minWidth: 100, fontFamily: "monospace" }, children: fieldName }),
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material8.ToggleButtonGroup, { value: fieldState, exclusive: true, size: "small", children: [
|
|
3464
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
3465
|
+
import_material8.ToggleButton,
|
|
3466
|
+
{
|
|
3467
|
+
value: "allow",
|
|
3468
|
+
onClick: () => setFieldState(fieldName, "allow"),
|
|
3469
|
+
disabled,
|
|
3470
|
+
sx: {
|
|
3471
|
+
px: 2,
|
|
3472
|
+
color: fieldState === "allow" ? "#ffffff" : "#6b7280",
|
|
3473
|
+
backgroundColor: fieldState === "allow" ? "#16a34a" : "#f3f4f6",
|
|
3474
|
+
borderColor: fieldState === "allow" ? "#16a34a" : "#d1d5db",
|
|
3475
|
+
"&:hover": {
|
|
3476
|
+
backgroundColor: fieldState === "allow" ? "#15803d" : "#e5e7eb",
|
|
3477
|
+
borderColor: fieldState === "allow" ? "#15803d" : "#9ca3af"
|
|
3478
|
+
},
|
|
3479
|
+
"&.Mui-selected": {
|
|
3480
|
+
backgroundColor: "#16a34a",
|
|
3481
|
+
color: "#ffffff",
|
|
3482
|
+
"&:hover": {
|
|
3483
|
+
backgroundColor: "#15803d"
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
},
|
|
3487
|
+
children: [
|
|
3488
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material2.CheckCircle, { sx: { fontSize: 16, mr: 0.5 } }),
|
|
3489
|
+
t("modules.form.publicPolicies.fields.conditions.states.allow")
|
|
3490
|
+
]
|
|
3491
|
+
}
|
|
3492
|
+
),
|
|
3493
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3494
|
+
import_material8.ToggleButton,
|
|
3495
|
+
{
|
|
3496
|
+
value: "owner_allow",
|
|
3497
|
+
onClick: () => setFieldState(fieldName, "owner_allow"),
|
|
3498
|
+
disabled,
|
|
3499
|
+
sx: {
|
|
3500
|
+
px: 2,
|
|
3501
|
+
color: fieldState === "owner_allow" ? "#ffffff" : "#6b7280",
|
|
3502
|
+
backgroundColor: fieldState === "owner_allow" ? "#0ea5e9" : "#f3f4f6",
|
|
3503
|
+
borderColor: fieldState === "owner_allow" ? "#0ea5e9" : "#d1d5db",
|
|
3504
|
+
"&:hover": {
|
|
3505
|
+
backgroundColor: fieldState === "owner_allow" ? "#0284c7" : "#e5e7eb",
|
|
3506
|
+
borderColor: fieldState === "owner_allow" ? "#0284c7" : "#9ca3af"
|
|
3507
|
+
},
|
|
3508
|
+
"&.Mui-selected": {
|
|
3509
|
+
backgroundColor: "#0ea5e9",
|
|
3510
|
+
color: "#ffffff",
|
|
3511
|
+
"&:hover": {
|
|
3512
|
+
backgroundColor: "#0284c7"
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
},
|
|
3516
|
+
children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
|
|
3517
|
+
}
|
|
3518
|
+
),
|
|
3519
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
3520
|
+
import_material8.ToggleButton,
|
|
3521
|
+
{
|
|
3522
|
+
value: "deny",
|
|
3523
|
+
onClick: () => setFieldState(fieldName, "deny"),
|
|
3524
|
+
disabled,
|
|
3525
|
+
sx: {
|
|
3526
|
+
px: 2,
|
|
3527
|
+
color: fieldState === "deny" ? "#ffffff" : "#6b7280",
|
|
3528
|
+
backgroundColor: fieldState === "deny" ? "#dc2626" : "#f3f4f6",
|
|
3529
|
+
borderColor: fieldState === "deny" ? "#dc2626" : "#d1d5db",
|
|
3530
|
+
"&:hover": {
|
|
3531
|
+
backgroundColor: fieldState === "deny" ? "#b91c1c" : "#e5e7eb",
|
|
3532
|
+
borderColor: fieldState === "deny" ? "#b91c1c" : "#9ca3af"
|
|
3533
|
+
},
|
|
3534
|
+
"&.Mui-selected": {
|
|
3535
|
+
backgroundColor: "#dc2626",
|
|
3536
|
+
color: "#ffffff",
|
|
3537
|
+
"&:hover": {
|
|
3538
|
+
backgroundColor: "#b91c1c"
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
},
|
|
3542
|
+
children: [
|
|
3543
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_icons_material2.Cancel, { sx: { fontSize: 16, mr: 0.5 } }),
|
|
3544
|
+
t("modules.form.publicPolicies.fields.conditions.states.deny")
|
|
3545
|
+
]
|
|
3546
|
+
}
|
|
3547
|
+
)
|
|
3548
|
+
] })
|
|
3549
|
+
] }, fieldName);
|
|
3550
|
+
}) })
|
|
3551
|
+
] }),
|
|
3552
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_material8.FormHelperText, { error: true, sx: { mt: 1 }, children: error })
|
|
3553
|
+
] });
|
|
3554
|
+
};
|
|
3555
|
+
var FieldSelector_default = FieldSelector;
|
|
3556
|
+
|
|
3557
|
+
// src/components/PublicPolicies/constants.ts
|
|
3558
|
+
var POLICY_ACTIONS = ["create", "read", "update", "delete"];
|
|
3559
|
+
var PREFERRED_POLICY_ORDER = [
|
|
3560
|
+
"create",
|
|
3561
|
+
"read",
|
|
3562
|
+
"update",
|
|
3563
|
+
"delete"
|
|
3564
|
+
];
|
|
3565
|
+
|
|
3566
|
+
// src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
|
|
3567
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
3568
|
+
var PolicyItem = (0, import_react14.forwardRef)(({
|
|
3569
|
+
policy,
|
|
3570
|
+
onChange,
|
|
3571
|
+
onRemove,
|
|
3572
|
+
availableFields,
|
|
3573
|
+
isSubmitting = false,
|
|
3574
|
+
usedActions,
|
|
3575
|
+
error
|
|
3576
|
+
}, ref) => {
|
|
3577
|
+
const { t } = (0, import_react_i18next2.useTranslation)();
|
|
3578
|
+
const takenActions = new Set(Array.from(usedActions || []));
|
|
3579
|
+
takenActions.delete(policy.action);
|
|
3580
|
+
const actionOptions = POLICY_ACTIONS.map((a) => ({
|
|
3581
|
+
value: a,
|
|
3582
|
+
label: t(`modules.form.publicPolicies.fields.action.options.${a}`)
|
|
3583
|
+
}));
|
|
3584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3585
|
+
import_material9.Paper,
|
|
3586
|
+
{
|
|
3587
|
+
ref,
|
|
3588
|
+
sx: {
|
|
3589
|
+
p: 3,
|
|
3590
|
+
border: "1px solid #d1d9e0",
|
|
3591
|
+
borderRadius: 2,
|
|
3592
|
+
position: "relative",
|
|
3593
|
+
backgroundColor: "#ffffff"
|
|
3594
|
+
},
|
|
3595
|
+
children: [
|
|
3596
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { sx: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", mb: 3 }, children: [
|
|
3597
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3598
|
+
import_material9.Typography,
|
|
3599
|
+
{
|
|
3600
|
+
variant: "subtitle1",
|
|
3601
|
+
sx: {
|
|
3602
|
+
fontWeight: 600,
|
|
3603
|
+
color: "#111418",
|
|
3604
|
+
fontSize: "1rem"
|
|
3605
|
+
},
|
|
3606
|
+
children: t("modules.form.publicPolicies.policyTitle")
|
|
3607
|
+
}
|
|
3608
|
+
),
|
|
3609
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3610
|
+
import_material9.IconButton,
|
|
3611
|
+
{
|
|
3612
|
+
onClick: onRemove,
|
|
3613
|
+
size: "small",
|
|
3614
|
+
disabled: isSubmitting,
|
|
3615
|
+
"aria-label": t("modules.form.publicPolicies.removePolicy"),
|
|
3616
|
+
sx: {
|
|
3617
|
+
color: "#656d76",
|
|
3618
|
+
"&:hover": {
|
|
3619
|
+
color: "#cf222e",
|
|
3620
|
+
backgroundColor: "rgba(207, 34, 46, 0.1)"
|
|
3621
|
+
}
|
|
3622
|
+
},
|
|
3623
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons_material3.Delete, {})
|
|
3624
|
+
}
|
|
3625
|
+
)
|
|
3626
|
+
] }),
|
|
3627
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Stack, { spacing: 3, children: [
|
|
3628
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Stack, { direction: { xs: "column", md: "row" }, spacing: 2, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Box, { sx: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.FormControl, { fullWidth: true, children: [
|
|
3629
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.InputLabel, { children: t("modules.form.publicPolicies.fields.action.label") }),
|
|
3630
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3631
|
+
import_material9.Select,
|
|
3632
|
+
{
|
|
3633
|
+
value: policy.action,
|
|
3634
|
+
label: t("modules.form.publicPolicies.fields.action.label"),
|
|
3635
|
+
disabled: isSubmitting,
|
|
3636
|
+
onChange: (e) => {
|
|
3637
|
+
const newAction = e.target.value;
|
|
3638
|
+
const next = { ...policy, action: newAction };
|
|
3639
|
+
if (newAction === "delete") {
|
|
3640
|
+
next.permission = "deny";
|
|
3641
|
+
delete next.fields;
|
|
3642
|
+
} else {
|
|
3643
|
+
next.fields = { allow: [], owner_allow: [], deny: availableFields };
|
|
3644
|
+
delete next.permission;
|
|
3645
|
+
}
|
|
3646
|
+
onChange(next);
|
|
3647
|
+
},
|
|
3648
|
+
sx: {
|
|
3649
|
+
backgroundColor: "#ffffff",
|
|
3650
|
+
"&:hover .MuiOutlinedInput-notchedOutline": {
|
|
3651
|
+
borderColor: "#8c959f"
|
|
3652
|
+
},
|
|
3653
|
+
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
|
3654
|
+
borderColor: "#0969da",
|
|
3655
|
+
borderWidth: 2
|
|
3656
|
+
}
|
|
3657
|
+
},
|
|
3658
|
+
children: actionOptions.map((option) => {
|
|
3659
|
+
const disabledOption = takenActions.has(option.value);
|
|
3660
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.MenuItem, { value: option.value, disabled: disabledOption, children: option.label }, option.value);
|
|
3661
|
+
})
|
|
3662
|
+
}
|
|
3663
|
+
),
|
|
3664
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.FormHelperText, { error: true, children: error })
|
|
3665
|
+
] }) }) }),
|
|
3666
|
+
policy.action === "delete" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { children: [
|
|
3667
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
|
|
3668
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
|
|
3669
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3670
|
+
import_material9.Button,
|
|
3671
|
+
{
|
|
3672
|
+
variant: policy.permission === "*" ? "contained" : "outlined",
|
|
3673
|
+
startIcon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons_material3.SelectAll, {}),
|
|
3674
|
+
onClick: () => onChange({ ...policy, permission: "*" }),
|
|
3675
|
+
disabled: isSubmitting,
|
|
3676
|
+
size: "small",
|
|
3677
|
+
sx: {
|
|
3678
|
+
minWidth: 140,
|
|
3679
|
+
whiteSpace: "nowrap",
|
|
3680
|
+
...policy.permission === "*" && {
|
|
3681
|
+
backgroundColor: "#16a34a",
|
|
3682
|
+
"&:hover": { backgroundColor: "#15803d" }
|
|
3683
|
+
}
|
|
3684
|
+
},
|
|
3685
|
+
children: t("modules.form.publicPolicies.fields.conditions.allFields")
|
|
3686
|
+
}
|
|
3687
|
+
),
|
|
3688
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3689
|
+
import_material9.Button,
|
|
3690
|
+
{
|
|
3691
|
+
variant: policy.permission === "owner" ? "contained" : "outlined",
|
|
3692
|
+
onClick: () => onChange({ ...policy, permission: "owner" }),
|
|
3693
|
+
disabled: isSubmitting,
|
|
3694
|
+
size: "small",
|
|
3695
|
+
sx: {
|
|
3696
|
+
minWidth: 140,
|
|
3697
|
+
whiteSpace: "nowrap",
|
|
3698
|
+
...policy.permission === "owner" && {
|
|
3699
|
+
backgroundColor: "#0ea5e9",
|
|
3700
|
+
"&:hover": { backgroundColor: "#0284c7" }
|
|
3701
|
+
}
|
|
3702
|
+
},
|
|
3703
|
+
children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
|
|
3704
|
+
}
|
|
3705
|
+
),
|
|
3706
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3707
|
+
import_material9.Button,
|
|
3708
|
+
{
|
|
3709
|
+
variant: policy.permission === "deny" ? "contained" : "outlined",
|
|
3710
|
+
startIcon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_icons_material3.ClearAll, {}),
|
|
3711
|
+
onClick: () => onChange({ ...policy, permission: "deny" }),
|
|
3712
|
+
disabled: isSubmitting,
|
|
3713
|
+
size: "small",
|
|
3714
|
+
sx: {
|
|
3715
|
+
minWidth: 140,
|
|
3716
|
+
whiteSpace: "nowrap",
|
|
3717
|
+
...policy.permission === "deny" && {
|
|
3718
|
+
backgroundColor: "#cf222e",
|
|
3719
|
+
"&:hover": { backgroundColor: "#bc1f2c" }
|
|
3720
|
+
}
|
|
3721
|
+
},
|
|
3722
|
+
children: t("modules.form.publicPolicies.fields.conditions.noFields")
|
|
3723
|
+
}
|
|
3724
|
+
)
|
|
3725
|
+
] })
|
|
3726
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3727
|
+
FieldSelector_default,
|
|
3728
|
+
{
|
|
3729
|
+
value: policy.fields || { allow: [], owner_allow: [], deny: [] },
|
|
3730
|
+
onChange: (nextFields) => onChange({ ...policy, fields: nextFields }),
|
|
3731
|
+
availableFields,
|
|
3732
|
+
disabled: isSubmitting
|
|
3733
|
+
}
|
|
3734
|
+
),
|
|
3735
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Paper, { variant: "outlined", sx: { p: 2, backgroundColor: "#f9fafb" }, children: policy.action === "delete" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
|
|
3736
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { component: "span", sx: {
|
|
3737
|
+
color: policy.permission === "*" ? "#16a34a" : policy.permission === "owner" ? "#0ea5e9" : "#dc2626"
|
|
3738
|
+
}, children: [
|
|
3739
|
+
t("modules.form.publicPolicies.fields.conditions.states.allow"),
|
|
3740
|
+
":"
|
|
3741
|
+
] }),
|
|
3742
|
+
" ",
|
|
3743
|
+
policy.permission || "-"
|
|
3744
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Stack, { spacing: 0.5, divider: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material9.Divider, { sx: { borderColor: "#e5e7eb" } }), children: [
|
|
3745
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
|
|
3746
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { component: "span", sx: { color: "#16a34a" }, children: [
|
|
3747
|
+
t("modules.form.publicPolicies.fields.conditions.states.allow"),
|
|
3748
|
+
":"
|
|
3749
|
+
] }),
|
|
3750
|
+
" ",
|
|
3751
|
+
(policy?.fields?.allow || []).join(", ") || "-"
|
|
3752
|
+
] }),
|
|
3753
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
|
|
3754
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { component: "span", sx: { color: "#0ea5e9" }, children: [
|
|
3755
|
+
t("modules.form.publicPolicies.fields.conditions.states.ownerAllow"),
|
|
3756
|
+
":"
|
|
3757
|
+
] }),
|
|
3758
|
+
" ",
|
|
3759
|
+
(policy?.fields?.owner_allow || []).join(", ") || "-"
|
|
3760
|
+
] }),
|
|
3761
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
|
|
3762
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material9.Box, { component: "span", sx: { color: "#dc2626" }, children: [
|
|
3763
|
+
t("modules.form.publicPolicies.fields.conditions.states.deny"),
|
|
3764
|
+
":"
|
|
3765
|
+
] }),
|
|
3766
|
+
" ",
|
|
3767
|
+
(policy?.fields?.deny || []).join(", ") || "-"
|
|
3768
|
+
] })
|
|
3769
|
+
] }) })
|
|
3770
|
+
] })
|
|
3771
|
+
]
|
|
3772
|
+
}
|
|
3773
|
+
);
|
|
3774
|
+
});
|
|
3775
|
+
var PolicyItem_default = PolicyItem;
|
|
3776
|
+
|
|
3777
|
+
// src/components/PublicPolicies/Policies.tsx
|
|
3778
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3779
|
+
var generateId = () => {
|
|
3780
|
+
const c = globalThis?.crypto;
|
|
3781
|
+
if (c && typeof c.randomUUID === "function") return c.randomUUID();
|
|
3782
|
+
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
3783
|
+
};
|
|
3784
|
+
var Policies = ({
|
|
3785
|
+
policies,
|
|
3786
|
+
onChange,
|
|
3787
|
+
availableFields,
|
|
3788
|
+
errors,
|
|
3789
|
+
isSubmitting = false
|
|
3790
|
+
}) => {
|
|
3791
|
+
const { t } = (0, import_react_i18next3.useTranslation)();
|
|
3792
|
+
const policyRefs = (0, import_react15.useRef)({});
|
|
3793
|
+
const takenActions = new Set((policies || []).map((p) => p.action).filter(Boolean));
|
|
3794
|
+
const remainingActions = PREFERRED_POLICY_ORDER.filter((a) => !takenActions.has(a));
|
|
3795
|
+
const canAddPolicy = remainingActions.length > 0;
|
|
3796
|
+
const addPolicy = () => {
|
|
3797
|
+
const defaultAction = remainingActions[0] || "create";
|
|
3798
|
+
const newPolicy = {
|
|
3799
|
+
id: generateId(),
|
|
3800
|
+
action: defaultAction
|
|
3801
|
+
};
|
|
3802
|
+
if (defaultAction === "delete") {
|
|
3803
|
+
newPolicy.permission = "deny";
|
|
3804
|
+
} else {
|
|
3805
|
+
newPolicy.fields = {
|
|
3806
|
+
allow: [],
|
|
3807
|
+
owner_allow: [],
|
|
3808
|
+
deny: availableFields
|
|
3809
|
+
};
|
|
3810
|
+
}
|
|
3811
|
+
const next = [...policies || [], newPolicy];
|
|
3812
|
+
onChange(next);
|
|
3813
|
+
setTimeout(() => {
|
|
3814
|
+
const newIndex = next.length - 1;
|
|
3815
|
+
const el = policyRefs.current[newIndex];
|
|
3816
|
+
if (el) {
|
|
3817
|
+
el.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
3818
|
+
}
|
|
3819
|
+
}, 100);
|
|
3820
|
+
};
|
|
3821
|
+
const removePolicy = (index) => {
|
|
3822
|
+
const next = [...policies];
|
|
3823
|
+
next.splice(index, 1);
|
|
3824
|
+
onChange(next);
|
|
3825
|
+
};
|
|
3826
|
+
const arrayError = (() => {
|
|
3827
|
+
if (!errors) return null;
|
|
3828
|
+
if (typeof errors === "string") return errors;
|
|
3829
|
+
const msg = errors._error;
|
|
3830
|
+
return typeof msg === "string" ? msg : null;
|
|
3831
|
+
})();
|
|
3832
|
+
const usedActions = new Set((policies || []).map((p) => p.action));
|
|
3833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
3834
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Divider, { sx: { borderColor: "#e0e4e7" } }),
|
|
3835
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { children: [
|
|
3836
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 3, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Box, { children: [
|
|
3837
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3838
|
+
import_material10.Typography,
|
|
3839
|
+
{
|
|
3840
|
+
variant: "h6",
|
|
3841
|
+
sx: {
|
|
3842
|
+
fontWeight: 600,
|
|
3843
|
+
color: "#111418",
|
|
3844
|
+
mb: 1
|
|
3845
|
+
},
|
|
3846
|
+
children: t("modules.form.publicPolicies.title")
|
|
3847
|
+
}
|
|
3848
|
+
),
|
|
3849
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3850
|
+
import_material10.Typography,
|
|
3851
|
+
{
|
|
3852
|
+
variant: "body2",
|
|
3853
|
+
color: "text.secondary",
|
|
3854
|
+
sx: { fontSize: "0.875rem" },
|
|
3855
|
+
children: t("modules.form.publicPolicies.description")
|
|
3856
|
+
}
|
|
3857
|
+
)
|
|
3858
|
+
] }) }),
|
|
3859
|
+
arrayError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Alert, { severity: "error", sx: { mb: 3 }, children: arrayError }),
|
|
3860
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material10.Stack, { spacing: 3, children: [
|
|
3861
|
+
(policies || []).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Alert, { severity: "info", children: t("modules.form.publicPolicies.noPolicies") }) : policies.map((policy, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3862
|
+
PolicyItem_default,
|
|
3863
|
+
{
|
|
3864
|
+
ref: (el) => {
|
|
3865
|
+
policyRefs.current[index] = el;
|
|
3866
|
+
},
|
|
3867
|
+
policy,
|
|
3868
|
+
onChange: (nextPolicy) => {
|
|
3869
|
+
const next = [...policies];
|
|
3870
|
+
next[index] = nextPolicy;
|
|
3871
|
+
onChange(next);
|
|
3872
|
+
},
|
|
3873
|
+
onRemove: () => removePolicy(index),
|
|
3874
|
+
availableFields,
|
|
3875
|
+
isSubmitting,
|
|
3876
|
+
usedActions,
|
|
3877
|
+
error: typeof errors === "object" && errors && policy.id in errors ? errors[policy.id] : void 0
|
|
3878
|
+
},
|
|
3879
|
+
policy.id
|
|
3880
|
+
)),
|
|
3881
|
+
canAddPolicy && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material10.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3882
|
+
import_material10.Button,
|
|
3883
|
+
{
|
|
3884
|
+
type: "button",
|
|
3885
|
+
variant: "outlined",
|
|
3886
|
+
startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material4.Add, {}),
|
|
3887
|
+
onClick: addPolicy,
|
|
3888
|
+
disabled: isSubmitting,
|
|
3889
|
+
sx: {
|
|
3890
|
+
borderColor: "#d0d7de",
|
|
3891
|
+
color: "#656d76",
|
|
3892
|
+
"&:hover": {
|
|
3893
|
+
borderColor: "#8c959f",
|
|
3894
|
+
backgroundColor: "transparent"
|
|
3895
|
+
}
|
|
3896
|
+
},
|
|
3897
|
+
children: t("modules.form.publicPolicies.addPolicy")
|
|
3898
|
+
}
|
|
3899
|
+
) })
|
|
3900
|
+
] })
|
|
3901
|
+
] })
|
|
3902
|
+
] });
|
|
3903
|
+
};
|
|
3904
|
+
var Policies_default = Policies;
|
|
3905
|
+
|
|
3906
|
+
// src/index.ts
|
|
3907
|
+
init_CrudifyDataProvider();
|
|
3908
|
+
|
|
3909
|
+
// src/hooks/useCrudifyUser.ts
|
|
3910
|
+
var import_react16 = require("react");
|
|
3911
|
+
var import_crudify_browser5 = __toESM(require("@nocios/crudify-browser"));
|
|
3912
|
+
init_CrudifyDataProvider();
|
|
3913
|
+
var useCrudifyUser = (options = {}) => {
|
|
3914
|
+
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
3915
|
+
const { isAuthenticated, isInitialized, user: jwtUser, token } = useCrudifyDataContext();
|
|
3916
|
+
const [userData, setUserData] = (0, import_react16.useState)(null);
|
|
3917
|
+
const [loading, setLoading] = (0, import_react16.useState)(false);
|
|
3918
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
3919
|
+
const abortControllerRef = (0, import_react16.useRef)(null);
|
|
3920
|
+
const mountedRef = (0, import_react16.useRef)(true);
|
|
3921
|
+
const requestIdRef = (0, import_react16.useRef)(0);
|
|
3922
|
+
const retryCountRef = (0, import_react16.useRef)(0);
|
|
3923
|
+
const getUserEmailFromJWT = (0, import_react16.useCallback)(() => {
|
|
3924
|
+
if (!jwtUser) return null;
|
|
3925
|
+
return jwtUser.email || jwtUser["cognito:username"] || null;
|
|
3926
|
+
}, [jwtUser]);
|
|
3927
|
+
const clearProfile = (0, import_react16.useCallback)(() => {
|
|
3928
|
+
setUserData(null);
|
|
3929
|
+
setError(null);
|
|
3930
|
+
setLoading(false);
|
|
3931
|
+
retryCountRef.current = 0;
|
|
3932
|
+
}, []);
|
|
3933
|
+
const refreshProfile = (0, import_react16.useCallback)(async () => {
|
|
3934
|
+
const userEmail = getUserEmailFromJWT();
|
|
3935
|
+
console.log("\u{1F464} useCrudifyUser - Refreshing profile for:", userEmail);
|
|
3936
|
+
if (!userEmail) {
|
|
3937
|
+
if (mountedRef.current) {
|
|
3938
|
+
setError("No user email available from JWT token");
|
|
3939
|
+
setLoading(false);
|
|
3940
|
+
}
|
|
3941
|
+
return;
|
|
3942
|
+
}
|
|
3943
|
+
if (!isInitialized) {
|
|
3944
|
+
if (mountedRef.current) {
|
|
3945
|
+
setError("Crudify not initialized");
|
|
3946
|
+
setLoading(false);
|
|
3947
|
+
}
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
if (abortControllerRef.current) {
|
|
3951
|
+
abortControllerRef.current.abort();
|
|
3952
|
+
}
|
|
3953
|
+
const abortController = new AbortController();
|
|
3954
|
+
abortControllerRef.current = abortController;
|
|
3955
|
+
const currentRequestId = ++requestIdRef.current;
|
|
3956
|
+
try {
|
|
3957
|
+
if (mountedRef.current) {
|
|
3958
|
+
setLoading(true);
|
|
3959
|
+
setError(null);
|
|
3960
|
+
}
|
|
3961
|
+
console.log("\u{1F464} useCrudifyUser - Fetching profile data from database");
|
|
3962
|
+
const response = await import_crudify_browser5.default.readItems("users", {
|
|
3963
|
+
filter: { email: userEmail },
|
|
3964
|
+
pagination: { limit: 1 }
|
|
3965
|
+
});
|
|
3966
|
+
console.log("\u{1F464} useCrudifyUser - Database response:", response);
|
|
3967
|
+
console.log("\u{1F464} useCrudifyUser - response.data:", response.data);
|
|
3968
|
+
console.log("\u{1F464} useCrudifyUser - response.data type:", typeof response.data);
|
|
3969
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
|
|
3970
|
+
let userData2 = null;
|
|
3971
|
+
if (response.success) {
|
|
3972
|
+
console.log("\u{1F464} useCrudifyUser - Processing successful response:", {
|
|
3973
|
+
dataType: typeof response.data,
|
|
3974
|
+
isArray: Array.isArray(response.data),
|
|
3975
|
+
hasResponse: !!response.data?.response,
|
|
3976
|
+
hasResponseData: !!response.data?.response?.data,
|
|
3977
|
+
responseDataType: typeof response.data?.response?.data
|
|
3978
|
+
});
|
|
3979
|
+
if (Array.isArray(response.data) && response.data.length > 0) {
|
|
3980
|
+
console.log("\u{1F464} useCrudifyUser - Found direct array format");
|
|
3981
|
+
userData2 = response.data[0];
|
|
3982
|
+
} else if (response.data?.response?.data) {
|
|
3983
|
+
console.log("\u{1F464} useCrudifyUser - Found nested response.data format");
|
|
3984
|
+
try {
|
|
3985
|
+
const rawData = response.data.response.data;
|
|
3986
|
+
console.log("\u{1F464} useCrudifyUser - Raw nested data:", rawData);
|
|
3987
|
+
console.log("\u{1F464} useCrudifyUser - Raw data type:", typeof rawData);
|
|
3988
|
+
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
3989
|
+
console.log("\u{1F464} useCrudifyUser - Parsed nested data:", parsedData);
|
|
3990
|
+
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
3991
|
+
userData2 = parsedData.items[0];
|
|
3992
|
+
console.log("\u{1F464} useCrudifyUser - Extracted user from nested items:", userData2);
|
|
3993
|
+
} else {
|
|
3994
|
+
console.log("\u{1F464} useCrudifyUser - No items found in parsed data or items array is empty");
|
|
3995
|
+
}
|
|
3996
|
+
} catch (parseError) {
|
|
3997
|
+
console.error("\u{1F464} useCrudifyUser - Error parsing nested response data:", parseError);
|
|
3998
|
+
}
|
|
3999
|
+
} else if (response.data && typeof response.data === "object") {
|
|
4000
|
+
console.log("\u{1F464} useCrudifyUser - Found object format, checking for items");
|
|
4001
|
+
if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
|
|
4002
|
+
console.log("\u{1F464} useCrudifyUser - Found items in object format");
|
|
4003
|
+
userData2 = response.data.items[0];
|
|
4004
|
+
} else {
|
|
4005
|
+
console.log("\u{1F464} useCrudifyUser - No items found in object format");
|
|
4006
|
+
}
|
|
4007
|
+
} else if (response.data?.data?.response?.data) {
|
|
4008
|
+
console.log("\u{1F464} useCrudifyUser - Found double-nested data.data.response.data format");
|
|
4009
|
+
try {
|
|
4010
|
+
const rawData = response.data.data.response.data;
|
|
4011
|
+
console.log("\u{1F464} useCrudifyUser - Raw double-nested data:", rawData);
|
|
4012
|
+
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
4013
|
+
console.log("\u{1F464} useCrudifyUser - Parsed double-nested data:", parsedData);
|
|
4014
|
+
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
4015
|
+
userData2 = parsedData.items[0];
|
|
4016
|
+
console.log("\u{1F464} useCrudifyUser - Extracted user from double-nested items:", userData2);
|
|
4017
|
+
}
|
|
4018
|
+
} catch (parseError) {
|
|
4019
|
+
console.error("\u{1F464} useCrudifyUser - Error parsing double-nested response data:", parseError);
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
if (userData2) {
|
|
4024
|
+
console.log("\u{1F464} useCrudifyUser - User data found:", userData2);
|
|
4025
|
+
setUserData(userData2);
|
|
4026
|
+
setError(null);
|
|
4027
|
+
retryCountRef.current = 0;
|
|
4028
|
+
console.log("\u{1F464} useCrudifyUser - Profile loaded successfully:", userData2);
|
|
4029
|
+
} else {
|
|
4030
|
+
setError("User profile not found in database");
|
|
4031
|
+
setUserData(null);
|
|
4032
|
+
console.warn("\u{1F464} useCrudifyUser - User not found for email:", userEmail);
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
} catch (err) {
|
|
4036
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
4037
|
+
const error2 = err;
|
|
4038
|
+
console.error("\u{1F464} useCrudifyUser - Error fetching profile:", error2);
|
|
4039
|
+
if (error2.name === "AbortError") {
|
|
4040
|
+
return;
|
|
4041
|
+
}
|
|
4042
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
|
|
4043
|
+
if (shouldRetry) {
|
|
4044
|
+
retryCountRef.current++;
|
|
4045
|
+
console.log(`\u{1F464} useCrudifyUser - Retrying profile fetch (${retryCountRef.current}/${maxRetries})`);
|
|
4046
|
+
setTimeout(() => {
|
|
4047
|
+
if (mountedRef.current) {
|
|
4048
|
+
refreshProfile();
|
|
4049
|
+
}
|
|
4050
|
+
}, 1e3 * retryCountRef.current);
|
|
4051
|
+
} else {
|
|
4052
|
+
setError("Failed to load user profile from database");
|
|
4053
|
+
setUserData(null);
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
} finally {
|
|
4057
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
4058
|
+
setLoading(false);
|
|
4059
|
+
}
|
|
4060
|
+
if (abortControllerRef.current === abortController) {
|
|
4061
|
+
abortControllerRef.current = null;
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
}, [isInitialized, getUserEmailFromJWT, retryOnError, maxRetries]);
|
|
4065
|
+
(0, import_react16.useEffect)(() => {
|
|
4066
|
+
if (autoFetch && isAuthenticated && isInitialized) {
|
|
4067
|
+
refreshProfile();
|
|
4068
|
+
} else if (!isAuthenticated) {
|
|
4069
|
+
clearProfile();
|
|
4070
|
+
}
|
|
3492
4071
|
}, [autoFetch, isAuthenticated, isInitialized, refreshProfile, clearProfile]);
|
|
3493
|
-
(0,
|
|
4072
|
+
(0, import_react16.useEffect)(() => {
|
|
3494
4073
|
mountedRef.current = true;
|
|
3495
4074
|
return () => {
|
|
3496
4075
|
mountedRef.current = false;
|
|
@@ -3514,7 +4093,7 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3514
4093
|
};
|
|
3515
4094
|
|
|
3516
4095
|
// src/hooks/useCrudifyData.ts
|
|
3517
|
-
var
|
|
4096
|
+
var import_react17 = require("react");
|
|
3518
4097
|
var import_crudify_browser6 = __toESM(require("@nocios/crudify-browser"));
|
|
3519
4098
|
init_CrudifyDataProvider();
|
|
3520
4099
|
var useCrudifyData = () => {
|
|
@@ -3523,10 +4102,10 @@ var useCrudifyData = () => {
|
|
|
3523
4102
|
isInitializing,
|
|
3524
4103
|
initializationError
|
|
3525
4104
|
} = useCrudifyDataContext();
|
|
3526
|
-
const isReady = (0,
|
|
4105
|
+
const isReady = (0, import_react17.useCallback)(() => {
|
|
3527
4106
|
return isInitialized && !initializationError && !isInitializing;
|
|
3528
4107
|
}, [isInitialized, initializationError, isInitializing]);
|
|
3529
|
-
const waitForReady = (0,
|
|
4108
|
+
const waitForReady = (0, import_react17.useCallback)(async () => {
|
|
3530
4109
|
if (isReady()) return;
|
|
3531
4110
|
if (initializationError) {
|
|
3532
4111
|
throw new Error(`Crudify initialization failed: ${initializationError}`);
|
|
@@ -3550,13 +4129,13 @@ var useCrudifyData = () => {
|
|
|
3550
4129
|
check();
|
|
3551
4130
|
});
|
|
3552
4131
|
}, [isReady, initializationError]);
|
|
3553
|
-
const ensureReady = (0,
|
|
4132
|
+
const ensureReady = (0, import_react17.useCallback)((operationName) => {
|
|
3554
4133
|
if (!isReady()) {
|
|
3555
4134
|
const error = initializationError ? `Crudify initialization failed: ${initializationError}` : isInitializing ? "Crudify is still initializing. Please wait." : "Crudify is not initialized";
|
|
3556
4135
|
throw new Error(`Cannot perform ${operationName}: ${error}`);
|
|
3557
4136
|
}
|
|
3558
4137
|
}, [isReady, initializationError, isInitializing]);
|
|
3559
|
-
const readItems = (0,
|
|
4138
|
+
const readItems = (0, import_react17.useCallback)(async (moduleKey, filter, options) => {
|
|
3560
4139
|
ensureReady("readItems");
|
|
3561
4140
|
console.log("\u{1F4CA} useCrudifyData - readItems called with:");
|
|
3562
4141
|
console.log(" - moduleKey:", moduleKey);
|
|
@@ -3575,7 +4154,7 @@ var useCrudifyData = () => {
|
|
|
3575
4154
|
throw error;
|
|
3576
4155
|
}
|
|
3577
4156
|
}, [ensureReady]);
|
|
3578
|
-
const readItem = (0,
|
|
4157
|
+
const readItem = (0, import_react17.useCallback)(async (moduleKey, filter, options) => {
|
|
3579
4158
|
ensureReady("readItem");
|
|
3580
4159
|
console.log("\u{1F4CA} useCrudifyData - readItem:", { moduleKey, filter, options });
|
|
3581
4160
|
try {
|
|
@@ -3587,7 +4166,7 @@ var useCrudifyData = () => {
|
|
|
3587
4166
|
throw error;
|
|
3588
4167
|
}
|
|
3589
4168
|
}, [ensureReady]);
|
|
3590
|
-
const createItem = (0,
|
|
4169
|
+
const createItem = (0, import_react17.useCallback)(async (moduleKey, data, options) => {
|
|
3591
4170
|
ensureReady("createItem");
|
|
3592
4171
|
console.log("\u{1F4CA} useCrudifyData - createItem:", { moduleKey, data, options });
|
|
3593
4172
|
try {
|
|
@@ -3599,7 +4178,7 @@ var useCrudifyData = () => {
|
|
|
3599
4178
|
throw error;
|
|
3600
4179
|
}
|
|
3601
4180
|
}, [ensureReady]);
|
|
3602
|
-
const updateItem = (0,
|
|
4181
|
+
const updateItem = (0, import_react17.useCallback)(async (moduleKey, data, options) => {
|
|
3603
4182
|
ensureReady("updateItem");
|
|
3604
4183
|
console.log("\u{1F4CA} useCrudifyData - updateItem:", { moduleKey, data, options });
|
|
3605
4184
|
try {
|
|
@@ -3611,7 +4190,7 @@ var useCrudifyData = () => {
|
|
|
3611
4190
|
throw error;
|
|
3612
4191
|
}
|
|
3613
4192
|
}, [ensureReady]);
|
|
3614
|
-
const deleteItem = (0,
|
|
4193
|
+
const deleteItem = (0, import_react17.useCallback)(async (moduleKey, id, options) => {
|
|
3615
4194
|
ensureReady("deleteItem");
|
|
3616
4195
|
console.log("\u{1F4CA} useCrudifyData - deleteItem:", { moduleKey, id, options });
|
|
3617
4196
|
try {
|
|
@@ -3623,7 +4202,7 @@ var useCrudifyData = () => {
|
|
|
3623
4202
|
throw error;
|
|
3624
4203
|
}
|
|
3625
4204
|
}, [ensureReady]);
|
|
3626
|
-
const transaction = (0,
|
|
4205
|
+
const transaction = (0, import_react17.useCallback)(async (operations, options) => {
|
|
3627
4206
|
ensureReady("transaction");
|
|
3628
4207
|
console.log("\u{1F4CA} useCrudifyData - transaction:", { operations, options });
|
|
3629
4208
|
try {
|
|
@@ -3635,7 +4214,7 @@ var useCrudifyData = () => {
|
|
|
3635
4214
|
throw error;
|
|
3636
4215
|
}
|
|
3637
4216
|
}, [ensureReady]);
|
|
3638
|
-
const login = (0,
|
|
4217
|
+
const login = (0, import_react17.useCallback)(async (email, password) => {
|
|
3639
4218
|
ensureReady("login");
|
|
3640
4219
|
console.log("\u{1F4CA} useCrudifyData - login:", { email });
|
|
3641
4220
|
try {
|
|
@@ -3668,7 +4247,7 @@ var useCrudifyData = () => {
|
|
|
3668
4247
|
};
|
|
3669
4248
|
|
|
3670
4249
|
// src/hooks/useCrudifyInstance.ts
|
|
3671
|
-
var
|
|
4250
|
+
var import_react18 = require("react");
|
|
3672
4251
|
var import_crudify_browser7 = __toESM(require("@nocios/crudify-browser"));
|
|
3673
4252
|
init_CrudifyDataProvider();
|
|
3674
4253
|
var useCrudifyInstance = () => {
|
|
@@ -3678,7 +4257,7 @@ var useCrudifyInstance = () => {
|
|
|
3678
4257
|
initializationError
|
|
3679
4258
|
} = useCrudifyDataContext();
|
|
3680
4259
|
const isReady = isInitialized && !initializationError && !isInitializing;
|
|
3681
|
-
const waitForReady = (0,
|
|
4260
|
+
const waitForReady = (0, import_react18.useCallback)(async () => {
|
|
3682
4261
|
console.log("\u{1F504} useCrudifyInstance - waitForReady: Starting wait");
|
|
3683
4262
|
console.log(" - isReady:", isReady);
|
|
3684
4263
|
console.log(" - isInitialized:", isInitialized);
|
|
@@ -3706,14 +4285,14 @@ var useCrudifyInstance = () => {
|
|
|
3706
4285
|
throw error;
|
|
3707
4286
|
}
|
|
3708
4287
|
}, [isReady, initializationError, isInitialized, isInitializing]);
|
|
3709
|
-
const ensureReady = (0,
|
|
4288
|
+
const ensureReady = (0, import_react18.useCallback)(async (operationName) => {
|
|
3710
4289
|
if (!isReady) {
|
|
3711
4290
|
console.log(`\u{1F504} useCrudifyInstance - ${operationName}: Waiting for crudify to be ready...`);
|
|
3712
4291
|
await waitForReady();
|
|
3713
4292
|
console.log(`\u2705 useCrudifyInstance - ${operationName}: Crudify is ready`);
|
|
3714
4293
|
}
|
|
3715
4294
|
}, [isReady, waitForReady]);
|
|
3716
|
-
const ensureTokenSync = (0,
|
|
4295
|
+
const ensureTokenSync = (0, import_react18.useCallback)(async () => {
|
|
3717
4296
|
console.log("\u{1F504} useCrudifyInstance - ensureTokenSync: Starting token sync check");
|
|
3718
4297
|
const { tokenManager: tokenManager2 } = await Promise.resolve().then(() => (init_TokenManager(), TokenManager_exports));
|
|
3719
4298
|
const tmToken = tokenManager2.getToken();
|
|
@@ -3726,1936 +4305,1357 @@ var useCrudifyInstance = () => {
|
|
|
3726
4305
|
console.log(" - crudify token after sync:", import_crudify_browser7.default.getToken?.() ? `${import_crudify_browser7.default.getToken?.()?.substring(0, 20)}...` : "null");
|
|
3727
4306
|
} else {
|
|
3728
4307
|
console.log("\u{1F504} useCrudifyInstance - No token sync needed, tokens match or no token");
|
|
3729
|
-
}
|
|
3730
|
-
}, []);
|
|
3731
|
-
const getStructure = (0,
|
|
3732
|
-
console.log("\u{1F4E1} useCrudifyInstance - getStructure: Starting");
|
|
3733
|
-
await ensureReady("getStructure");
|
|
3734
|
-
try {
|
|
3735
|
-
const { tokenManager: tokenManager2 } = await Promise.resolve().then(() => (init_TokenManager(), TokenManager_exports));
|
|
3736
|
-
const tmToken = tokenManager2.getToken();
|
|
3737
|
-
const crudifyToken = import_crudify_browser7.default.getToken?.();
|
|
3738
|
-
console.log("\u{1F510} useCrudifyInstance - getStructure: Token status check:");
|
|
3739
|
-
console.log(" - TokenManager token:", tmToken ? `${tmToken.substring(0, 20)}...` : "null");
|
|
3740
|
-
console.log(" - crudify.getToken():", crudifyToken ? `${crudifyToken.substring(0, 20)}...` : "null");
|
|
3741
|
-
console.log(" - Tokens match:", tmToken === crudifyToken);
|
|
3742
|
-
await ensureTokenSync();
|
|
3743
|
-
console.log("\u{1F4E1} useCrudifyInstance - getStructure: Calling crudify.getStructure");
|
|
3744
|
-
const response = await import_crudify_browser7.default.getStructure(options);
|
|
3745
|
-
console.log("\u{1F4E1} useCrudifyInstance - getStructure: Response received", response);
|
|
3746
|
-
return response;
|
|
3747
|
-
} catch (error) {
|
|
3748
|
-
console.error("\u{1F4E1} useCrudifyInstance - getStructure: Error", error);
|
|
3749
|
-
throw error;
|
|
3750
|
-
}
|
|
3751
|
-
}, [ensureReady, ensureTokenSync]);
|
|
3752
|
-
const getStructurePublic = (0, import_react15.useCallback)(async (options) => {
|
|
3753
|
-
console.log("\u{1F4E1} useCrudifyInstance - getStructurePublic: Starting");
|
|
3754
|
-
await ensureReady("getStructurePublic");
|
|
3755
|
-
try {
|
|
3756
|
-
console.log("\u{1F4E1} useCrudifyInstance - getStructurePublic: Calling crudify.getStructurePublic");
|
|
3757
|
-
const response = await import_crudify_browser7.default.getStructurePublic(options);
|
|
3758
|
-
console.log("\u{1F4E1} useCrudifyInstance - getStructurePublic: Response received", response);
|
|
3759
|
-
return response;
|
|
3760
|
-
} catch (error) {
|
|
3761
|
-
console.error("\u{1F4E1} useCrudifyInstance - getStructurePublic: Error", error);
|
|
3762
|
-
throw error;
|
|
3763
|
-
}
|
|
3764
|
-
}, [ensureReady]);
|
|
3765
|
-
const readItems = (0, import_react15.useCallback)(async (moduleKey, filter, options) => {
|
|
3766
|
-
await ensureReady("readItems");
|
|
3767
|
-
await ensureTokenSync();
|
|
3768
|
-
if (moduleKey === "__test_connection__") {
|
|
3769
|
-
console.error("\u{1F6A8} FOUND TEST CONNECTION CALL in useCrudifyInstance! Stack trace:");
|
|
3770
|
-
console.error(new Error().stack);
|
|
3771
|
-
}
|
|
3772
|
-
try {
|
|
3773
|
-
const response = await import_crudify_browser7.default.readItems(moduleKey, filter || {}, options);
|
|
3774
|
-
return response;
|
|
3775
|
-
} catch (error) {
|
|
3776
|
-
console.error("\u{1F4CA} useCrudifyInstance - readItems error:", error);
|
|
3777
|
-
throw error;
|
|
3778
|
-
}
|
|
3779
|
-
}, [ensureReady, ensureTokenSync]);
|
|
3780
|
-
const readItem = (0, import_react15.useCallback)(async (moduleKey, filter, options) => {
|
|
3781
|
-
await ensureReady("readItem");
|
|
3782
|
-
try {
|
|
3783
|
-
const response = await import_crudify_browser7.default.readItem(moduleKey, filter, options);
|
|
3784
|
-
return response;
|
|
3785
|
-
} catch (error) {
|
|
3786
|
-
console.error("\u{1F4CA} useCrudifyInstance - readItem error:", error);
|
|
3787
|
-
throw error;
|
|
3788
|
-
}
|
|
3789
|
-
}, [ensureReady]);
|
|
3790
|
-
const createItem = (0, import_react15.useCallback)(async (moduleKey, data, options) => {
|
|
3791
|
-
await ensureReady("createItem");
|
|
3792
|
-
try {
|
|
3793
|
-
const response = await import_crudify_browser7.default.createItem(moduleKey, data, options);
|
|
3794
|
-
return response;
|
|
3795
|
-
} catch (error) {
|
|
3796
|
-
console.error("\u{1F4CA} useCrudifyInstance - createItem error:", error);
|
|
3797
|
-
throw error;
|
|
3798
|
-
}
|
|
3799
|
-
}, [ensureReady]);
|
|
3800
|
-
const updateItem = (0, import_react15.useCallback)(async (moduleKey, data, options) => {
|
|
3801
|
-
await ensureReady("updateItem");
|
|
3802
|
-
try {
|
|
3803
|
-
const response = await import_crudify_browser7.default.updateItem(moduleKey, data, options);
|
|
3804
|
-
return response;
|
|
3805
|
-
} catch (error) {
|
|
3806
|
-
console.error("\u{1F4CA} useCrudifyInstance - updateItem error:", error);
|
|
3807
|
-
throw error;
|
|
3808
|
-
}
|
|
3809
|
-
}, [ensureReady]);
|
|
3810
|
-
const deleteItem = (0, import_react15.useCallback)(async (moduleKey, id, options) => {
|
|
3811
|
-
await ensureReady("deleteItem");
|
|
3812
|
-
try {
|
|
3813
|
-
const response = await import_crudify_browser7.default.deleteItem(moduleKey, id, options);
|
|
3814
|
-
return response;
|
|
3815
|
-
} catch (error) {
|
|
3816
|
-
console.error("\u{1F4CA} useCrudifyInstance - deleteItem error:", error);
|
|
3817
|
-
throw error;
|
|
3818
|
-
}
|
|
3819
|
-
}, [ensureReady]);
|
|
3820
|
-
const transaction = (0, import_react15.useCallback)(async (operations, options) => {
|
|
3821
|
-
await ensureReady("transaction");
|
|
3822
|
-
try {
|
|
3823
|
-
const response = await import_crudify_browser7.default.transaction(operations, options);
|
|
3824
|
-
return response;
|
|
3825
|
-
} catch (error) {
|
|
3826
|
-
console.error("\u{1F4CA} useCrudifyInstance - transaction error:", error);
|
|
3827
|
-
throw error;
|
|
3828
|
-
}
|
|
3829
|
-
}, [ensureReady]);
|
|
3830
|
-
const login = (0, import_react15.useCallback)(async (email, password) => {
|
|
3831
|
-
await ensureReady("login");
|
|
3832
|
-
try {
|
|
3833
|
-
const response = await import_crudify_browser7.default.login(email, password);
|
|
3834
|
-
return response;
|
|
3835
|
-
} catch (error) {
|
|
3836
|
-
console.error("\u{1F4CA} useCrudifyInstance - login error:", error);
|
|
3837
|
-
throw error;
|
|
3838
|
-
}
|
|
3839
|
-
}, [ensureReady]);
|
|
3840
|
-
return {
|
|
3841
|
-
// Core operations
|
|
3842
|
-
getStructure,
|
|
3843
|
-
getStructurePublic,
|
|
3844
|
-
readItems,
|
|
3845
|
-
readItem,
|
|
3846
|
-
createItem,
|
|
3847
|
-
updateItem,
|
|
3848
|
-
deleteItem,
|
|
3849
|
-
transaction,
|
|
3850
|
-
login,
|
|
3851
|
-
// State information
|
|
3852
|
-
isReady,
|
|
3853
|
-
isInitialized,
|
|
3854
|
-
isInitializing,
|
|
3855
|
-
initializationError,
|
|
3856
|
-
// Utility methods
|
|
3857
|
-
waitForReady
|
|
3858
|
-
};
|
|
3859
|
-
};
|
|
3860
|
-
var getCrudifyInstanceAsync = async () => {
|
|
3861
|
-
console.log("\u{1F504} getCrudifyInstanceAsync - Starting");
|
|
3862
|
-
const { crudifyInitializer: crudifyInitializer2 } = await Promise.resolve().then(() => (init_CrudifyDataProvider(), CrudifyDataProvider_exports));
|
|
3863
|
-
console.log("\u{1F504} getCrudifyInstanceAsync - Checking if ready");
|
|
3864
|
-
console.log(" - crudifyInitializer.isReady():", crudifyInitializer2.isReady());
|
|
3865
|
-
console.log(" - crudifyInitializer.getStatus():", crudifyInitializer2.getStatus());
|
|
3866
|
-
if (!crudifyInitializer2.isReady()) {
|
|
3867
|
-
console.log("\u{1F504} getCrudifyInstanceAsync - Waiting for crudify initialization...");
|
|
3868
|
-
await crudifyInitializer2.waitForInitialization();
|
|
3869
|
-
if (!crudifyInitializer2.isReady()) {
|
|
3870
|
-
const error = crudifyInitializer2.getError();
|
|
3871
|
-
throw new Error(`Crudify initialization failed: ${error || "Unknown error after waiting"}`);
|
|
3872
|
-
}
|
|
3873
|
-
console.log("\u2705 getCrudifyInstanceAsync - Crudify is ready after waiting");
|
|
3874
|
-
} else {
|
|
3875
|
-
console.log("\u2705 getCrudifyInstanceAsync - Already ready, no wait needed");
|
|
3876
|
-
}
|
|
3877
|
-
console.log("\u2705 getCrudifyInstanceAsync - Returning crudify instance");
|
|
3878
|
-
return import_crudify_browser7.default;
|
|
3879
|
-
};
|
|
3880
|
-
var getCrudifyInstanceSync = async () => {
|
|
3881
|
-
const { crudifyInitializer: crudifyInitializer2 } = await Promise.resolve().then(() => (init_CrudifyDataProvider(), CrudifyDataProvider_exports));
|
|
3882
|
-
if (!crudifyInitializer2.isReady()) {
|
|
3883
|
-
throw new Error("Crudify not ready. Use getCrudifyInstanceAsync() or call this from within a React component using useCrudifyInstance()");
|
|
3884
|
-
}
|
|
3885
|
-
return import_crudify_browser7.default;
|
|
3886
|
-
};
|
|
3887
|
-
|
|
3888
|
-
// src/index.ts
|
|
3889
|
-
init_CrudifyDataProvider();
|
|
3890
|
-
init_jwtUtils();
|
|
3891
|
-
init_cookies();
|
|
3892
|
-
init_secureStorage();
|
|
3893
|
-
|
|
3894
|
-
// src/core/SessionManager.ts
|
|
3895
|
-
var import_crudify_browser8 = __toESM(require("@nocios/crudify-browser"));
|
|
3896
|
-
|
|
3897
|
-
// src/utils/tokenStorage.ts
|
|
3898
|
-
var import_crypto_js2 = __toESM(require("crypto-js"));
|
|
3899
|
-
var _TokenStorage = class _TokenStorage {
|
|
3900
|
-
/**
|
|
3901
|
-
* Configurar tipo de almacenamiento
|
|
3902
|
-
*/
|
|
3903
|
-
static setStorageType(type) {
|
|
3904
|
-
_TokenStorage.storageType = type;
|
|
3905
|
-
}
|
|
3906
|
-
/**
|
|
3907
|
-
* Verificar si el storage está disponible
|
|
3908
|
-
*/
|
|
3909
|
-
static isStorageAvailable(type) {
|
|
3910
|
-
try {
|
|
3911
|
-
const storage = window[type];
|
|
3912
|
-
const testKey = "__storage_test__";
|
|
3913
|
-
storage.setItem(testKey, "test");
|
|
3914
|
-
storage.removeItem(testKey);
|
|
3915
|
-
return true;
|
|
3916
|
-
} catch {
|
|
3917
|
-
return false;
|
|
3918
|
-
}
|
|
3919
|
-
}
|
|
3920
|
-
/**
|
|
3921
|
-
* Obtener instancia de storage
|
|
3922
|
-
*/
|
|
3923
|
-
static getStorage() {
|
|
3924
|
-
if (_TokenStorage.storageType === "none") return null;
|
|
3925
|
-
if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
|
|
3926
|
-
console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
|
|
3927
|
-
return null;
|
|
3928
|
-
}
|
|
3929
|
-
return window[_TokenStorage.storageType];
|
|
3930
|
-
}
|
|
3931
|
-
/**
|
|
3932
|
-
* Encriptar datos sensibles
|
|
3933
|
-
*/
|
|
3934
|
-
static encrypt(data) {
|
|
4308
|
+
}
|
|
4309
|
+
}, []);
|
|
4310
|
+
const getStructure = (0, import_react18.useCallback)(async (options) => {
|
|
4311
|
+
console.log("\u{1F4E1} useCrudifyInstance - getStructure: Starting");
|
|
4312
|
+
await ensureReady("getStructure");
|
|
3935
4313
|
try {
|
|
3936
|
-
|
|
4314
|
+
const { tokenManager: tokenManager2 } = await Promise.resolve().then(() => (init_TokenManager(), TokenManager_exports));
|
|
4315
|
+
const tmToken = tokenManager2.getToken();
|
|
4316
|
+
const crudifyToken = import_crudify_browser7.default.getToken?.();
|
|
4317
|
+
console.log("\u{1F510} useCrudifyInstance - getStructure: Token status check:");
|
|
4318
|
+
console.log(" - TokenManager token:", tmToken ? `${tmToken.substring(0, 20)}...` : "null");
|
|
4319
|
+
console.log(" - crudify.getToken():", crudifyToken ? `${crudifyToken.substring(0, 20)}...` : "null");
|
|
4320
|
+
console.log(" - Tokens match:", tmToken === crudifyToken);
|
|
4321
|
+
await ensureTokenSync();
|
|
4322
|
+
console.log("\u{1F4E1} useCrudifyInstance - getStructure: Calling crudify.getStructure");
|
|
4323
|
+
const response = await import_crudify_browser7.default.getStructure(options);
|
|
4324
|
+
console.log("\u{1F4E1} useCrudifyInstance - getStructure: Response received", response);
|
|
4325
|
+
return response;
|
|
3937
4326
|
} catch (error) {
|
|
3938
|
-
console.error("
|
|
3939
|
-
|
|
4327
|
+
console.error("\u{1F4E1} useCrudifyInstance - getStructure: Error", error);
|
|
4328
|
+
throw error;
|
|
3940
4329
|
}
|
|
3941
|
-
}
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
static decrypt(encryptedData) {
|
|
4330
|
+
}, [ensureReady, ensureTokenSync]);
|
|
4331
|
+
const getStructurePublic = (0, import_react18.useCallback)(async (options) => {
|
|
4332
|
+
console.log("\u{1F4E1} useCrudifyInstance - getStructurePublic: Starting");
|
|
4333
|
+
await ensureReady("getStructurePublic");
|
|
3946
4334
|
try {
|
|
3947
|
-
|
|
3948
|
-
const
|
|
3949
|
-
|
|
4335
|
+
console.log("\u{1F4E1} useCrudifyInstance - getStructurePublic: Calling crudify.getStructurePublic");
|
|
4336
|
+
const response = await import_crudify_browser7.default.getStructurePublic(options);
|
|
4337
|
+
console.log("\u{1F4E1} useCrudifyInstance - getStructurePublic: Response received", response);
|
|
4338
|
+
return response;
|
|
3950
4339
|
} catch (error) {
|
|
3951
|
-
console.error("
|
|
3952
|
-
|
|
4340
|
+
console.error("\u{1F4E1} useCrudifyInstance - getStructurePublic: Error", error);
|
|
4341
|
+
throw error;
|
|
4342
|
+
}
|
|
4343
|
+
}, [ensureReady]);
|
|
4344
|
+
const readItems = (0, import_react18.useCallback)(async (moduleKey, filter, options) => {
|
|
4345
|
+
await ensureReady("readItems");
|
|
4346
|
+
await ensureTokenSync();
|
|
4347
|
+
if (moduleKey === "__test_connection__") {
|
|
4348
|
+
console.error("\u{1F6A8} FOUND TEST CONNECTION CALL in useCrudifyInstance! Stack trace:");
|
|
4349
|
+
console.error(new Error().stack);
|
|
3953
4350
|
}
|
|
3954
|
-
}
|
|
3955
|
-
/**
|
|
3956
|
-
* Guardar tokens de forma segura
|
|
3957
|
-
*/
|
|
3958
|
-
static saveTokens(tokens) {
|
|
3959
|
-
const storage = _TokenStorage.getStorage();
|
|
3960
|
-
if (!storage) return;
|
|
3961
4351
|
try {
|
|
3962
|
-
const
|
|
3963
|
-
|
|
3964
|
-
refreshToken: tokens.refreshToken,
|
|
3965
|
-
expiresAt: tokens.expiresAt,
|
|
3966
|
-
refreshExpiresAt: tokens.refreshExpiresAt,
|
|
3967
|
-
savedAt: Date.now()
|
|
3968
|
-
};
|
|
3969
|
-
const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
|
|
3970
|
-
storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
|
|
3971
|
-
console.debug("Crudify: Tokens saved successfully");
|
|
4352
|
+
const response = await import_crudify_browser7.default.readItems(moduleKey, filter || {}, options);
|
|
4353
|
+
return response;
|
|
3972
4354
|
} catch (error) {
|
|
3973
|
-
console.error("
|
|
4355
|
+
console.error("\u{1F4CA} useCrudifyInstance - readItems error:", error);
|
|
4356
|
+
throw error;
|
|
3974
4357
|
}
|
|
3975
|
-
}
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
*/
|
|
3979
|
-
static getTokens() {
|
|
3980
|
-
const storage = _TokenStorage.getStorage();
|
|
3981
|
-
if (!storage) return null;
|
|
4358
|
+
}, [ensureReady, ensureTokenSync]);
|
|
4359
|
+
const readItem = (0, import_react18.useCallback)(async (moduleKey, filter, options) => {
|
|
4360
|
+
await ensureReady("readItem");
|
|
3982
4361
|
try {
|
|
3983
|
-
const
|
|
3984
|
-
|
|
3985
|
-
const decrypted = _TokenStorage.decrypt(encrypted);
|
|
3986
|
-
const tokenData = JSON.parse(decrypted);
|
|
3987
|
-
if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
|
|
3988
|
-
console.warn("Crudify: Incomplete token data found, clearing storage");
|
|
3989
|
-
_TokenStorage.clearTokens();
|
|
3990
|
-
return null;
|
|
3991
|
-
}
|
|
3992
|
-
if (Date.now() >= tokenData.refreshExpiresAt) {
|
|
3993
|
-
console.info("Crudify: Refresh token expired, clearing storage");
|
|
3994
|
-
_TokenStorage.clearTokens();
|
|
3995
|
-
return null;
|
|
3996
|
-
}
|
|
3997
|
-
return {
|
|
3998
|
-
accessToken: tokenData.accessToken,
|
|
3999
|
-
refreshToken: tokenData.refreshToken,
|
|
4000
|
-
expiresAt: tokenData.expiresAt,
|
|
4001
|
-
refreshExpiresAt: tokenData.refreshExpiresAt
|
|
4002
|
-
};
|
|
4362
|
+
const response = await import_crudify_browser7.default.readItem(moduleKey, filter, options);
|
|
4363
|
+
return response;
|
|
4003
4364
|
} catch (error) {
|
|
4004
|
-
console.error("
|
|
4005
|
-
|
|
4006
|
-
return null;
|
|
4365
|
+
console.error("\u{1F4CA} useCrudifyInstance - readItem error:", error);
|
|
4366
|
+
throw error;
|
|
4007
4367
|
}
|
|
4008
|
-
}
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
*/
|
|
4012
|
-
static clearTokens() {
|
|
4013
|
-
const storage = _TokenStorage.getStorage();
|
|
4014
|
-
if (!storage) return;
|
|
4368
|
+
}, [ensureReady]);
|
|
4369
|
+
const createItem = (0, import_react18.useCallback)(async (moduleKey, data, options) => {
|
|
4370
|
+
await ensureReady("createItem");
|
|
4015
4371
|
try {
|
|
4016
|
-
|
|
4017
|
-
|
|
4372
|
+
const response = await import_crudify_browser7.default.createItem(moduleKey, data, options);
|
|
4373
|
+
return response;
|
|
4018
4374
|
} catch (error) {
|
|
4019
|
-
console.error("
|
|
4020
|
-
|
|
4021
|
-
}
|
|
4022
|
-
/**
|
|
4023
|
-
* Verificar si hay tokens válidos guardados
|
|
4024
|
-
*/
|
|
4025
|
-
static hasValidTokens() {
|
|
4026
|
-
const tokens = _TokenStorage.getTokens();
|
|
4027
|
-
return tokens !== null;
|
|
4028
|
-
}
|
|
4029
|
-
/**
|
|
4030
|
-
* Obtener información de expiración
|
|
4031
|
-
*/
|
|
4032
|
-
static getExpirationInfo() {
|
|
4033
|
-
const tokens = _TokenStorage.getTokens();
|
|
4034
|
-
if (!tokens) return null;
|
|
4035
|
-
const now = Date.now();
|
|
4036
|
-
return {
|
|
4037
|
-
accessExpired: now >= tokens.expiresAt,
|
|
4038
|
-
refreshExpired: now >= tokens.refreshExpiresAt,
|
|
4039
|
-
accessExpiresIn: Math.max(0, tokens.expiresAt - now),
|
|
4040
|
-
refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
|
|
4041
|
-
};
|
|
4042
|
-
}
|
|
4043
|
-
/**
|
|
4044
|
-
* Actualizar solo el access token (después de refresh)
|
|
4045
|
-
*/
|
|
4046
|
-
static updateAccessToken(newAccessToken, newExpiresAt) {
|
|
4047
|
-
const existingTokens = _TokenStorage.getTokens();
|
|
4048
|
-
if (!existingTokens) {
|
|
4049
|
-
console.warn("Crudify: Cannot update access token, no existing tokens found");
|
|
4050
|
-
return;
|
|
4051
|
-
}
|
|
4052
|
-
_TokenStorage.saveTokens({
|
|
4053
|
-
...existingTokens,
|
|
4054
|
-
accessToken: newAccessToken,
|
|
4055
|
-
expiresAt: newExpiresAt
|
|
4056
|
-
});
|
|
4057
|
-
}
|
|
4058
|
-
};
|
|
4059
|
-
_TokenStorage.TOKEN_KEY = "crudify_tokens";
|
|
4060
|
-
_TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
|
|
4061
|
-
_TokenStorage.storageType = "localStorage";
|
|
4062
|
-
var TokenStorage = _TokenStorage;
|
|
4063
|
-
|
|
4064
|
-
// src/core/SessionManager.ts
|
|
4065
|
-
var SessionManager = class _SessionManager {
|
|
4066
|
-
constructor() {
|
|
4067
|
-
this.config = {};
|
|
4068
|
-
this.initialized = false;
|
|
4069
|
-
}
|
|
4070
|
-
static getInstance() {
|
|
4071
|
-
if (!_SessionManager.instance) {
|
|
4072
|
-
_SessionManager.instance = new _SessionManager();
|
|
4073
|
-
}
|
|
4074
|
-
return _SessionManager.instance;
|
|
4075
|
-
}
|
|
4076
|
-
/**
|
|
4077
|
-
* Inicializar el SessionManager
|
|
4078
|
-
*/
|
|
4079
|
-
async initialize(config = {}) {
|
|
4080
|
-
if (this.initialized) {
|
|
4081
|
-
console.warn("SessionManager: Already initialized");
|
|
4082
|
-
return;
|
|
4083
|
-
}
|
|
4084
|
-
this.config = {
|
|
4085
|
-
storageType: "localStorage",
|
|
4086
|
-
autoRestore: true,
|
|
4087
|
-
enableLogging: false,
|
|
4088
|
-
...config
|
|
4089
|
-
};
|
|
4090
|
-
TokenStorage.setStorageType(this.config.storageType || "localStorage");
|
|
4091
|
-
if (this.config.enableLogging) {
|
|
4375
|
+
console.error("\u{1F4CA} useCrudifyInstance - createItem error:", error);
|
|
4376
|
+
throw error;
|
|
4092
4377
|
}
|
|
4093
|
-
|
|
4094
|
-
|
|
4378
|
+
}, [ensureReady]);
|
|
4379
|
+
const updateItem = (0, import_react18.useCallback)(async (moduleKey, data, options) => {
|
|
4380
|
+
await ensureReady("updateItem");
|
|
4381
|
+
try {
|
|
4382
|
+
const response = await import_crudify_browser7.default.updateItem(moduleKey, data, options);
|
|
4383
|
+
return response;
|
|
4384
|
+
} catch (error) {
|
|
4385
|
+
console.error("\u{1F4CA} useCrudifyInstance - updateItem error:", error);
|
|
4386
|
+
throw error;
|
|
4095
4387
|
}
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
/**
|
|
4100
|
-
* Login con persistencia automática
|
|
4101
|
-
*/
|
|
4102
|
-
async login(email, password) {
|
|
4388
|
+
}, [ensureReady]);
|
|
4389
|
+
const deleteItem = (0, import_react18.useCallback)(async (moduleKey, id, options) => {
|
|
4390
|
+
await ensureReady("deleteItem");
|
|
4103
4391
|
try {
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
if (!response.success) {
|
|
4107
|
-
this.log("Login failed:", response.errors);
|
|
4108
|
-
return {
|
|
4109
|
-
success: false,
|
|
4110
|
-
error: this.formatError(response.errors)
|
|
4111
|
-
};
|
|
4112
|
-
}
|
|
4113
|
-
const tokens = {
|
|
4114
|
-
accessToken: response.data.token,
|
|
4115
|
-
refreshToken: response.data.refreshToken,
|
|
4116
|
-
expiresAt: response.data.expiresAt,
|
|
4117
|
-
refreshExpiresAt: response.data.refreshExpiresAt
|
|
4118
|
-
};
|
|
4119
|
-
TokenStorage.saveTokens(tokens);
|
|
4120
|
-
this.log("Login successful, tokens saved");
|
|
4121
|
-
this.config.onLoginSuccess?.(tokens);
|
|
4122
|
-
return {
|
|
4123
|
-
success: true,
|
|
4124
|
-
tokens
|
|
4125
|
-
};
|
|
4392
|
+
const response = await import_crudify_browser7.default.deleteItem(moduleKey, id, options);
|
|
4393
|
+
return response;
|
|
4126
4394
|
} catch (error) {
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
success: false,
|
|
4130
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
4131
|
-
};
|
|
4395
|
+
console.error("\u{1F4CA} useCrudifyInstance - deleteItem error:", error);
|
|
4396
|
+
throw error;
|
|
4132
4397
|
}
|
|
4133
|
-
}
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
*/
|
|
4137
|
-
async logout() {
|
|
4398
|
+
}, [ensureReady]);
|
|
4399
|
+
const transaction = (0, import_react18.useCallback)(async (operations, options) => {
|
|
4400
|
+
await ensureReady("transaction");
|
|
4138
4401
|
try {
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
TokenStorage.clearTokens();
|
|
4142
|
-
this.log("Logout successful");
|
|
4143
|
-
this.config.onLogout?.();
|
|
4402
|
+
const response = await import_crudify_browser7.default.transaction(operations, options);
|
|
4403
|
+
return response;
|
|
4144
4404
|
} catch (error) {
|
|
4145
|
-
|
|
4146
|
-
|
|
4405
|
+
console.error("\u{1F4CA} useCrudifyInstance - transaction error:", error);
|
|
4406
|
+
throw error;
|
|
4147
4407
|
}
|
|
4148
|
-
}
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
*/
|
|
4152
|
-
async restoreSession() {
|
|
4408
|
+
}, [ensureReady]);
|
|
4409
|
+
const login = (0, import_react18.useCallback)(async (email, password) => {
|
|
4410
|
+
await ensureReady("login");
|
|
4153
4411
|
try {
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
if (!savedTokens) {
|
|
4157
|
-
this.log("No valid tokens found in storage");
|
|
4158
|
-
return false;
|
|
4159
|
-
}
|
|
4160
|
-
import_crudify_browser8.default.setTokens({
|
|
4161
|
-
accessToken: savedTokens.accessToken,
|
|
4162
|
-
refreshToken: savedTokens.refreshToken,
|
|
4163
|
-
expiresAt: savedTokens.expiresAt,
|
|
4164
|
-
refreshExpiresAt: savedTokens.refreshExpiresAt
|
|
4165
|
-
});
|
|
4166
|
-
this.log("Session restored successfully");
|
|
4167
|
-
this.config.onSessionRestored?.(savedTokens);
|
|
4168
|
-
return true;
|
|
4412
|
+
const response = await import_crudify_browser7.default.login(email, password);
|
|
4413
|
+
return response;
|
|
4169
4414
|
} catch (error) {
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4415
|
+
console.error("\u{1F4CA} useCrudifyInstance - login error:", error);
|
|
4416
|
+
throw error;
|
|
4417
|
+
}
|
|
4418
|
+
}, [ensureReady]);
|
|
4419
|
+
return {
|
|
4420
|
+
// Core operations
|
|
4421
|
+
getStructure,
|
|
4422
|
+
getStructurePublic,
|
|
4423
|
+
readItems,
|
|
4424
|
+
readItem,
|
|
4425
|
+
createItem,
|
|
4426
|
+
updateItem,
|
|
4427
|
+
deleteItem,
|
|
4428
|
+
transaction,
|
|
4429
|
+
login,
|
|
4430
|
+
// State information
|
|
4431
|
+
isReady,
|
|
4432
|
+
isInitialized,
|
|
4433
|
+
isInitializing,
|
|
4434
|
+
initializationError,
|
|
4435
|
+
// Utility methods
|
|
4436
|
+
waitForReady
|
|
4437
|
+
};
|
|
4438
|
+
};
|
|
4439
|
+
var getCrudifyInstanceAsync = async () => {
|
|
4440
|
+
console.log("\u{1F504} getCrudifyInstanceAsync - Starting");
|
|
4441
|
+
const { crudifyInitializer: crudifyInitializer2 } = await Promise.resolve().then(() => (init_CrudifyDataProvider(), CrudifyDataProvider_exports));
|
|
4442
|
+
console.log("\u{1F504} getCrudifyInstanceAsync - Checking if ready");
|
|
4443
|
+
console.log(" - crudifyInitializer.isReady():", crudifyInitializer2.isReady());
|
|
4444
|
+
console.log(" - crudifyInitializer.getStatus():", crudifyInitializer2.getStatus());
|
|
4445
|
+
if (!crudifyInitializer2.isReady()) {
|
|
4446
|
+
console.log("\u{1F504} getCrudifyInstanceAsync - Waiting for crudify initialization...");
|
|
4447
|
+
await crudifyInitializer2.waitForInitialization();
|
|
4448
|
+
if (!crudifyInitializer2.isReady()) {
|
|
4449
|
+
const error = crudifyInitializer2.getError();
|
|
4450
|
+
throw new Error(`Crudify initialization failed: ${error || "Unknown error after waiting"}`);
|
|
4173
4451
|
}
|
|
4452
|
+
console.log("\u2705 getCrudifyInstanceAsync - Crudify is ready after waiting");
|
|
4453
|
+
} else {
|
|
4454
|
+
console.log("\u2705 getCrudifyInstanceAsync - Already ready, no wait needed");
|
|
4174
4455
|
}
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4456
|
+
console.log("\u2705 getCrudifyInstanceAsync - Returning crudify instance");
|
|
4457
|
+
return import_crudify_browser7.default;
|
|
4458
|
+
};
|
|
4459
|
+
var getCrudifyInstanceSync = async () => {
|
|
4460
|
+
const { crudifyInitializer: crudifyInitializer2 } = await Promise.resolve().then(() => (init_CrudifyDataProvider(), CrudifyDataProvider_exports));
|
|
4461
|
+
if (!crudifyInitializer2.isReady()) {
|
|
4462
|
+
throw new Error("Crudify not ready. Use getCrudifyInstanceAsync() or call this from within a React component using useCrudifyInstance()");
|
|
4180
4463
|
}
|
|
4464
|
+
return import_crudify_browser7.default;
|
|
4465
|
+
};
|
|
4466
|
+
|
|
4467
|
+
// src/index.ts
|
|
4468
|
+
init_CrudifyDataProvider();
|
|
4469
|
+
init_jwtUtils();
|
|
4470
|
+
init_cookies();
|
|
4471
|
+
init_secureStorage();
|
|
4472
|
+
|
|
4473
|
+
// src/core/SessionManager.ts
|
|
4474
|
+
var import_crudify_browser8 = __toESM(require("@nocios/crudify-browser"));
|
|
4475
|
+
|
|
4476
|
+
// src/utils/tokenStorage.ts
|
|
4477
|
+
var import_crypto_js2 = __toESM(require("crypto-js"));
|
|
4478
|
+
var _TokenStorage = class _TokenStorage {
|
|
4181
4479
|
/**
|
|
4182
|
-
*
|
|
4480
|
+
* Configurar tipo de almacenamiento
|
|
4183
4481
|
*/
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
const storageInfo = TokenStorage.getExpirationInfo();
|
|
4187
|
-
return {
|
|
4188
|
-
isLoggedIn: this.isAuthenticated(),
|
|
4189
|
-
crudifyTokens,
|
|
4190
|
-
storageInfo,
|
|
4191
|
-
hasValidTokens: TokenStorage.hasValidTokens()
|
|
4192
|
-
};
|
|
4482
|
+
static setStorageType(type) {
|
|
4483
|
+
_TokenStorage.storageType = type;
|
|
4193
4484
|
}
|
|
4194
4485
|
/**
|
|
4195
|
-
*
|
|
4486
|
+
* Verificar si el storage está disponible
|
|
4196
4487
|
*/
|
|
4197
|
-
|
|
4488
|
+
static isStorageAvailable(type) {
|
|
4198
4489
|
try {
|
|
4199
|
-
|
|
4200
|
-
const
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
TokenStorage.clearTokens();
|
|
4204
|
-
this.config.onSessionExpired?.();
|
|
4205
|
-
return false;
|
|
4206
|
-
}
|
|
4207
|
-
const newTokens = {
|
|
4208
|
-
accessToken: response.data.token,
|
|
4209
|
-
refreshToken: response.data.refreshToken,
|
|
4210
|
-
expiresAt: response.data.expiresAt,
|
|
4211
|
-
refreshExpiresAt: response.data.refreshExpiresAt
|
|
4212
|
-
};
|
|
4213
|
-
TokenStorage.saveTokens(newTokens);
|
|
4214
|
-
this.log("Tokens refreshed and saved successfully");
|
|
4490
|
+
const storage = window[type];
|
|
4491
|
+
const testKey = "__storage_test__";
|
|
4492
|
+
storage.setItem(testKey, "test");
|
|
4493
|
+
storage.removeItem(testKey);
|
|
4215
4494
|
return true;
|
|
4216
|
-
} catch
|
|
4217
|
-
this.log("Token refresh error:", error);
|
|
4218
|
-
TokenStorage.clearTokens();
|
|
4219
|
-
this.config.onSessionExpired?.();
|
|
4495
|
+
} catch {
|
|
4220
4496
|
return false;
|
|
4221
4497
|
}
|
|
4222
4498
|
}
|
|
4223
4499
|
/**
|
|
4224
|
-
*
|
|
4225
|
-
*/
|
|
4226
|
-
setupResponseInterceptor() {
|
|
4227
|
-
import_crudify_browser8.default.setResponseInterceptor(async (response) => {
|
|
4228
|
-
if (response.errors) {
|
|
4229
|
-
const hasAuthError = response.errors.some(
|
|
4230
|
-
(error) => error.message?.includes("Unauthorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED"
|
|
4231
|
-
);
|
|
4232
|
-
if (hasAuthError && TokenStorage.hasValidTokens()) {
|
|
4233
|
-
this.log("Auth error detected, attempting token refresh...");
|
|
4234
|
-
const refreshSuccess = await this.refreshTokens();
|
|
4235
|
-
if (!refreshSuccess) {
|
|
4236
|
-
this.log("Session expired, triggering callback");
|
|
4237
|
-
this.config.onSessionExpired?.();
|
|
4238
|
-
}
|
|
4239
|
-
}
|
|
4240
|
-
}
|
|
4241
|
-
return response;
|
|
4242
|
-
});
|
|
4243
|
-
this.log("Response interceptor configured");
|
|
4244
|
-
}
|
|
4245
|
-
/**
|
|
4246
|
-
* Limpiar sesión completamente
|
|
4500
|
+
* Obtener instancia de storage
|
|
4247
4501
|
*/
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
// Métodos privados
|
|
4254
|
-
log(message, ...args) {
|
|
4255
|
-
if (this.config.enableLogging) {
|
|
4256
|
-
console.log(`[SessionManager] ${message}`, ...args);
|
|
4257
|
-
}
|
|
4258
|
-
}
|
|
4259
|
-
formatError(errors) {
|
|
4260
|
-
if (!errors) return "Unknown error";
|
|
4261
|
-
if (typeof errors === "string") return errors;
|
|
4262
|
-
if (typeof errors === "object") {
|
|
4263
|
-
const errorMessages = Object.values(errors).flat();
|
|
4264
|
-
return errorMessages.join(", ");
|
|
4502
|
+
static getStorage() {
|
|
4503
|
+
if (_TokenStorage.storageType === "none") return null;
|
|
4504
|
+
if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
|
|
4505
|
+
console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
|
|
4506
|
+
return null;
|
|
4265
4507
|
}
|
|
4266
|
-
return
|
|
4508
|
+
return window[_TokenStorage.storageType];
|
|
4267
4509
|
}
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
isAuthenticated: false,
|
|
4275
|
-
isLoading: true,
|
|
4276
|
-
isInitialized: false,
|
|
4277
|
-
tokens: null,
|
|
4278
|
-
error: null
|
|
4279
|
-
});
|
|
4280
|
-
const sessionManager = SessionManager.getInstance();
|
|
4281
|
-
const initialize = (0, import_react16.useCallback)(async () => {
|
|
4282
|
-
try {
|
|
4283
|
-
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
4284
|
-
const config = {
|
|
4285
|
-
autoRestore: options.autoRestore ?? true,
|
|
4286
|
-
enableLogging: options.enableLogging ?? false,
|
|
4287
|
-
onSessionExpired: () => {
|
|
4288
|
-
setState((prev) => ({
|
|
4289
|
-
...prev,
|
|
4290
|
-
isAuthenticated: false,
|
|
4291
|
-
tokens: null,
|
|
4292
|
-
error: "Session expired"
|
|
4293
|
-
}));
|
|
4294
|
-
options.onSessionExpired?.();
|
|
4295
|
-
},
|
|
4296
|
-
onSessionRestored: (tokens) => {
|
|
4297
|
-
setState((prev) => ({
|
|
4298
|
-
...prev,
|
|
4299
|
-
isAuthenticated: true,
|
|
4300
|
-
tokens,
|
|
4301
|
-
error: null
|
|
4302
|
-
}));
|
|
4303
|
-
options.onSessionRestored?.(tokens);
|
|
4304
|
-
},
|
|
4305
|
-
onLoginSuccess: (tokens) => {
|
|
4306
|
-
setState((prev) => ({
|
|
4307
|
-
...prev,
|
|
4308
|
-
isAuthenticated: true,
|
|
4309
|
-
tokens,
|
|
4310
|
-
error: null
|
|
4311
|
-
}));
|
|
4312
|
-
},
|
|
4313
|
-
onLogout: () => {
|
|
4314
|
-
setState((prev) => ({
|
|
4315
|
-
...prev,
|
|
4316
|
-
isAuthenticated: false,
|
|
4317
|
-
tokens: null,
|
|
4318
|
-
error: null
|
|
4319
|
-
}));
|
|
4320
|
-
}
|
|
4321
|
-
};
|
|
4322
|
-
await sessionManager.initialize(config);
|
|
4323
|
-
sessionManager.setupResponseInterceptor();
|
|
4324
|
-
const isAuth = sessionManager.isAuthenticated();
|
|
4325
|
-
const tokenInfo = sessionManager.getTokenInfo();
|
|
4326
|
-
setState((prev) => ({
|
|
4327
|
-
...prev,
|
|
4328
|
-
isAuthenticated: isAuth,
|
|
4329
|
-
isInitialized: true,
|
|
4330
|
-
isLoading: false,
|
|
4331
|
-
tokens: tokenInfo.crudifyTokens.accessToken ? {
|
|
4332
|
-
accessToken: tokenInfo.crudifyTokens.accessToken,
|
|
4333
|
-
refreshToken: tokenInfo.crudifyTokens.refreshToken,
|
|
4334
|
-
expiresAt: tokenInfo.crudifyTokens.expiresAt,
|
|
4335
|
-
refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
|
|
4336
|
-
} : null
|
|
4337
|
-
}));
|
|
4510
|
+
/**
|
|
4511
|
+
* Encriptar datos sensibles
|
|
4512
|
+
*/
|
|
4513
|
+
static encrypt(data) {
|
|
4514
|
+
try {
|
|
4515
|
+
return import_crypto_js2.default.AES.encrypt(data, _TokenStorage.ENCRYPTION_KEY).toString();
|
|
4338
4516
|
} catch (error) {
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
isLoading: false,
|
|
4342
|
-
isInitialized: true,
|
|
4343
|
-
error: error instanceof Error ? error.message : "Initialization failed"
|
|
4344
|
-
}));
|
|
4517
|
+
console.error("Crudify: Encryption failed", error);
|
|
4518
|
+
return data;
|
|
4345
4519
|
}
|
|
4346
|
-
}
|
|
4347
|
-
|
|
4348
|
-
|
|
4520
|
+
}
|
|
4521
|
+
/**
|
|
4522
|
+
* Desencriptar datos
|
|
4523
|
+
*/
|
|
4524
|
+
static decrypt(encryptedData) {
|
|
4349
4525
|
try {
|
|
4350
|
-
const
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
...prev,
|
|
4354
|
-
isAuthenticated: true,
|
|
4355
|
-
tokens: result.tokens,
|
|
4356
|
-
isLoading: false,
|
|
4357
|
-
error: null
|
|
4358
|
-
}));
|
|
4359
|
-
} else {
|
|
4360
|
-
setState((prev) => ({
|
|
4361
|
-
...prev,
|
|
4362
|
-
isAuthenticated: false,
|
|
4363
|
-
tokens: null,
|
|
4364
|
-
isLoading: false,
|
|
4365
|
-
error: result.error || "Login failed"
|
|
4366
|
-
}));
|
|
4367
|
-
}
|
|
4368
|
-
return result;
|
|
4526
|
+
const bytes = import_crypto_js2.default.AES.decrypt(encryptedData, _TokenStorage.ENCRYPTION_KEY);
|
|
4527
|
+
const decrypted = bytes.toString(import_crypto_js2.default.enc.Utf8);
|
|
4528
|
+
return decrypted || encryptedData;
|
|
4369
4529
|
} catch (error) {
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
...prev,
|
|
4373
|
-
isAuthenticated: false,
|
|
4374
|
-
tokens: null,
|
|
4375
|
-
isLoading: false,
|
|
4376
|
-
error: errorMsg
|
|
4377
|
-
}));
|
|
4378
|
-
return {
|
|
4379
|
-
success: false,
|
|
4380
|
-
error: errorMsg
|
|
4381
|
-
};
|
|
4530
|
+
console.error("Crudify: Decryption failed", error);
|
|
4531
|
+
return encryptedData;
|
|
4382
4532
|
}
|
|
4383
|
-
}
|
|
4384
|
-
|
|
4385
|
-
|
|
4533
|
+
}
|
|
4534
|
+
/**
|
|
4535
|
+
* Guardar tokens de forma segura
|
|
4536
|
+
*/
|
|
4537
|
+
static saveTokens(tokens) {
|
|
4538
|
+
const storage = _TokenStorage.getStorage();
|
|
4539
|
+
if (!storage) return;
|
|
4386
4540
|
try {
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4541
|
+
const tokenData = {
|
|
4542
|
+
accessToken: tokens.accessToken,
|
|
4543
|
+
refreshToken: tokens.refreshToken,
|
|
4544
|
+
expiresAt: tokens.expiresAt,
|
|
4545
|
+
refreshExpiresAt: tokens.refreshExpiresAt,
|
|
4546
|
+
savedAt: Date.now()
|
|
4547
|
+
};
|
|
4548
|
+
const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
|
|
4549
|
+
storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
|
|
4550
|
+
console.debug("Crudify: Tokens saved successfully");
|
|
4395
4551
|
} catch (error) {
|
|
4396
|
-
|
|
4397
|
-
...prev,
|
|
4398
|
-
isAuthenticated: false,
|
|
4399
|
-
tokens: null,
|
|
4400
|
-
isLoading: false,
|
|
4401
|
-
error: error instanceof Error ? error.message : "Logout error"
|
|
4402
|
-
}));
|
|
4552
|
+
console.error("Crudify: Failed to save tokens", error);
|
|
4403
4553
|
}
|
|
4404
|
-
}
|
|
4405
|
-
|
|
4554
|
+
}
|
|
4555
|
+
/**
|
|
4556
|
+
* Obtener tokens guardados
|
|
4557
|
+
*/
|
|
4558
|
+
static getTokens() {
|
|
4559
|
+
const storage = _TokenStorage.getStorage();
|
|
4560
|
+
if (!storage) return null;
|
|
4406
4561
|
try {
|
|
4407
|
-
const
|
|
4408
|
-
if (
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
expiresAt: tokenInfo.crudifyTokens.expiresAt,
|
|
4416
|
-
refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
|
|
4417
|
-
} : null,
|
|
4418
|
-
error: null
|
|
4419
|
-
}));
|
|
4420
|
-
} else {
|
|
4421
|
-
setState((prev) => ({
|
|
4422
|
-
...prev,
|
|
4423
|
-
isAuthenticated: false,
|
|
4424
|
-
tokens: null,
|
|
4425
|
-
error: "Token refresh failed"
|
|
4426
|
-
}));
|
|
4562
|
+
const encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
|
|
4563
|
+
if (!encrypted) return null;
|
|
4564
|
+
const decrypted = _TokenStorage.decrypt(encrypted);
|
|
4565
|
+
const tokenData = JSON.parse(decrypted);
|
|
4566
|
+
if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
|
|
4567
|
+
console.warn("Crudify: Incomplete token data found, clearing storage");
|
|
4568
|
+
_TokenStorage.clearTokens();
|
|
4569
|
+
return null;
|
|
4427
4570
|
}
|
|
4428
|
-
|
|
4571
|
+
if (Date.now() >= tokenData.refreshExpiresAt) {
|
|
4572
|
+
console.info("Crudify: Refresh token expired, clearing storage");
|
|
4573
|
+
_TokenStorage.clearTokens();
|
|
4574
|
+
return null;
|
|
4575
|
+
}
|
|
4576
|
+
return {
|
|
4577
|
+
accessToken: tokenData.accessToken,
|
|
4578
|
+
refreshToken: tokenData.refreshToken,
|
|
4579
|
+
expiresAt: tokenData.expiresAt,
|
|
4580
|
+
refreshExpiresAt: tokenData.refreshExpiresAt
|
|
4581
|
+
};
|
|
4429
4582
|
} catch (error) {
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
isAuthenticated: false,
|
|
4433
|
-
tokens: null,
|
|
4434
|
-
error: error instanceof Error ? error.message : "Token refresh failed"
|
|
4435
|
-
}));
|
|
4436
|
-
return false;
|
|
4437
|
-
}
|
|
4438
|
-
}, [sessionManager]);
|
|
4439
|
-
const clearError = (0, import_react16.useCallback)(() => {
|
|
4440
|
-
setState((prev) => ({ ...prev, error: null }));
|
|
4441
|
-
}, []);
|
|
4442
|
-
const getTokenInfo = (0, import_react16.useCallback)(() => {
|
|
4443
|
-
return sessionManager.getTokenInfo();
|
|
4444
|
-
}, [sessionManager]);
|
|
4445
|
-
(0, import_react16.useEffect)(() => {
|
|
4446
|
-
initialize();
|
|
4447
|
-
}, [initialize]);
|
|
4448
|
-
return {
|
|
4449
|
-
// Estado
|
|
4450
|
-
...state,
|
|
4451
|
-
// Acciones
|
|
4452
|
-
login,
|
|
4453
|
-
logout,
|
|
4454
|
-
refreshTokens,
|
|
4455
|
-
clearError,
|
|
4456
|
-
getTokenInfo,
|
|
4457
|
-
// Utilidades
|
|
4458
|
-
isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
|
|
4459
|
-
// 5 minutos
|
|
4460
|
-
expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
|
|
4461
|
-
refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
|
|
4462
|
-
};
|
|
4463
|
-
}
|
|
4464
|
-
|
|
4465
|
-
// src/providers/SessionProvider.tsx
|
|
4466
|
-
var import_react17 = require("react");
|
|
4467
|
-
init_jwtUtils();
|
|
4468
|
-
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
4469
|
-
var SessionContext = (0, import_react17.createContext)(void 0);
|
|
4470
|
-
function SessionProvider({ children, options = {} }) {
|
|
4471
|
-
const sessionHook = useSession(options);
|
|
4472
|
-
const sessionData = (0, import_react17.useMemo)(() => {
|
|
4473
|
-
if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
|
|
4583
|
+
console.error("Crudify: Failed to retrieve tokens", error);
|
|
4584
|
+
_TokenStorage.clearTokens();
|
|
4474
4585
|
return null;
|
|
4475
4586
|
}
|
|
4587
|
+
}
|
|
4588
|
+
/**
|
|
4589
|
+
* Limpiar tokens almacenados
|
|
4590
|
+
*/
|
|
4591
|
+
static clearTokens() {
|
|
4592
|
+
const storage = _TokenStorage.getStorage();
|
|
4593
|
+
if (!storage) return;
|
|
4476
4594
|
try {
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
const result = {
|
|
4480
|
-
_id: decoded.sub,
|
|
4481
|
-
email: decoded.email,
|
|
4482
|
-
subscriberKey: decoded.subscriber
|
|
4483
|
-
};
|
|
4484
|
-
Object.keys(decoded).forEach((key) => {
|
|
4485
|
-
if (!["sub", "email", "subscriber"].includes(key)) {
|
|
4486
|
-
result[key] = decoded[key];
|
|
4487
|
-
}
|
|
4488
|
-
});
|
|
4489
|
-
return result;
|
|
4490
|
-
}
|
|
4595
|
+
storage.removeItem(_TokenStorage.TOKEN_KEY);
|
|
4596
|
+
console.debug("Crudify: Tokens cleared from storage");
|
|
4491
4597
|
} catch (error) {
|
|
4492
|
-
console.error("
|
|
4598
|
+
console.error("Crudify: Failed to clear tokens", error);
|
|
4493
4599
|
}
|
|
4494
|
-
return null;
|
|
4495
|
-
}, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
|
|
4496
|
-
const contextValue = {
|
|
4497
|
-
...sessionHook,
|
|
4498
|
-
sessionData
|
|
4499
|
-
};
|
|
4500
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SessionContext.Provider, { value: contextValue, children });
|
|
4501
|
-
}
|
|
4502
|
-
function useSessionContext() {
|
|
4503
|
-
const context = (0, import_react17.useContext)(SessionContext);
|
|
4504
|
-
if (context === void 0) {
|
|
4505
|
-
throw new Error("useSessionContext must be used within a SessionProvider");
|
|
4506
4600
|
}
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
}) {
|
|
4514
|
-
const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
|
|
4515
|
-
if (!isInitialized || isLoading) {
|
|
4516
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: "Loading..." });
|
|
4601
|
+
/**
|
|
4602
|
+
* Verificar si hay tokens válidos guardados
|
|
4603
|
+
*/
|
|
4604
|
+
static hasValidTokens() {
|
|
4605
|
+
const tokens = _TokenStorage.getTokens();
|
|
4606
|
+
return tokens !== null;
|
|
4517
4607
|
}
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4608
|
+
/**
|
|
4609
|
+
* Obtener información de expiración
|
|
4610
|
+
*/
|
|
4611
|
+
static getExpirationInfo() {
|
|
4612
|
+
const tokens = _TokenStorage.getTokens();
|
|
4613
|
+
if (!tokens) return null;
|
|
4614
|
+
const now = Date.now();
|
|
4615
|
+
return {
|
|
4616
|
+
accessExpired: now >= tokens.expiresAt,
|
|
4617
|
+
refreshExpired: now >= tokens.refreshExpiresAt,
|
|
4618
|
+
accessExpiresIn: Math.max(0, tokens.expiresAt - now),
|
|
4619
|
+
refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
|
|
4620
|
+
};
|
|
4621
|
+
}
|
|
4622
|
+
/**
|
|
4623
|
+
* Actualizar solo el access token (después de refresh)
|
|
4624
|
+
*/
|
|
4625
|
+
static updateAccessToken(newAccessToken, newExpiresAt) {
|
|
4626
|
+
const existingTokens = _TokenStorage.getTokens();
|
|
4627
|
+
if (!existingTokens) {
|
|
4628
|
+
console.warn("Crudify: Cannot update access token, no existing tokens found");
|
|
4629
|
+
return;
|
|
4522
4630
|
}
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
const session = useSessionContext();
|
|
4529
|
-
if (!session.isInitialized) {
|
|
4530
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: "Session not initialized" });
|
|
4631
|
+
_TokenStorage.saveTokens({
|
|
4632
|
+
...existingTokens,
|
|
4633
|
+
accessToken: newAccessToken,
|
|
4634
|
+
expiresAt: newExpiresAt
|
|
4635
|
+
});
|
|
4531
4636
|
}
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
fontSize: "12px",
|
|
4538
|
-
fontFamily: "monospace"
|
|
4539
|
-
}, children: [
|
|
4540
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h4", { children: "Session Debug Info" }),
|
|
4541
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4542
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Authenticated:" }),
|
|
4543
|
-
" ",
|
|
4544
|
-
session.isAuthenticated ? "Yes" : "No"
|
|
4545
|
-
] }),
|
|
4546
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4547
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Loading:" }),
|
|
4548
|
-
" ",
|
|
4549
|
-
session.isLoading ? "Yes" : "No"
|
|
4550
|
-
] }),
|
|
4551
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4552
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Error:" }),
|
|
4553
|
-
" ",
|
|
4554
|
-
session.error || "None"
|
|
4555
|
-
] }),
|
|
4556
|
-
session.tokens && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
4557
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4558
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Access Token:" }),
|
|
4559
|
-
" ",
|
|
4560
|
-
session.tokens.accessToken.substring(0, 20),
|
|
4561
|
-
"..."
|
|
4562
|
-
] }),
|
|
4563
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4564
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Refresh Token:" }),
|
|
4565
|
-
" ",
|
|
4566
|
-
session.tokens.refreshToken.substring(0, 20),
|
|
4567
|
-
"..."
|
|
4568
|
-
] }),
|
|
4569
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4570
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Access Expires In:" }),
|
|
4571
|
-
" ",
|
|
4572
|
-
Math.round(session.expiresIn / 1e3 / 60),
|
|
4573
|
-
" minutes"
|
|
4574
|
-
] }),
|
|
4575
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4576
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Refresh Expires In:" }),
|
|
4577
|
-
" ",
|
|
4578
|
-
Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
|
|
4579
|
-
" hours"
|
|
4580
|
-
] }),
|
|
4581
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4582
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Expiring Soon:" }),
|
|
4583
|
-
" ",
|
|
4584
|
-
session.isExpiringSoon ? "Yes" : "No"
|
|
4585
|
-
] })
|
|
4586
|
-
] })
|
|
4587
|
-
] });
|
|
4588
|
-
}
|
|
4637
|
+
};
|
|
4638
|
+
_TokenStorage.TOKEN_KEY = "crudify_tokens";
|
|
4639
|
+
_TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
|
|
4640
|
+
_TokenStorage.storageType = "localStorage";
|
|
4641
|
+
var TokenStorage = _TokenStorage;
|
|
4589
4642
|
|
|
4590
|
-
// src/
|
|
4591
|
-
var
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
} = useSessionContext();
|
|
4609
|
-
const handleLogin = async (e) => {
|
|
4610
|
-
e.preventDefault();
|
|
4611
|
-
if (!email || !password) {
|
|
4643
|
+
// src/core/SessionManager.ts
|
|
4644
|
+
var SessionManager = class _SessionManager {
|
|
4645
|
+
constructor() {
|
|
4646
|
+
this.config = {};
|
|
4647
|
+
this.initialized = false;
|
|
4648
|
+
}
|
|
4649
|
+
static getInstance() {
|
|
4650
|
+
if (!_SessionManager.instance) {
|
|
4651
|
+
_SessionManager.instance = new _SessionManager();
|
|
4652
|
+
}
|
|
4653
|
+
return _SessionManager.instance;
|
|
4654
|
+
}
|
|
4655
|
+
/**
|
|
4656
|
+
* Inicializar el SessionManager
|
|
4657
|
+
*/
|
|
4658
|
+
async initialize(config = {}) {
|
|
4659
|
+
if (this.initialized) {
|
|
4660
|
+
console.warn("SessionManager: Already initialized");
|
|
4612
4661
|
return;
|
|
4613
4662
|
}
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4663
|
+
this.config = {
|
|
4664
|
+
storageType: "localStorage",
|
|
4665
|
+
autoRestore: true,
|
|
4666
|
+
enableLogging: false,
|
|
4667
|
+
...config
|
|
4668
|
+
};
|
|
4669
|
+
TokenStorage.setStorageType(this.config.storageType || "localStorage");
|
|
4670
|
+
if (this.config.enableLogging) {
|
|
4619
4671
|
}
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
await refreshTokens();
|
|
4626
|
-
};
|
|
4627
|
-
if (isAuthenticated) {
|
|
4628
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { maxWidth: 600, mx: "auto", p: 3 }, children: [
|
|
4629
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "h4", gutterBottom: true, children: "Welcome! \u{1F389}" }),
|
|
4630
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "success", sx: { mb: 3 }, children: "You are successfully logged in with Refresh Token Pattern enabled" }),
|
|
4631
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { mb: 3, p: 2, bgcolor: "background.paper", border: 1, borderColor: "divider", borderRadius: 1 }, children: [
|
|
4632
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "h6", gutterBottom: true, children: "Token Status" }),
|
|
4633
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Typography, { variant: "body2", color: "text.secondary", children: [
|
|
4634
|
-
"Access Token expires in: ",
|
|
4635
|
-
Math.round(expiresIn / 1e3 / 60),
|
|
4636
|
-
" minutes"
|
|
4637
|
-
] }),
|
|
4638
|
-
isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "warning", sx: { mt: 1 }, children: "Token expires soon - automatic refresh will happen" })
|
|
4639
|
-
] }),
|
|
4640
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { display: "flex", gap: 2, flexWrap: "wrap" }, children: [
|
|
4641
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4642
|
-
import_material8.Button,
|
|
4643
|
-
{
|
|
4644
|
-
variant: "contained",
|
|
4645
|
-
onClick: handleRefreshTokens,
|
|
4646
|
-
disabled: isLoading,
|
|
4647
|
-
startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.CircularProgress, { size: 16 }) : null,
|
|
4648
|
-
children: "Refresh Tokens"
|
|
4649
|
-
}
|
|
4650
|
-
),
|
|
4651
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4652
|
-
import_material8.Button,
|
|
4653
|
-
{
|
|
4654
|
-
variant: "outlined",
|
|
4655
|
-
color: "error",
|
|
4656
|
-
onClick: handleLogout,
|
|
4657
|
-
disabled: isLoading,
|
|
4658
|
-
children: "Logout"
|
|
4659
|
-
}
|
|
4660
|
-
)
|
|
4661
|
-
] }),
|
|
4662
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
|
|
4663
|
-
] });
|
|
4672
|
+
if (this.config.autoRestore) {
|
|
4673
|
+
await this.restoreSession();
|
|
4674
|
+
}
|
|
4675
|
+
this.initialized = true;
|
|
4676
|
+
this.log("SessionManager initialized successfully");
|
|
4664
4677
|
}
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4678
|
+
/**
|
|
4679
|
+
* Login con persistencia automática
|
|
4680
|
+
*/
|
|
4681
|
+
async login(email, password) {
|
|
4682
|
+
try {
|
|
4683
|
+
this.log("Attempting login...");
|
|
4684
|
+
const response = await import_crudify_browser8.default.login(email, password);
|
|
4685
|
+
if (!response.success) {
|
|
4686
|
+
this.log("Login failed:", response.errors);
|
|
4687
|
+
return {
|
|
4688
|
+
success: false,
|
|
4689
|
+
error: this.formatError(response.errors)
|
|
4690
|
+
};
|
|
4677
4691
|
}
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
value: password,
|
|
4699
|
-
onChange: (e) => setPassword(e.target.value),
|
|
4700
|
-
margin: "normal",
|
|
4701
|
-
required: true,
|
|
4702
|
-
autoComplete: "current-password"
|
|
4703
|
-
}
|
|
4704
|
-
),
|
|
4705
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4706
|
-
import_material8.Button,
|
|
4707
|
-
{
|
|
4708
|
-
type: "submit",
|
|
4709
|
-
fullWidth: true,
|
|
4710
|
-
variant: "contained",
|
|
4711
|
-
size: "large",
|
|
4712
|
-
disabled: isLoading,
|
|
4713
|
-
startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.CircularProgress, { size: 16 }) : null,
|
|
4714
|
-
sx: { mt: 3, mb: 2 },
|
|
4715
|
-
children: isLoading ? "Logging in..." : "Login"
|
|
4716
|
-
}
|
|
4717
|
-
)
|
|
4718
|
-
] }),
|
|
4719
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
|
|
4720
|
-
] });
|
|
4721
|
-
}
|
|
4722
|
-
function SessionStatus() {
|
|
4723
|
-
const { isAuthenticated, isLoading, isExpiringSoon, expiresIn } = useSessionContext();
|
|
4724
|
-
if (isLoading) {
|
|
4725
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
|
4726
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.CircularProgress, { size: 16 }),
|
|
4727
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "caption", children: "Loading session..." })
|
|
4728
|
-
] });
|
|
4729
|
-
}
|
|
4730
|
-
if (!isAuthenticated) {
|
|
4731
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "caption", color: "text.secondary", children: "Not logged in" });
|
|
4692
|
+
const tokens = {
|
|
4693
|
+
accessToken: response.data.token,
|
|
4694
|
+
refreshToken: response.data.refreshToken,
|
|
4695
|
+
expiresAt: response.data.expiresAt,
|
|
4696
|
+
refreshExpiresAt: response.data.refreshExpiresAt
|
|
4697
|
+
};
|
|
4698
|
+
TokenStorage.saveTokens(tokens);
|
|
4699
|
+
this.log("Login successful, tokens saved");
|
|
4700
|
+
this.config.onLoginSuccess?.(tokens);
|
|
4701
|
+
return {
|
|
4702
|
+
success: true,
|
|
4703
|
+
tokens
|
|
4704
|
+
};
|
|
4705
|
+
} catch (error) {
|
|
4706
|
+
this.log("Login error:", error);
|
|
4707
|
+
return {
|
|
4708
|
+
success: false,
|
|
4709
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
4710
|
+
};
|
|
4711
|
+
}
|
|
4732
4712
|
}
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
"
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
var useUserData = (options = {}) => {
|
|
4747
|
-
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
4748
|
-
const { isAuthenticated, isInitialized, sessionData, tokens } = useSessionContext();
|
|
4749
|
-
const [userData, setUserData] = (0, import_react19.useState)(null);
|
|
4750
|
-
const [loading, setLoading] = (0, import_react19.useState)(false);
|
|
4751
|
-
const [error, setError] = (0, import_react19.useState)(null);
|
|
4752
|
-
const abortControllerRef = (0, import_react19.useRef)(null);
|
|
4753
|
-
const mountedRef = (0, import_react19.useRef)(true);
|
|
4754
|
-
const requestIdRef = (0, import_react19.useRef)(0);
|
|
4755
|
-
const retryCountRef = (0, import_react19.useRef)(0);
|
|
4756
|
-
const getUserEmail = (0, import_react19.useCallback)(() => {
|
|
4757
|
-
if (!sessionData) return null;
|
|
4758
|
-
return sessionData.email || sessionData["cognito:username"] || null;
|
|
4759
|
-
}, [sessionData]);
|
|
4760
|
-
const clearProfile = (0, import_react19.useCallback)(() => {
|
|
4761
|
-
setUserData(null);
|
|
4762
|
-
setError(null);
|
|
4763
|
-
setLoading(false);
|
|
4764
|
-
retryCountRef.current = 0;
|
|
4765
|
-
}, []);
|
|
4766
|
-
const refreshProfile = (0, import_react19.useCallback)(async () => {
|
|
4767
|
-
const userEmail = getUserEmail();
|
|
4768
|
-
console.log("\u{1F464} useUserData - Refreshing profile for:", userEmail);
|
|
4769
|
-
if (!userEmail) {
|
|
4770
|
-
if (mountedRef.current) {
|
|
4771
|
-
setError("No user email available from session data");
|
|
4772
|
-
setLoading(false);
|
|
4773
|
-
}
|
|
4774
|
-
return;
|
|
4713
|
+
/**
|
|
4714
|
+
* Logout con limpieza de tokens
|
|
4715
|
+
*/
|
|
4716
|
+
async logout() {
|
|
4717
|
+
try {
|
|
4718
|
+
this.log("Logging out...");
|
|
4719
|
+
await import_crudify_browser8.default.logout();
|
|
4720
|
+
TokenStorage.clearTokens();
|
|
4721
|
+
this.log("Logout successful");
|
|
4722
|
+
this.config.onLogout?.();
|
|
4723
|
+
} catch (error) {
|
|
4724
|
+
this.log("Logout error:", error);
|
|
4725
|
+
TokenStorage.clearTokens();
|
|
4775
4726
|
}
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4727
|
+
}
|
|
4728
|
+
/**
|
|
4729
|
+
* Restaurar sesión desde storage
|
|
4730
|
+
*/
|
|
4731
|
+
async restoreSession() {
|
|
4732
|
+
try {
|
|
4733
|
+
this.log("Attempting to restore session...");
|
|
4734
|
+
const savedTokens = TokenStorage.getTokens();
|
|
4735
|
+
if (!savedTokens) {
|
|
4736
|
+
this.log("No valid tokens found in storage");
|
|
4737
|
+
return false;
|
|
4780
4738
|
}
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4739
|
+
import_crudify_browser8.default.setTokens({
|
|
4740
|
+
accessToken: savedTokens.accessToken,
|
|
4741
|
+
refreshToken: savedTokens.refreshToken,
|
|
4742
|
+
expiresAt: savedTokens.expiresAt,
|
|
4743
|
+
refreshExpiresAt: savedTokens.refreshExpiresAt
|
|
4744
|
+
});
|
|
4745
|
+
this.log("Session restored successfully");
|
|
4746
|
+
this.config.onSessionRestored?.(savedTokens);
|
|
4747
|
+
return true;
|
|
4748
|
+
} catch (error) {
|
|
4749
|
+
this.log("Session restore error:", error);
|
|
4750
|
+
TokenStorage.clearTokens();
|
|
4751
|
+
return false;
|
|
4785
4752
|
}
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4753
|
+
}
|
|
4754
|
+
/**
|
|
4755
|
+
* Verificar si el usuario está autenticado
|
|
4756
|
+
*/
|
|
4757
|
+
isAuthenticated() {
|
|
4758
|
+
return import_crudify_browser8.default.isLogin() || TokenStorage.hasValidTokens();
|
|
4759
|
+
}
|
|
4760
|
+
/**
|
|
4761
|
+
* Obtener información de tokens actuales
|
|
4762
|
+
*/
|
|
4763
|
+
getTokenInfo() {
|
|
4764
|
+
const crudifyTokens = import_crudify_browser8.default.getTokenData();
|
|
4765
|
+
const storageInfo = TokenStorage.getExpirationInfo();
|
|
4766
|
+
return {
|
|
4767
|
+
isLoggedIn: this.isAuthenticated(),
|
|
4768
|
+
crudifyTokens,
|
|
4769
|
+
storageInfo,
|
|
4770
|
+
hasValidTokens: TokenStorage.hasValidTokens()
|
|
4771
|
+
};
|
|
4772
|
+
}
|
|
4773
|
+
/**
|
|
4774
|
+
* Refrescar tokens manualmente
|
|
4775
|
+
*/
|
|
4776
|
+
async refreshTokens() {
|
|
4789
4777
|
try {
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4778
|
+
this.log("Manually refreshing tokens...");
|
|
4779
|
+
const response = await import_crudify_browser8.default.refreshAccessToken();
|
|
4780
|
+
if (!response.success) {
|
|
4781
|
+
this.log("Token refresh failed:", response.errors);
|
|
4782
|
+
TokenStorage.clearTokens();
|
|
4783
|
+
this.config.onSessionExpired?.();
|
|
4784
|
+
return false;
|
|
4793
4785
|
}
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
console.log("\u{1F464} useUserData - Extracted user from nested items:", userData2);
|
|
4826
|
-
} else {
|
|
4827
|
-
console.log("\u{1F464} useUserData - No items found in parsed data or items array is empty");
|
|
4828
|
-
}
|
|
4829
|
-
} catch (parseError) {
|
|
4830
|
-
console.error("\u{1F464} useUserData - Error parsing nested response data:", parseError);
|
|
4831
|
-
}
|
|
4832
|
-
} else if (response.data && typeof response.data === "object") {
|
|
4833
|
-
console.log("\u{1F464} useUserData - Found object format, checking for items");
|
|
4834
|
-
if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
|
|
4835
|
-
console.log("\u{1F464} useUserData - Found items in object format");
|
|
4836
|
-
userData2 = response.data.items[0];
|
|
4837
|
-
} else {
|
|
4838
|
-
console.log("\u{1F464} useUserData - No items found in object format");
|
|
4839
|
-
}
|
|
4840
|
-
} else if (response.data?.data?.response?.data) {
|
|
4841
|
-
console.log("\u{1F464} useUserData - Found double-nested data.data.response.data format");
|
|
4842
|
-
try {
|
|
4843
|
-
const rawData = response.data.data.response.data;
|
|
4844
|
-
console.log("\u{1F464} useUserData - Raw double-nested data:", rawData);
|
|
4845
|
-
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
4846
|
-
console.log("\u{1F464} useUserData - Parsed double-nested data:", parsedData);
|
|
4847
|
-
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
4848
|
-
userData2 = parsedData.items[0];
|
|
4849
|
-
console.log("\u{1F464} useUserData - Extracted user from double-nested items:", userData2);
|
|
4850
|
-
}
|
|
4851
|
-
} catch (parseError) {
|
|
4852
|
-
console.error("\u{1F464} useUserData - Error parsing double-nested response data:", parseError);
|
|
4853
|
-
}
|
|
4786
|
+
const newTokens = {
|
|
4787
|
+
accessToken: response.data.token,
|
|
4788
|
+
refreshToken: response.data.refreshToken,
|
|
4789
|
+
expiresAt: response.data.expiresAt,
|
|
4790
|
+
refreshExpiresAt: response.data.refreshExpiresAt
|
|
4791
|
+
};
|
|
4792
|
+
TokenStorage.saveTokens(newTokens);
|
|
4793
|
+
this.log("Tokens refreshed and saved successfully");
|
|
4794
|
+
return true;
|
|
4795
|
+
} catch (error) {
|
|
4796
|
+
this.log("Token refresh error:", error);
|
|
4797
|
+
TokenStorage.clearTokens();
|
|
4798
|
+
this.config.onSessionExpired?.();
|
|
4799
|
+
return false;
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4802
|
+
/**
|
|
4803
|
+
* Configurar interceptor de respuesta para manejo automático de errores
|
|
4804
|
+
*/
|
|
4805
|
+
setupResponseInterceptor() {
|
|
4806
|
+
import_crudify_browser8.default.setResponseInterceptor(async (response) => {
|
|
4807
|
+
if (response.errors) {
|
|
4808
|
+
const hasAuthError = response.errors.some(
|
|
4809
|
+
(error) => error.message?.includes("Unauthorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED"
|
|
4810
|
+
);
|
|
4811
|
+
if (hasAuthError && TokenStorage.hasValidTokens()) {
|
|
4812
|
+
this.log("Auth error detected, attempting token refresh...");
|
|
4813
|
+
const refreshSuccess = await this.refreshTokens();
|
|
4814
|
+
if (!refreshSuccess) {
|
|
4815
|
+
this.log("Session expired, triggering callback");
|
|
4816
|
+
this.config.onSessionExpired?.();
|
|
4854
4817
|
}
|
|
4855
4818
|
}
|
|
4856
|
-
if (userData2) {
|
|
4857
|
-
console.log("\u{1F464} useUserData - User data found:", userData2);
|
|
4858
|
-
setUserData(userData2);
|
|
4859
|
-
setError(null);
|
|
4860
|
-
retryCountRef.current = 0;
|
|
4861
|
-
console.log("\u{1F464} useUserData - Profile loaded successfully:", userData2);
|
|
4862
|
-
} else {
|
|
4863
|
-
setError("User profile not found in database");
|
|
4864
|
-
setUserData(null);
|
|
4865
|
-
console.warn("\u{1F464} useUserData - User not found for email:", userEmail);
|
|
4866
|
-
}
|
|
4867
4819
|
}
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4820
|
+
return response;
|
|
4821
|
+
});
|
|
4822
|
+
this.log("Response interceptor configured");
|
|
4823
|
+
}
|
|
4824
|
+
/**
|
|
4825
|
+
* Limpiar sesión completamente
|
|
4826
|
+
*/
|
|
4827
|
+
clearSession() {
|
|
4828
|
+
TokenStorage.clearTokens();
|
|
4829
|
+
import_crudify_browser8.default.logout();
|
|
4830
|
+
this.log("Session cleared completely");
|
|
4831
|
+
}
|
|
4832
|
+
// Métodos privados
|
|
4833
|
+
log(message, ...args) {
|
|
4834
|
+
if (this.config.enableLogging) {
|
|
4835
|
+
console.log(`[SessionManager] ${message}`, ...args);
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
formatError(errors) {
|
|
4839
|
+
if (!errors) return "Unknown error";
|
|
4840
|
+
if (typeof errors === "string") return errors;
|
|
4841
|
+
if (typeof errors === "object") {
|
|
4842
|
+
const errorMessages = Object.values(errors).flat();
|
|
4843
|
+
return errorMessages.join(", ");
|
|
4844
|
+
}
|
|
4845
|
+
return "Authentication failed";
|
|
4846
|
+
}
|
|
4847
|
+
};
|
|
4848
|
+
|
|
4849
|
+
// src/hooks/useSession.ts
|
|
4850
|
+
var import_react19 = require("react");
|
|
4851
|
+
function useSession(options = {}) {
|
|
4852
|
+
const [state, setState] = (0, import_react19.useState)({
|
|
4853
|
+
isAuthenticated: false,
|
|
4854
|
+
isLoading: true,
|
|
4855
|
+
isInitialized: false,
|
|
4856
|
+
tokens: null,
|
|
4857
|
+
error: null
|
|
4858
|
+
});
|
|
4859
|
+
const sessionManager = SessionManager.getInstance();
|
|
4860
|
+
const initialize = (0, import_react19.useCallback)(async () => {
|
|
4861
|
+
try {
|
|
4862
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
4863
|
+
const config = {
|
|
4864
|
+
autoRestore: options.autoRestore ?? true,
|
|
4865
|
+
enableLogging: options.enableLogging ?? false,
|
|
4866
|
+
onSessionExpired: () => {
|
|
4867
|
+
setState((prev) => ({
|
|
4868
|
+
...prev,
|
|
4869
|
+
isAuthenticated: false,
|
|
4870
|
+
tokens: null,
|
|
4871
|
+
error: "Session expired"
|
|
4872
|
+
}));
|
|
4873
|
+
options.onSessionExpired?.();
|
|
4874
|
+
},
|
|
4875
|
+
onSessionRestored: (tokens) => {
|
|
4876
|
+
setState((prev) => ({
|
|
4877
|
+
...prev,
|
|
4878
|
+
isAuthenticated: true,
|
|
4879
|
+
tokens,
|
|
4880
|
+
error: null
|
|
4881
|
+
}));
|
|
4882
|
+
options.onSessionRestored?.(tokens);
|
|
4883
|
+
},
|
|
4884
|
+
onLoginSuccess: (tokens) => {
|
|
4885
|
+
setState((prev) => ({
|
|
4886
|
+
...prev,
|
|
4887
|
+
isAuthenticated: true,
|
|
4888
|
+
tokens,
|
|
4889
|
+
error: null
|
|
4890
|
+
}));
|
|
4891
|
+
},
|
|
4892
|
+
onLogout: () => {
|
|
4893
|
+
setState((prev) => ({
|
|
4894
|
+
...prev,
|
|
4895
|
+
isAuthenticated: false,
|
|
4896
|
+
tokens: null,
|
|
4897
|
+
error: null
|
|
4898
|
+
}));
|
|
4887
4899
|
}
|
|
4900
|
+
};
|
|
4901
|
+
await sessionManager.initialize(config);
|
|
4902
|
+
sessionManager.setupResponseInterceptor();
|
|
4903
|
+
const isAuth = sessionManager.isAuthenticated();
|
|
4904
|
+
const tokenInfo = sessionManager.getTokenInfo();
|
|
4905
|
+
setState((prev) => ({
|
|
4906
|
+
...prev,
|
|
4907
|
+
isAuthenticated: isAuth,
|
|
4908
|
+
isInitialized: true,
|
|
4909
|
+
isLoading: false,
|
|
4910
|
+
tokens: tokenInfo.crudifyTokens.accessToken ? {
|
|
4911
|
+
accessToken: tokenInfo.crudifyTokens.accessToken,
|
|
4912
|
+
refreshToken: tokenInfo.crudifyTokens.refreshToken,
|
|
4913
|
+
expiresAt: tokenInfo.crudifyTokens.expiresAt,
|
|
4914
|
+
refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
|
|
4915
|
+
} : null
|
|
4916
|
+
}));
|
|
4917
|
+
} catch (error) {
|
|
4918
|
+
setState((prev) => ({
|
|
4919
|
+
...prev,
|
|
4920
|
+
isLoading: false,
|
|
4921
|
+
isInitialized: true,
|
|
4922
|
+
error: error instanceof Error ? error.message : "Initialization failed"
|
|
4923
|
+
}));
|
|
4924
|
+
}
|
|
4925
|
+
}, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
|
|
4926
|
+
const login = (0, import_react19.useCallback)(async (email, password) => {
|
|
4927
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
4928
|
+
try {
|
|
4929
|
+
const result = await sessionManager.login(email, password);
|
|
4930
|
+
if (result.success && result.tokens) {
|
|
4931
|
+
setState((prev) => ({
|
|
4932
|
+
...prev,
|
|
4933
|
+
isAuthenticated: true,
|
|
4934
|
+
tokens: result.tokens,
|
|
4935
|
+
isLoading: false,
|
|
4936
|
+
error: null
|
|
4937
|
+
}));
|
|
4938
|
+
} else {
|
|
4939
|
+
setState((prev) => ({
|
|
4940
|
+
...prev,
|
|
4941
|
+
isAuthenticated: false,
|
|
4942
|
+
tokens: null,
|
|
4943
|
+
isLoading: false,
|
|
4944
|
+
error: result.error || "Login failed"
|
|
4945
|
+
}));
|
|
4888
4946
|
}
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4947
|
+
return result;
|
|
4948
|
+
} catch (error) {
|
|
4949
|
+
const errorMsg = error instanceof Error ? error.message : "Login failed";
|
|
4950
|
+
setState((prev) => ({
|
|
4951
|
+
...prev,
|
|
4952
|
+
isAuthenticated: false,
|
|
4953
|
+
tokens: null,
|
|
4954
|
+
isLoading: false,
|
|
4955
|
+
error: errorMsg
|
|
4956
|
+
}));
|
|
4957
|
+
return {
|
|
4958
|
+
success: false,
|
|
4959
|
+
error: errorMsg
|
|
4960
|
+
};
|
|
4896
4961
|
}
|
|
4897
|
-
}, [
|
|
4898
|
-
(0, import_react19.
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4962
|
+
}, [sessionManager]);
|
|
4963
|
+
const logout = (0, import_react19.useCallback)(async () => {
|
|
4964
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
4965
|
+
try {
|
|
4966
|
+
await sessionManager.logout();
|
|
4967
|
+
setState((prev) => ({
|
|
4968
|
+
...prev,
|
|
4969
|
+
isAuthenticated: false,
|
|
4970
|
+
tokens: null,
|
|
4971
|
+
isLoading: false,
|
|
4972
|
+
error: null
|
|
4973
|
+
}));
|
|
4974
|
+
} catch (error) {
|
|
4975
|
+
setState((prev) => ({
|
|
4976
|
+
...prev,
|
|
4977
|
+
isAuthenticated: false,
|
|
4978
|
+
tokens: null,
|
|
4979
|
+
isLoading: false,
|
|
4980
|
+
error: error instanceof Error ? error.message : "Logout error"
|
|
4981
|
+
}));
|
|
4903
4982
|
}
|
|
4904
|
-
}, [
|
|
4905
|
-
(0, import_react19.
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4983
|
+
}, [sessionManager]);
|
|
4984
|
+
const refreshTokens = (0, import_react19.useCallback)(async () => {
|
|
4985
|
+
try {
|
|
4986
|
+
const success = await sessionManager.refreshTokens();
|
|
4987
|
+
if (success) {
|
|
4988
|
+
const tokenInfo = sessionManager.getTokenInfo();
|
|
4989
|
+
setState((prev) => ({
|
|
4990
|
+
...prev,
|
|
4991
|
+
tokens: tokenInfo.crudifyTokens.accessToken ? {
|
|
4992
|
+
accessToken: tokenInfo.crudifyTokens.accessToken,
|
|
4993
|
+
refreshToken: tokenInfo.crudifyTokens.refreshToken,
|
|
4994
|
+
expiresAt: tokenInfo.crudifyTokens.expiresAt,
|
|
4995
|
+
refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
|
|
4996
|
+
} : null,
|
|
4997
|
+
error: null
|
|
4998
|
+
}));
|
|
4999
|
+
} else {
|
|
5000
|
+
setState((prev) => ({
|
|
5001
|
+
...prev,
|
|
5002
|
+
isAuthenticated: false,
|
|
5003
|
+
tokens: null,
|
|
5004
|
+
error: "Token refresh failed"
|
|
5005
|
+
}));
|
|
4912
5006
|
}
|
|
4913
|
-
|
|
5007
|
+
return success;
|
|
5008
|
+
} catch (error) {
|
|
5009
|
+
setState((prev) => ({
|
|
5010
|
+
...prev,
|
|
5011
|
+
isAuthenticated: false,
|
|
5012
|
+
tokens: null,
|
|
5013
|
+
error: error instanceof Error ? error.message : "Token refresh failed"
|
|
5014
|
+
}));
|
|
5015
|
+
return false;
|
|
5016
|
+
}
|
|
5017
|
+
}, [sessionManager]);
|
|
5018
|
+
const clearError = (0, import_react19.useCallback)(() => {
|
|
5019
|
+
setState((prev) => ({ ...prev, error: null }));
|
|
4914
5020
|
}, []);
|
|
4915
|
-
const
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
};
|
|
5021
|
+
const getTokenInfo = (0, import_react19.useCallback)(() => {
|
|
5022
|
+
return sessionManager.getTokenInfo();
|
|
5023
|
+
}, [sessionManager]);
|
|
5024
|
+
(0, import_react19.useEffect)(() => {
|
|
5025
|
+
initialize();
|
|
5026
|
+
}, [initialize]);
|
|
4921
5027
|
return {
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
5028
|
+
// Estado
|
|
5029
|
+
...state,
|
|
5030
|
+
// Acciones
|
|
5031
|
+
login,
|
|
5032
|
+
logout,
|
|
5033
|
+
refreshTokens,
|
|
5034
|
+
clearError,
|
|
5035
|
+
getTokenInfo,
|
|
5036
|
+
// Utilidades
|
|
5037
|
+
isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
|
|
5038
|
+
// 5 minutos
|
|
5039
|
+
expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
|
|
5040
|
+
refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
|
|
4927
5041
|
};
|
|
4928
|
-
}
|
|
5042
|
+
}
|
|
5043
|
+
|
|
5044
|
+
// src/providers/SessionProvider.tsx
|
|
5045
|
+
var import_react20 = require("react");
|
|
5046
|
+
init_jwtUtils();
|
|
5047
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
5048
|
+
var SessionContext = (0, import_react20.createContext)(void 0);
|
|
5049
|
+
function SessionProvider({ children, options = {} }) {
|
|
5050
|
+
const sessionHook = useSession(options);
|
|
5051
|
+
const sessionData = (0, import_react20.useMemo)(() => {
|
|
5052
|
+
if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
|
|
5053
|
+
return null;
|
|
5054
|
+
}
|
|
5055
|
+
try {
|
|
5056
|
+
const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
|
|
5057
|
+
if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
|
|
5058
|
+
const result = {
|
|
5059
|
+
_id: decoded.sub,
|
|
5060
|
+
email: decoded.email,
|
|
5061
|
+
subscriberKey: decoded.subscriber
|
|
5062
|
+
};
|
|
5063
|
+
Object.keys(decoded).forEach((key) => {
|
|
5064
|
+
if (!["sub", "email", "subscriber"].includes(key)) {
|
|
5065
|
+
result[key] = decoded[key];
|
|
5066
|
+
}
|
|
5067
|
+
});
|
|
5068
|
+
return result;
|
|
5069
|
+
}
|
|
5070
|
+
} catch (error) {
|
|
5071
|
+
console.error("Error decoding JWT token for sessionData:", error);
|
|
5072
|
+
}
|
|
5073
|
+
return null;
|
|
5074
|
+
}, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
|
|
5075
|
+
const contextValue = {
|
|
5076
|
+
...sessionHook,
|
|
5077
|
+
sessionData
|
|
5078
|
+
};
|
|
5079
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SessionContext.Provider, { value: contextValue, children });
|
|
5080
|
+
}
|
|
5081
|
+
function useSessionContext() {
|
|
5082
|
+
const context = (0, import_react20.useContext)(SessionContext);
|
|
5083
|
+
if (context === void 0) {
|
|
5084
|
+
throw new Error("useSessionContext must be used within a SessionProvider");
|
|
5085
|
+
}
|
|
5086
|
+
return context;
|
|
5087
|
+
}
|
|
5088
|
+
function ProtectedRoute({
|
|
5089
|
+
children,
|
|
5090
|
+
fallback = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { children: "Please log in to access this content" }),
|
|
5091
|
+
redirectTo
|
|
5092
|
+
}) {
|
|
5093
|
+
const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
|
|
5094
|
+
if (!isInitialized || isLoading) {
|
|
5095
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { children: "Loading..." });
|
|
5096
|
+
}
|
|
5097
|
+
if (!isAuthenticated) {
|
|
5098
|
+
if (redirectTo) {
|
|
5099
|
+
redirectTo();
|
|
5100
|
+
return null;
|
|
5101
|
+
}
|
|
5102
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: fallback });
|
|
5103
|
+
}
|
|
5104
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
5105
|
+
}
|
|
5106
|
+
function SessionDebugInfo() {
|
|
5107
|
+
const session = useSessionContext();
|
|
5108
|
+
if (!session.isInitialized) {
|
|
5109
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { children: "Session not initialized" });
|
|
5110
|
+
}
|
|
5111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: {
|
|
5112
|
+
padding: "10px",
|
|
5113
|
+
margin: "10px",
|
|
5114
|
+
border: "1px solid #ccc",
|
|
5115
|
+
borderRadius: "4px",
|
|
5116
|
+
fontSize: "12px",
|
|
5117
|
+
fontFamily: "monospace"
|
|
5118
|
+
}, children: [
|
|
5119
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h4", { children: "Session Debug Info" }),
|
|
5120
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5121
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Authenticated:" }),
|
|
5122
|
+
" ",
|
|
5123
|
+
session.isAuthenticated ? "Yes" : "No"
|
|
5124
|
+
] }),
|
|
5125
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5126
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Loading:" }),
|
|
5127
|
+
" ",
|
|
5128
|
+
session.isLoading ? "Yes" : "No"
|
|
5129
|
+
] }),
|
|
5130
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5131
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Error:" }),
|
|
5132
|
+
" ",
|
|
5133
|
+
session.error || "None"
|
|
5134
|
+
] }),
|
|
5135
|
+
session.tokens && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
5136
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5137
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Access Token:" }),
|
|
5138
|
+
" ",
|
|
5139
|
+
session.tokens.accessToken.substring(0, 20),
|
|
5140
|
+
"..."
|
|
5141
|
+
] }),
|
|
5142
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5143
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Refresh Token:" }),
|
|
5144
|
+
" ",
|
|
5145
|
+
session.tokens.refreshToken.substring(0, 20),
|
|
5146
|
+
"..."
|
|
5147
|
+
] }),
|
|
5148
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5149
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Access Expires In:" }),
|
|
5150
|
+
" ",
|
|
5151
|
+
Math.round(session.expiresIn / 1e3 / 60),
|
|
5152
|
+
" minutes"
|
|
5153
|
+
] }),
|
|
5154
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5155
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Refresh Expires In:" }),
|
|
5156
|
+
" ",
|
|
5157
|
+
Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
|
|
5158
|
+
" hours"
|
|
5159
|
+
] }),
|
|
5160
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
5161
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Expiring Soon:" }),
|
|
5162
|
+
" ",
|
|
5163
|
+
session.isExpiringSoon ? "Yes" : "No"
|
|
5164
|
+
] })
|
|
5165
|
+
] })
|
|
5166
|
+
] });
|
|
5167
|
+
}
|
|
4929
5168
|
|
|
4930
|
-
// src/
|
|
4931
|
-
var
|
|
4932
|
-
var
|
|
5169
|
+
// src/components/LoginComponent.tsx
|
|
5170
|
+
var import_react21 = require("react");
|
|
5171
|
+
var import_material11 = require("@mui/material");
|
|
5172
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
5173
|
+
function LoginComponent() {
|
|
5174
|
+
const [email, setEmail] = (0, import_react21.useState)("");
|
|
5175
|
+
const [password, setPassword] = (0, import_react21.useState)("");
|
|
5176
|
+
const [showForm, setShowForm] = (0, import_react21.useState)(false);
|
|
4933
5177
|
const {
|
|
4934
5178
|
isAuthenticated,
|
|
4935
5179
|
isLoading,
|
|
4936
|
-
isInitialized,
|
|
4937
|
-
tokens,
|
|
4938
5180
|
error,
|
|
4939
|
-
sessionData,
|
|
4940
5181
|
login,
|
|
4941
5182
|
logout,
|
|
4942
5183
|
refreshTokens,
|
|
4943
5184
|
clearError,
|
|
4944
|
-
getTokenInfo,
|
|
4945
|
-
isExpiringSoon,
|
|
4946
|
-
expiresIn,
|
|
4947
|
-
refreshExpiresIn
|
|
4948
|
-
} = useSessionContext();
|
|
4949
|
-
const setToken = (0, import_react20.useCallback)((token) => {
|
|
4950
|
-
if (token) {
|
|
4951
|
-
console.warn("useAuth.setToken() is deprecated. Use login() method instead for better security.");
|
|
4952
|
-
} else {
|
|
4953
|
-
logout();
|
|
4954
|
-
}
|
|
4955
|
-
}, [logout]);
|
|
4956
|
-
const tokenExpiration = tokens?.expiresAt ? new Date(tokens.expiresAt) : null;
|
|
4957
|
-
return {
|
|
4958
|
-
// Estado básico (compatible con legacy)
|
|
4959
|
-
isAuthenticated,
|
|
4960
|
-
loading: isLoading,
|
|
4961
|
-
// En el nuevo sistema se llama isLoading
|
|
4962
|
-
error,
|
|
4963
|
-
// Datos del token (compatible con legacy + mejorado)
|
|
4964
|
-
token: tokens?.accessToken || null,
|
|
4965
|
-
user: sessionData,
|
|
4966
|
-
// sessionData del nuevo sistema (más rico que legacy)
|
|
4967
|
-
tokenExpiration,
|
|
4968
|
-
// Acciones (compatible con legacy + mejorado)
|
|
4969
|
-
setToken,
|
|
4970
|
-
logout,
|
|
4971
|
-
refreshToken: refreshTokens,
|
|
4972
|
-
// Funcionalidad real en el nuevo sistema
|
|
4973
|
-
// Nuevas funcionalidades del sistema de refresh tokens
|
|
4974
|
-
login,
|
|
4975
5185
|
isExpiringSoon,
|
|
4976
|
-
expiresIn
|
|
4977
|
-
refreshExpiresIn,
|
|
4978
|
-
getTokenInfo,
|
|
4979
|
-
clearError
|
|
4980
|
-
};
|
|
4981
|
-
};
|
|
4982
|
-
|
|
4983
|
-
// src/hooks/useData.ts
|
|
4984
|
-
var import_react21 = require("react");
|
|
4985
|
-
var import_crudify_browser10 = __toESM(require("@nocios/crudify-browser"));
|
|
4986
|
-
var useData = () => {
|
|
4987
|
-
const {
|
|
4988
|
-
isInitialized,
|
|
4989
|
-
isLoading,
|
|
4990
|
-
error,
|
|
4991
|
-
isAuthenticated,
|
|
4992
|
-
login: sessionLogin
|
|
5186
|
+
expiresIn
|
|
4993
5187
|
} = useSessionContext();
|
|
4994
|
-
const
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
return new Promise((resolve, reject) => {
|
|
4999
|
-
const checkReady = () => {
|
|
5000
|
-
if (isReady()) {
|
|
5001
|
-
resolve();
|
|
5002
|
-
} else if (error) {
|
|
5003
|
-
reject(new Error(error));
|
|
5004
|
-
} else {
|
|
5005
|
-
setTimeout(checkReady, 100);
|
|
5006
|
-
}
|
|
5007
|
-
};
|
|
5008
|
-
checkReady();
|
|
5009
|
-
});
|
|
5010
|
-
}, [isReady, error]);
|
|
5011
|
-
const ensureReady = (0, import_react21.useCallback)(async () => {
|
|
5012
|
-
if (!isReady()) {
|
|
5013
|
-
throw new Error("System not ready. Check isInitialized, isLoading, and error states.");
|
|
5014
|
-
}
|
|
5015
|
-
}, [isReady]);
|
|
5016
|
-
const readItems = (0, import_react21.useCallback)(async (moduleKey, filter, options) => {
|
|
5017
|
-
await ensureReady();
|
|
5018
|
-
return await import_crudify_browser10.default.readItems(moduleKey, filter || {}, options);
|
|
5019
|
-
}, [ensureReady]);
|
|
5020
|
-
const readItem = (0, import_react21.useCallback)(async (moduleKey, filter, options) => {
|
|
5021
|
-
await ensureReady();
|
|
5022
|
-
return await import_crudify_browser10.default.readItem(moduleKey, filter, options);
|
|
5023
|
-
}, [ensureReady]);
|
|
5024
|
-
const createItem = (0, import_react21.useCallback)(async (moduleKey, data, options) => {
|
|
5025
|
-
await ensureReady();
|
|
5026
|
-
return await import_crudify_browser10.default.createItem(moduleKey, data, options);
|
|
5027
|
-
}, [ensureReady]);
|
|
5028
|
-
const updateItem = (0, import_react21.useCallback)(async (moduleKey, data, options) => {
|
|
5029
|
-
await ensureReady();
|
|
5030
|
-
return await import_crudify_browser10.default.updateItem(moduleKey, data, options);
|
|
5031
|
-
}, [ensureReady]);
|
|
5032
|
-
const deleteItem = (0, import_react21.useCallback)(async (moduleKey, id, options) => {
|
|
5033
|
-
await ensureReady();
|
|
5034
|
-
return await import_crudify_browser10.default.deleteItem(moduleKey, id, options);
|
|
5035
|
-
}, [ensureReady]);
|
|
5036
|
-
const transaction = (0, import_react21.useCallback)(async (operations, options) => {
|
|
5037
|
-
await ensureReady();
|
|
5038
|
-
return await import_crudify_browser10.default.transaction(operations, options);
|
|
5039
|
-
}, [ensureReady]);
|
|
5040
|
-
const login = (0, import_react21.useCallback)(async (email, password) => {
|
|
5041
|
-
try {
|
|
5042
|
-
const result = await sessionLogin(email, password);
|
|
5043
|
-
if (result.success) {
|
|
5044
|
-
return {
|
|
5045
|
-
success: true,
|
|
5046
|
-
data: result.tokens
|
|
5047
|
-
};
|
|
5048
|
-
} else {
|
|
5049
|
-
return {
|
|
5050
|
-
success: false,
|
|
5051
|
-
errors: result.error || "Login failed"
|
|
5052
|
-
};
|
|
5053
|
-
}
|
|
5054
|
-
} catch (error2) {
|
|
5055
|
-
return {
|
|
5056
|
-
success: false,
|
|
5057
|
-
errors: error2 instanceof Error ? error2.message : "Login failed"
|
|
5058
|
-
};
|
|
5188
|
+
const handleLogin = async (e) => {
|
|
5189
|
+
e.preventDefault();
|
|
5190
|
+
if (!email || !password) {
|
|
5191
|
+
return;
|
|
5059
5192
|
}
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
createItem,
|
|
5066
|
-
updateItem,
|
|
5067
|
-
deleteItem,
|
|
5068
|
-
transaction,
|
|
5069
|
-
login,
|
|
5070
|
-
// Estado
|
|
5071
|
-
isInitialized,
|
|
5072
|
-
isInitializing: isLoading,
|
|
5073
|
-
// El nuevo sistema usa isLoading
|
|
5074
|
-
initializationError: error,
|
|
5075
|
-
// Utilidades
|
|
5076
|
-
isReady,
|
|
5077
|
-
waitForReady
|
|
5078
|
-
};
|
|
5079
|
-
};
|
|
5080
|
-
|
|
5081
|
-
// src/components/PublicPolicies/Policies.tsx
|
|
5082
|
-
var import_react24 = require("react");
|
|
5083
|
-
var import_react_i18next3 = require("react-i18next");
|
|
5084
|
-
var import_material11 = require("@mui/material");
|
|
5085
|
-
var import_icons_material4 = require("@mui/icons-material");
|
|
5086
|
-
|
|
5087
|
-
// src/components/PublicPolicies/PolicyItem/PolicyItem.tsx
|
|
5088
|
-
var import_react23 = require("react");
|
|
5089
|
-
var import_react_i18next2 = require("react-i18next");
|
|
5090
|
-
var import_material10 = require("@mui/material");
|
|
5091
|
-
var import_icons_material3 = require("@mui/icons-material");
|
|
5092
|
-
|
|
5093
|
-
// src/components/PublicPolicies/FieldSelector/FieldSelector.tsx
|
|
5094
|
-
var import_react22 = require("react");
|
|
5095
|
-
var import_react_i18next = require("react-i18next");
|
|
5096
|
-
var import_material9 = require("@mui/material");
|
|
5097
|
-
var import_icons_material2 = require("@mui/icons-material");
|
|
5098
|
-
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
5099
|
-
var FieldSelector = ({
|
|
5100
|
-
value,
|
|
5101
|
-
onChange,
|
|
5102
|
-
availableFields,
|
|
5103
|
-
error,
|
|
5104
|
-
disabled = false
|
|
5105
|
-
}) => {
|
|
5106
|
-
const { t } = (0, import_react_i18next.useTranslation)();
|
|
5107
|
-
const [mode, setMode] = (0, import_react22.useState)("custom");
|
|
5108
|
-
const isUpdatingRef = (0, import_react22.useRef)(false);
|
|
5109
|
-
(0, import_react22.useEffect)(() => {
|
|
5110
|
-
const current = value || { allow: [], owner_allow: [], deny: [] };
|
|
5111
|
-
const all = new Set(availableFields);
|
|
5112
|
-
const allow = (current.allow || []).filter((f) => all.has(f));
|
|
5113
|
-
const owner = (current.owner_allow || []).filter((f) => all.has(f));
|
|
5114
|
-
const deny = (current.deny || []).filter((f) => all.has(f));
|
|
5115
|
-
availableFields.forEach((f) => {
|
|
5116
|
-
if (!allow.includes(f) && !owner.includes(f) && !deny.includes(f)) deny.push(f);
|
|
5117
|
-
});
|
|
5118
|
-
const normalized = { allow, owner_allow: owner, deny };
|
|
5119
|
-
if (JSON.stringify(normalized) !== JSON.stringify(current)) {
|
|
5120
|
-
onChange(normalized);
|
|
5193
|
+
const result = await login(email, password);
|
|
5194
|
+
if (result.success) {
|
|
5195
|
+
setEmail("");
|
|
5196
|
+
setPassword("");
|
|
5197
|
+
setShowForm(false);
|
|
5121
5198
|
}
|
|
5122
|
-
if (allow.length === availableFields.length) setMode("all");
|
|
5123
|
-
else if (deny.length === availableFields.length) setMode("none");
|
|
5124
|
-
else setMode("custom");
|
|
5125
|
-
}, [availableFields, value]);
|
|
5126
|
-
const setAllAllow = () => {
|
|
5127
|
-
isUpdatingRef.current = true;
|
|
5128
|
-
onChange({ allow: [...availableFields], owner_allow: [], deny: [] });
|
|
5129
|
-
setMode("all");
|
|
5130
|
-
setTimeout(() => {
|
|
5131
|
-
isUpdatingRef.current = false;
|
|
5132
|
-
}, 0);
|
|
5133
|
-
};
|
|
5134
|
-
const setAllDeny = () => {
|
|
5135
|
-
isUpdatingRef.current = true;
|
|
5136
|
-
onChange({ allow: [], owner_allow: [], deny: [...availableFields] });
|
|
5137
|
-
setMode("none");
|
|
5138
|
-
setTimeout(() => {
|
|
5139
|
-
isUpdatingRef.current = false;
|
|
5140
|
-
}, 0);
|
|
5141
5199
|
};
|
|
5142
|
-
const
|
|
5143
|
-
|
|
5144
|
-
if (value?.owner_allow?.includes(fieldName)) return "owner_allow";
|
|
5145
|
-
return "deny";
|
|
5200
|
+
const handleLogout = async () => {
|
|
5201
|
+
await logout();
|
|
5146
5202
|
};
|
|
5147
|
-
const
|
|
5148
|
-
|
|
5149
|
-
const allow = new Set(value?.allow || []);
|
|
5150
|
-
const owner = new Set(value?.owner_allow || []);
|
|
5151
|
-
const deny = new Set(value?.deny || []);
|
|
5152
|
-
allow.delete(fieldName);
|
|
5153
|
-
owner.delete(fieldName);
|
|
5154
|
-
deny.delete(fieldName);
|
|
5155
|
-
if (state === "allow") allow.add(fieldName);
|
|
5156
|
-
if (state === "owner_allow") owner.add(fieldName);
|
|
5157
|
-
if (state === "deny") deny.add(fieldName);
|
|
5158
|
-
onChange({ allow: Array.from(allow), owner_allow: Array.from(owner), deny: Array.from(deny) });
|
|
5159
|
-
setMode("custom");
|
|
5160
|
-
setTimeout(() => {
|
|
5161
|
-
isUpdatingRef.current = false;
|
|
5162
|
-
}, 0);
|
|
5203
|
+
const handleRefreshTokens = async () => {
|
|
5204
|
+
await refreshTokens();
|
|
5163
5205
|
};
|
|
5164
|
-
if (
|
|
5165
|
-
return /* @__PURE__ */ (0,
|
|
5166
|
-
/* @__PURE__ */ (0,
|
|
5167
|
-
/* @__PURE__ */ (0,
|
|
5168
|
-
|
|
5206
|
+
if (isAuthenticated) {
|
|
5207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { sx: { maxWidth: 600, mx: "auto", p: 3 }, children: [
|
|
5208
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Typography, { variant: "h4", gutterBottom: true, children: "Welcome! \u{1F389}" }),
|
|
5209
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Alert, { severity: "success", sx: { mb: 3 }, children: "You are successfully logged in with Refresh Token Pattern enabled" }),
|
|
5210
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { sx: { mb: 3, p: 2, bgcolor: "background.paper", border: 1, borderColor: "divider", borderRadius: 1 }, children: [
|
|
5211
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Typography, { variant: "h6", gutterBottom: true, children: "Token Status" }),
|
|
5212
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Typography, { variant: "body2", color: "text.secondary", children: [
|
|
5213
|
+
"Access Token expires in: ",
|
|
5214
|
+
Math.round(expiresIn / 1e3 / 60),
|
|
5215
|
+
" minutes"
|
|
5216
|
+
] }),
|
|
5217
|
+
isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Alert, { severity: "warning", sx: { mt: 1 }, children: "Token expires soon - automatic refresh will happen" })
|
|
5218
|
+
] }),
|
|
5219
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { sx: { display: "flex", gap: 2, flexWrap: "wrap" }, children: [
|
|
5220
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5221
|
+
import_material11.Button,
|
|
5222
|
+
{
|
|
5223
|
+
variant: "contained",
|
|
5224
|
+
onClick: handleRefreshTokens,
|
|
5225
|
+
disabled: isLoading,
|
|
5226
|
+
startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.CircularProgress, { size: 16 }) : null,
|
|
5227
|
+
children: "Refresh Tokens"
|
|
5228
|
+
}
|
|
5229
|
+
),
|
|
5230
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5231
|
+
import_material11.Button,
|
|
5232
|
+
{
|
|
5233
|
+
variant: "outlined",
|
|
5234
|
+
color: "error",
|
|
5235
|
+
onClick: handleLogout,
|
|
5236
|
+
disabled: isLoading,
|
|
5237
|
+
children: "Logout"
|
|
5238
|
+
}
|
|
5239
|
+
)
|
|
5240
|
+
] }),
|
|
5241
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
|
|
5169
5242
|
] });
|
|
5170
5243
|
}
|
|
5171
|
-
return /* @__PURE__ */ (0,
|
|
5172
|
-
/* @__PURE__ */ (0,
|
|
5173
|
-
/* @__PURE__ */ (0,
|
|
5174
|
-
|
|
5175
|
-
|
|
5244
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { sx: { maxWidth: 400, mx: "auto", p: 3 }, children: [
|
|
5245
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Typography, { variant: "h4", gutterBottom: true, align: "center", children: "Login with Refresh Tokens" }),
|
|
5246
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Alert, { severity: "info", sx: { mb: 3 }, children: "This demo shows the new Refresh Token Pattern with automatic session management" }),
|
|
5247
|
+
!showForm ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5248
|
+
import_material11.Button,
|
|
5249
|
+
{
|
|
5250
|
+
fullWidth: true,
|
|
5251
|
+
variant: "contained",
|
|
5252
|
+
size: "large",
|
|
5253
|
+
onClick: () => setShowForm(true),
|
|
5254
|
+
sx: { mt: 2 },
|
|
5255
|
+
children: "Show Login Form"
|
|
5256
|
+
}
|
|
5257
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("form", { onSubmit: handleLogin, children: [
|
|
5258
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5259
|
+
import_material11.TextField,
|
|
5176
5260
|
{
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
backgroundColor: "#16a34a",
|
|
5186
|
-
"&:hover": { backgroundColor: "#15803d" }
|
|
5187
|
-
}
|
|
5188
|
-
},
|
|
5189
|
-
children: t("modules.form.publicPolicies.fields.conditions.allFields")
|
|
5261
|
+
fullWidth: true,
|
|
5262
|
+
label: "Email",
|
|
5263
|
+
type: "email",
|
|
5264
|
+
value: email,
|
|
5265
|
+
onChange: (e) => setEmail(e.target.value),
|
|
5266
|
+
margin: "normal",
|
|
5267
|
+
required: true,
|
|
5268
|
+
autoComplete: "email"
|
|
5190
5269
|
}
|
|
5191
5270
|
),
|
|
5192
|
-
/* @__PURE__ */ (0,
|
|
5193
|
-
|
|
5271
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5272
|
+
import_material11.TextField,
|
|
5194
5273
|
{
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5274
|
+
fullWidth: true,
|
|
5275
|
+
label: "Password",
|
|
5276
|
+
type: "password",
|
|
5277
|
+
value: password,
|
|
5278
|
+
onChange: (e) => setPassword(e.target.value),
|
|
5279
|
+
margin: "normal",
|
|
5280
|
+
required: true,
|
|
5281
|
+
autoComplete: "current-password"
|
|
5282
|
+
}
|
|
5283
|
+
),
|
|
5284
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5285
|
+
import_material11.Button,
|
|
5286
|
+
{
|
|
5287
|
+
type: "submit",
|
|
5288
|
+
fullWidth: true,
|
|
5289
|
+
variant: "contained",
|
|
5290
|
+
size: "large",
|
|
5291
|
+
disabled: isLoading,
|
|
5292
|
+
startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.CircularProgress, { size: 16 }) : null,
|
|
5293
|
+
sx: { mt: 3, mb: 2 },
|
|
5294
|
+
children: isLoading ? "Logging in..." : "Login"
|
|
5208
5295
|
}
|
|
5209
5296
|
)
|
|
5210
5297
|
] }),
|
|
5211
|
-
/* @__PURE__ */ (0,
|
|
5212
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.help") }),
|
|
5213
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.Stack, { spacing: 1, children: availableFields.map((fieldName) => {
|
|
5214
|
-
const fieldState = getFieldState(fieldName);
|
|
5215
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material9.Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
|
|
5216
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.Typography, { variant: "body2", sx: { minWidth: 100, fontFamily: "monospace" }, children: fieldName }),
|
|
5217
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material9.ToggleButtonGroup, { value: fieldState, exclusive: true, size: "small", children: [
|
|
5218
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
5219
|
-
import_material9.ToggleButton,
|
|
5220
|
-
{
|
|
5221
|
-
value: "allow",
|
|
5222
|
-
onClick: () => setFieldState(fieldName, "allow"),
|
|
5223
|
-
disabled,
|
|
5224
|
-
sx: {
|
|
5225
|
-
px: 2,
|
|
5226
|
-
color: fieldState === "allow" ? "#ffffff" : "#6b7280",
|
|
5227
|
-
backgroundColor: fieldState === "allow" ? "#16a34a" : "#f3f4f6",
|
|
5228
|
-
borderColor: fieldState === "allow" ? "#16a34a" : "#d1d5db",
|
|
5229
|
-
"&:hover": {
|
|
5230
|
-
backgroundColor: fieldState === "allow" ? "#15803d" : "#e5e7eb",
|
|
5231
|
-
borderColor: fieldState === "allow" ? "#15803d" : "#9ca3af"
|
|
5232
|
-
},
|
|
5233
|
-
"&.Mui-selected": {
|
|
5234
|
-
backgroundColor: "#16a34a",
|
|
5235
|
-
color: "#ffffff",
|
|
5236
|
-
"&:hover": {
|
|
5237
|
-
backgroundColor: "#15803d"
|
|
5238
|
-
}
|
|
5239
|
-
}
|
|
5240
|
-
},
|
|
5241
|
-
children: [
|
|
5242
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material2.CheckCircle, { sx: { fontSize: 16, mr: 0.5 } }),
|
|
5243
|
-
t("modules.form.publicPolicies.fields.conditions.states.allow")
|
|
5244
|
-
]
|
|
5245
|
-
}
|
|
5246
|
-
),
|
|
5247
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5248
|
-
import_material9.ToggleButton,
|
|
5249
|
-
{
|
|
5250
|
-
value: "owner_allow",
|
|
5251
|
-
onClick: () => setFieldState(fieldName, "owner_allow"),
|
|
5252
|
-
disabled,
|
|
5253
|
-
sx: {
|
|
5254
|
-
px: 2,
|
|
5255
|
-
color: fieldState === "owner_allow" ? "#ffffff" : "#6b7280",
|
|
5256
|
-
backgroundColor: fieldState === "owner_allow" ? "#0ea5e9" : "#f3f4f6",
|
|
5257
|
-
borderColor: fieldState === "owner_allow" ? "#0ea5e9" : "#d1d5db",
|
|
5258
|
-
"&:hover": {
|
|
5259
|
-
backgroundColor: fieldState === "owner_allow" ? "#0284c7" : "#e5e7eb",
|
|
5260
|
-
borderColor: fieldState === "owner_allow" ? "#0284c7" : "#9ca3af"
|
|
5261
|
-
},
|
|
5262
|
-
"&.Mui-selected": {
|
|
5263
|
-
backgroundColor: "#0ea5e9",
|
|
5264
|
-
color: "#ffffff",
|
|
5265
|
-
"&:hover": {
|
|
5266
|
-
backgroundColor: "#0284c7"
|
|
5267
|
-
}
|
|
5268
|
-
}
|
|
5269
|
-
},
|
|
5270
|
-
children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
|
|
5271
|
-
}
|
|
5272
|
-
),
|
|
5273
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
5274
|
-
import_material9.ToggleButton,
|
|
5275
|
-
{
|
|
5276
|
-
value: "deny",
|
|
5277
|
-
onClick: () => setFieldState(fieldName, "deny"),
|
|
5278
|
-
disabled,
|
|
5279
|
-
sx: {
|
|
5280
|
-
px: 2,
|
|
5281
|
-
color: fieldState === "deny" ? "#ffffff" : "#6b7280",
|
|
5282
|
-
backgroundColor: fieldState === "deny" ? "#dc2626" : "#f3f4f6",
|
|
5283
|
-
borderColor: fieldState === "deny" ? "#dc2626" : "#d1d5db",
|
|
5284
|
-
"&:hover": {
|
|
5285
|
-
backgroundColor: fieldState === "deny" ? "#b91c1c" : "#e5e7eb",
|
|
5286
|
-
borderColor: fieldState === "deny" ? "#b91c1c" : "#9ca3af"
|
|
5287
|
-
},
|
|
5288
|
-
"&.Mui-selected": {
|
|
5289
|
-
backgroundColor: "#dc2626",
|
|
5290
|
-
color: "#ffffff",
|
|
5291
|
-
"&:hover": {
|
|
5292
|
-
backgroundColor: "#b91c1c"
|
|
5293
|
-
}
|
|
5294
|
-
}
|
|
5295
|
-
},
|
|
5296
|
-
children: [
|
|
5297
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material2.Cancel, { sx: { fontSize: 16, mr: 0.5 } }),
|
|
5298
|
-
t("modules.form.publicPolicies.fields.conditions.states.deny")
|
|
5299
|
-
]
|
|
5300
|
-
}
|
|
5301
|
-
)
|
|
5302
|
-
] })
|
|
5303
|
-
] }, fieldName);
|
|
5304
|
-
}) })
|
|
5305
|
-
] }),
|
|
5306
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.FormHelperText, { error: true, sx: { mt: 1 }, children: error })
|
|
5298
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
|
|
5307
5299
|
] });
|
|
5308
|
-
}
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5300
|
+
}
|
|
5301
|
+
function SessionStatus() {
|
|
5302
|
+
const { isAuthenticated, isLoading, isExpiringSoon, expiresIn } = useSessionContext();
|
|
5303
|
+
if (isLoading) {
|
|
5304
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
|
5305
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.CircularProgress, { size: 16 }),
|
|
5306
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Typography, { variant: "caption", children: "Loading session..." })
|
|
5307
|
+
] });
|
|
5308
|
+
}
|
|
5309
|
+
if (!isAuthenticated) {
|
|
5310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Typography, { variant: "caption", color: "text.secondary", children: "Not logged in" });
|
|
5311
|
+
}
|
|
5312
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { children: [
|
|
5313
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Typography, { variant: "caption", color: "success.main", children: "\u2713 Authenticated" }),
|
|
5314
|
+
isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Typography, { variant: "caption", color: "warning.main", display: "block", children: [
|
|
5315
|
+
"\u26A0 Token expires in ",
|
|
5316
|
+
Math.round(expiresIn / 1e3 / 60),
|
|
5317
|
+
" min"
|
|
5318
|
+
] })
|
|
5319
|
+
] });
|
|
5320
|
+
}
|
|
5319
5321
|
|
|
5320
|
-
// src/
|
|
5321
|
-
var
|
|
5322
|
-
var
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
const
|
|
5332
|
-
const
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5322
|
+
// src/hooks/useUserData.ts
|
|
5323
|
+
var import_react22 = require("react");
|
|
5324
|
+
var import_crudify_browser9 = __toESM(require("@nocios/crudify-browser"));
|
|
5325
|
+
var useUserData = (options = {}) => {
|
|
5326
|
+
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
5327
|
+
const { isAuthenticated, isInitialized, sessionData, tokens } = useSessionContext();
|
|
5328
|
+
const [userData, setUserData] = (0, import_react22.useState)(null);
|
|
5329
|
+
const [loading, setLoading] = (0, import_react22.useState)(false);
|
|
5330
|
+
const [error, setError] = (0, import_react22.useState)(null);
|
|
5331
|
+
const abortControllerRef = (0, import_react22.useRef)(null);
|
|
5332
|
+
const mountedRef = (0, import_react22.useRef)(true);
|
|
5333
|
+
const requestIdRef = (0, import_react22.useRef)(0);
|
|
5334
|
+
const retryCountRef = (0, import_react22.useRef)(0);
|
|
5335
|
+
const getUserEmail = (0, import_react22.useCallback)(() => {
|
|
5336
|
+
if (!sessionData) return null;
|
|
5337
|
+
return sessionData.email || sessionData["cognito:username"] || null;
|
|
5338
|
+
}, [sessionData]);
|
|
5339
|
+
const clearProfile = (0, import_react22.useCallback)(() => {
|
|
5340
|
+
setUserData(null);
|
|
5341
|
+
setError(null);
|
|
5342
|
+
setLoading(false);
|
|
5343
|
+
retryCountRef.current = 0;
|
|
5344
|
+
}, []);
|
|
5345
|
+
const refreshProfile = (0, import_react22.useCallback)(async () => {
|
|
5346
|
+
const userEmail = getUserEmail();
|
|
5347
|
+
console.log("\u{1F464} useUserData - Refreshing profile for:", userEmail);
|
|
5348
|
+
if (!userEmail) {
|
|
5349
|
+
if (mountedRef.current) {
|
|
5350
|
+
setError("No user email available from session data");
|
|
5351
|
+
setLoading(false);
|
|
5352
|
+
}
|
|
5353
|
+
return;
|
|
5354
|
+
}
|
|
5355
|
+
if (!isInitialized) {
|
|
5356
|
+
if (mountedRef.current) {
|
|
5357
|
+
setError("Session not initialized");
|
|
5358
|
+
setLoading(false);
|
|
5359
|
+
}
|
|
5360
|
+
return;
|
|
5361
|
+
}
|
|
5362
|
+
if (abortControllerRef.current) {
|
|
5363
|
+
abortControllerRef.current.abort();
|
|
5364
|
+
}
|
|
5365
|
+
const abortController = new AbortController();
|
|
5366
|
+
abortControllerRef.current = abortController;
|
|
5367
|
+
const currentRequestId = ++requestIdRef.current;
|
|
5368
|
+
try {
|
|
5369
|
+
if (mountedRef.current) {
|
|
5370
|
+
setLoading(true);
|
|
5371
|
+
setError(null);
|
|
5372
|
+
}
|
|
5373
|
+
console.log("\u{1F464} useUserData - Fetching profile data from database");
|
|
5374
|
+
const response = await import_crudify_browser9.default.readItems("users", {
|
|
5375
|
+
filter: { email: userEmail },
|
|
5376
|
+
pagination: { limit: 1 }
|
|
5377
|
+
});
|
|
5378
|
+
console.log("\u{1F464} useUserData - Database response:", response);
|
|
5379
|
+
console.log("\u{1F464} useUserData - response.data:", response.data);
|
|
5380
|
+
console.log("\u{1F464} useUserData - response.data type:", typeof response.data);
|
|
5381
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
|
|
5382
|
+
let userData2 = null;
|
|
5383
|
+
if (response.success) {
|
|
5384
|
+
console.log("\u{1F464} useUserData - Processing successful response:", {
|
|
5385
|
+
dataType: typeof response.data,
|
|
5386
|
+
isArray: Array.isArray(response.data),
|
|
5387
|
+
hasResponse: !!response.data?.response,
|
|
5388
|
+
hasResponseData: !!response.data?.response?.data,
|
|
5389
|
+
responseDataType: typeof response.data?.response?.data
|
|
5390
|
+
});
|
|
5391
|
+
if (Array.isArray(response.data) && response.data.length > 0) {
|
|
5392
|
+
console.log("\u{1F464} useUserData - Found direct array format");
|
|
5393
|
+
userData2 = response.data[0];
|
|
5394
|
+
} else if (response.data?.response?.data) {
|
|
5395
|
+
console.log("\u{1F464} useUserData - Found nested response.data format");
|
|
5396
|
+
try {
|
|
5397
|
+
const rawData = response.data.response.data;
|
|
5398
|
+
console.log("\u{1F464} useUserData - Raw nested data:", rawData);
|
|
5399
|
+
console.log("\u{1F464} useUserData - Raw data type:", typeof rawData);
|
|
5400
|
+
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
5401
|
+
console.log("\u{1F464} useUserData - Parsed nested data:", parsedData);
|
|
5402
|
+
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
5403
|
+
userData2 = parsedData.items[0];
|
|
5404
|
+
console.log("\u{1F464} useUserData - Extracted user from nested items:", userData2);
|
|
5405
|
+
} else {
|
|
5406
|
+
console.log("\u{1F464} useUserData - No items found in parsed data or items array is empty");
|
|
5407
|
+
}
|
|
5408
|
+
} catch (parseError) {
|
|
5409
|
+
console.error("\u{1F464} useUserData - Error parsing nested response data:", parseError);
|
|
5361
5410
|
}
|
|
5362
|
-
)
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
"aria-label": t("modules.form.publicPolicies.removePolicy"),
|
|
5370
|
-
sx: {
|
|
5371
|
-
color: "#656d76",
|
|
5372
|
-
"&:hover": {
|
|
5373
|
-
color: "#cf222e",
|
|
5374
|
-
backgroundColor: "rgba(207, 34, 46, 0.1)"
|
|
5375
|
-
}
|
|
5376
|
-
},
|
|
5377
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons_material3.Delete, {})
|
|
5411
|
+
} else if (response.data && typeof response.data === "object") {
|
|
5412
|
+
console.log("\u{1F464} useUserData - Found object format, checking for items");
|
|
5413
|
+
if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
|
|
5414
|
+
console.log("\u{1F464} useUserData - Found items in object format");
|
|
5415
|
+
userData2 = response.data.items[0];
|
|
5416
|
+
} else {
|
|
5417
|
+
console.log("\u{1F464} useUserData - No items found in object format");
|
|
5378
5418
|
}
|
|
5379
|
-
)
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
{
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
disabled: isSubmitting,
|
|
5390
|
-
onChange: (e) => {
|
|
5391
|
-
const newAction = e.target.value;
|
|
5392
|
-
const next = { ...policy, action: newAction };
|
|
5393
|
-
if (newAction === "delete") {
|
|
5394
|
-
next.permission = "deny";
|
|
5395
|
-
delete next.fields;
|
|
5396
|
-
} else {
|
|
5397
|
-
next.fields = { allow: [], owner_allow: [], deny: availableFields };
|
|
5398
|
-
delete next.permission;
|
|
5399
|
-
}
|
|
5400
|
-
onChange(next);
|
|
5401
|
-
},
|
|
5402
|
-
sx: {
|
|
5403
|
-
backgroundColor: "#ffffff",
|
|
5404
|
-
"&:hover .MuiOutlinedInput-notchedOutline": {
|
|
5405
|
-
borderColor: "#8c959f"
|
|
5406
|
-
},
|
|
5407
|
-
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
|
5408
|
-
borderColor: "#0969da",
|
|
5409
|
-
borderWidth: 2
|
|
5410
|
-
}
|
|
5411
|
-
},
|
|
5412
|
-
children: actionOptions.map((option) => {
|
|
5413
|
-
const disabledOption = takenActions.has(option.value);
|
|
5414
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.MenuItem, { value: option.value, disabled: disabledOption, children: option.label }, option.value);
|
|
5415
|
-
})
|
|
5419
|
+
} else if (response.data?.data?.response?.data) {
|
|
5420
|
+
console.log("\u{1F464} useUserData - Found double-nested data.data.response.data format");
|
|
5421
|
+
try {
|
|
5422
|
+
const rawData = response.data.data.response.data;
|
|
5423
|
+
console.log("\u{1F464} useUserData - Raw double-nested data:", rawData);
|
|
5424
|
+
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
5425
|
+
console.log("\u{1F464} useUserData - Parsed double-nested data:", parsedData);
|
|
5426
|
+
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
5427
|
+
userData2 = parsedData.items[0];
|
|
5428
|
+
console.log("\u{1F464} useUserData - Extracted user from double-nested items:", userData2);
|
|
5416
5429
|
}
|
|
5417
|
-
)
|
|
5418
|
-
|
|
5419
|
-
] }) }) }),
|
|
5420
|
-
policy.action === "delete" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Box, { children: [
|
|
5421
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
|
|
5422
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
|
|
5423
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5424
|
-
import_material10.Button,
|
|
5425
|
-
{
|
|
5426
|
-
variant: policy.permission === "*" ? "contained" : "outlined",
|
|
5427
|
-
startIcon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons_material3.SelectAll, {}),
|
|
5428
|
-
onClick: () => onChange({ ...policy, permission: "*" }),
|
|
5429
|
-
disabled: isSubmitting,
|
|
5430
|
-
size: "small",
|
|
5431
|
-
sx: {
|
|
5432
|
-
minWidth: 140,
|
|
5433
|
-
whiteSpace: "nowrap",
|
|
5434
|
-
...policy.permission === "*" && {
|
|
5435
|
-
backgroundColor: "#16a34a",
|
|
5436
|
-
"&:hover": { backgroundColor: "#15803d" }
|
|
5437
|
-
}
|
|
5438
|
-
},
|
|
5439
|
-
children: t("modules.form.publicPolicies.fields.conditions.allFields")
|
|
5440
|
-
}
|
|
5441
|
-
),
|
|
5442
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5443
|
-
import_material10.Button,
|
|
5444
|
-
{
|
|
5445
|
-
variant: policy.permission === "owner" ? "contained" : "outlined",
|
|
5446
|
-
onClick: () => onChange({ ...policy, permission: "owner" }),
|
|
5447
|
-
disabled: isSubmitting,
|
|
5448
|
-
size: "small",
|
|
5449
|
-
sx: {
|
|
5450
|
-
minWidth: 140,
|
|
5451
|
-
whiteSpace: "nowrap",
|
|
5452
|
-
...policy.permission === "owner" && {
|
|
5453
|
-
backgroundColor: "#0ea5e9",
|
|
5454
|
-
"&:hover": { backgroundColor: "#0284c7" }
|
|
5455
|
-
}
|
|
5456
|
-
},
|
|
5457
|
-
children: t("modules.form.publicPolicies.fields.conditions.states.ownerAllow")
|
|
5458
|
-
}
|
|
5459
|
-
),
|
|
5460
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5461
|
-
import_material10.Button,
|
|
5462
|
-
{
|
|
5463
|
-
variant: policy.permission === "deny" ? "contained" : "outlined",
|
|
5464
|
-
startIcon: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons_material3.ClearAll, {}),
|
|
5465
|
-
onClick: () => onChange({ ...policy, permission: "deny" }),
|
|
5466
|
-
disabled: isSubmitting,
|
|
5467
|
-
size: "small",
|
|
5468
|
-
sx: {
|
|
5469
|
-
minWidth: 140,
|
|
5470
|
-
whiteSpace: "nowrap",
|
|
5471
|
-
...policy.permission === "deny" && {
|
|
5472
|
-
backgroundColor: "#cf222e",
|
|
5473
|
-
"&:hover": { backgroundColor: "#bc1f2c" }
|
|
5474
|
-
}
|
|
5475
|
-
},
|
|
5476
|
-
children: t("modules.form.publicPolicies.fields.conditions.noFields")
|
|
5477
|
-
}
|
|
5478
|
-
)
|
|
5479
|
-
] })
|
|
5480
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5481
|
-
FieldSelector_default,
|
|
5482
|
-
{
|
|
5483
|
-
value: policy.fields || { allow: [], owner_allow: [], deny: [] },
|
|
5484
|
-
onChange: (nextFields) => onChange({ ...policy, fields: nextFields }),
|
|
5485
|
-
availableFields,
|
|
5486
|
-
disabled: isSubmitting
|
|
5430
|
+
} catch (parseError) {
|
|
5431
|
+
console.error("\u{1F464} useUserData - Error parsing double-nested response data:", parseError);
|
|
5487
5432
|
}
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
}
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
const takenActions = new Set((policies || []).map((p) => p.action).filter(Boolean));
|
|
5548
|
-
const remainingActions = PREFERRED_POLICY_ORDER.filter((a) => !takenActions.has(a));
|
|
5549
|
-
const canAddPolicy = remainingActions.length > 0;
|
|
5550
|
-
const addPolicy = () => {
|
|
5551
|
-
const defaultAction = remainingActions[0] || "create";
|
|
5552
|
-
const newPolicy = {
|
|
5553
|
-
id: generateId(),
|
|
5554
|
-
action: defaultAction
|
|
5433
|
+
}
|
|
5434
|
+
}
|
|
5435
|
+
if (userData2) {
|
|
5436
|
+
console.log("\u{1F464} useUserData - User data found:", userData2);
|
|
5437
|
+
setUserData(userData2);
|
|
5438
|
+
setError(null);
|
|
5439
|
+
retryCountRef.current = 0;
|
|
5440
|
+
console.log("\u{1F464} useUserData - Profile loaded successfully:", userData2);
|
|
5441
|
+
} else {
|
|
5442
|
+
setError("User profile not found in database");
|
|
5443
|
+
setUserData(null);
|
|
5444
|
+
console.warn("\u{1F464} useUserData - User not found for email:", userEmail);
|
|
5445
|
+
}
|
|
5446
|
+
}
|
|
5447
|
+
} catch (err) {
|
|
5448
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
5449
|
+
const error2 = err;
|
|
5450
|
+
console.error("\u{1F464} useUserData - Error fetching profile:", error2);
|
|
5451
|
+
if (error2.name === "AbortError") {
|
|
5452
|
+
return;
|
|
5453
|
+
}
|
|
5454
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
|
|
5455
|
+
if (shouldRetry) {
|
|
5456
|
+
retryCountRef.current++;
|
|
5457
|
+
console.log(`\u{1F464} useUserData - Retrying profile fetch (${retryCountRef.current}/${maxRetries})`);
|
|
5458
|
+
setTimeout(() => {
|
|
5459
|
+
if (mountedRef.current) {
|
|
5460
|
+
refreshProfile();
|
|
5461
|
+
}
|
|
5462
|
+
}, 1e3 * retryCountRef.current);
|
|
5463
|
+
} else {
|
|
5464
|
+
setError("Failed to load user profile from database");
|
|
5465
|
+
setUserData(null);
|
|
5466
|
+
}
|
|
5467
|
+
}
|
|
5468
|
+
} finally {
|
|
5469
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
5470
|
+
setLoading(false);
|
|
5471
|
+
}
|
|
5472
|
+
if (abortControllerRef.current === abortController) {
|
|
5473
|
+
abortControllerRef.current = null;
|
|
5474
|
+
}
|
|
5475
|
+
}
|
|
5476
|
+
}, [isInitialized, getUserEmail, retryOnError, maxRetries]);
|
|
5477
|
+
(0, import_react22.useEffect)(() => {
|
|
5478
|
+
if (autoFetch && isAuthenticated && isInitialized) {
|
|
5479
|
+
refreshProfile();
|
|
5480
|
+
} else if (!isAuthenticated) {
|
|
5481
|
+
clearProfile();
|
|
5482
|
+
}
|
|
5483
|
+
}, [autoFetch, isAuthenticated, isInitialized, refreshProfile, clearProfile]);
|
|
5484
|
+
(0, import_react22.useEffect)(() => {
|
|
5485
|
+
mountedRef.current = true;
|
|
5486
|
+
return () => {
|
|
5487
|
+
mountedRef.current = false;
|
|
5488
|
+
if (abortControllerRef.current) {
|
|
5489
|
+
abortControllerRef.current.abort();
|
|
5490
|
+
abortControllerRef.current = null;
|
|
5491
|
+
}
|
|
5555
5492
|
};
|
|
5556
|
-
|
|
5557
|
-
|
|
5493
|
+
}, []);
|
|
5494
|
+
const user = {
|
|
5495
|
+
session: sessionData,
|
|
5496
|
+
// Usar sessionData del nuevo sistema
|
|
5497
|
+
data: userData
|
|
5498
|
+
// Mantener userData del database igual que legacy
|
|
5499
|
+
};
|
|
5500
|
+
return {
|
|
5501
|
+
user,
|
|
5502
|
+
loading,
|
|
5503
|
+
error,
|
|
5504
|
+
refreshProfile,
|
|
5505
|
+
clearProfile
|
|
5506
|
+
};
|
|
5507
|
+
};
|
|
5508
|
+
|
|
5509
|
+
// src/hooks/useAuth.ts
|
|
5510
|
+
var import_react23 = require("react");
|
|
5511
|
+
var useAuth = () => {
|
|
5512
|
+
const {
|
|
5513
|
+
isAuthenticated,
|
|
5514
|
+
isLoading,
|
|
5515
|
+
isInitialized,
|
|
5516
|
+
tokens,
|
|
5517
|
+
error,
|
|
5518
|
+
sessionData,
|
|
5519
|
+
login,
|
|
5520
|
+
logout,
|
|
5521
|
+
refreshTokens,
|
|
5522
|
+
clearError,
|
|
5523
|
+
getTokenInfo,
|
|
5524
|
+
isExpiringSoon,
|
|
5525
|
+
expiresIn,
|
|
5526
|
+
refreshExpiresIn
|
|
5527
|
+
} = useSessionContext();
|
|
5528
|
+
const setToken = (0, import_react23.useCallback)((token) => {
|
|
5529
|
+
if (token) {
|
|
5530
|
+
console.warn("useAuth.setToken() is deprecated. Use login() method instead for better security.");
|
|
5558
5531
|
} else {
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5532
|
+
logout();
|
|
5533
|
+
}
|
|
5534
|
+
}, [logout]);
|
|
5535
|
+
const tokenExpiration = tokens?.expiresAt ? new Date(tokens.expiresAt) : null;
|
|
5536
|
+
return {
|
|
5537
|
+
// Estado básico (compatible con legacy)
|
|
5538
|
+
isAuthenticated,
|
|
5539
|
+
loading: isLoading,
|
|
5540
|
+
// En el nuevo sistema se llama isLoading
|
|
5541
|
+
error,
|
|
5542
|
+
// Datos del token (compatible con legacy + mejorado)
|
|
5543
|
+
token: tokens?.accessToken || null,
|
|
5544
|
+
user: sessionData,
|
|
5545
|
+
// sessionData del nuevo sistema (más rico que legacy)
|
|
5546
|
+
tokenExpiration,
|
|
5547
|
+
// Acciones (compatible con legacy + mejorado)
|
|
5548
|
+
setToken,
|
|
5549
|
+
logout,
|
|
5550
|
+
refreshToken: refreshTokens,
|
|
5551
|
+
// Funcionalidad real en el nuevo sistema
|
|
5552
|
+
// Nuevas funcionalidades del sistema de refresh tokens
|
|
5553
|
+
login,
|
|
5554
|
+
isExpiringSoon,
|
|
5555
|
+
expiresIn,
|
|
5556
|
+
refreshExpiresIn,
|
|
5557
|
+
getTokenInfo,
|
|
5558
|
+
clearError
|
|
5559
|
+
};
|
|
5560
|
+
};
|
|
5561
|
+
|
|
5562
|
+
// src/hooks/useData.ts
|
|
5563
|
+
var import_react24 = require("react");
|
|
5564
|
+
var import_crudify_browser10 = __toESM(require("@nocios/crudify-browser"));
|
|
5565
|
+
var useData = () => {
|
|
5566
|
+
const {
|
|
5567
|
+
isInitialized,
|
|
5568
|
+
isLoading,
|
|
5569
|
+
error,
|
|
5570
|
+
isAuthenticated,
|
|
5571
|
+
login: sessionLogin
|
|
5572
|
+
} = useSessionContext();
|
|
5573
|
+
const isReady = (0, import_react24.useCallback)(() => {
|
|
5574
|
+
return isInitialized && !isLoading && !error;
|
|
5575
|
+
}, [isInitialized, isLoading, error]);
|
|
5576
|
+
const waitForReady = (0, import_react24.useCallback)(async () => {
|
|
5577
|
+
return new Promise((resolve, reject) => {
|
|
5578
|
+
const checkReady = () => {
|
|
5579
|
+
if (isReady()) {
|
|
5580
|
+
resolve();
|
|
5581
|
+
} else if (error) {
|
|
5582
|
+
reject(new Error(error));
|
|
5583
|
+
} else {
|
|
5584
|
+
setTimeout(checkReady, 100);
|
|
5585
|
+
}
|
|
5563
5586
|
};
|
|
5587
|
+
checkReady();
|
|
5588
|
+
});
|
|
5589
|
+
}, [isReady, error]);
|
|
5590
|
+
const ensureReady = (0, import_react24.useCallback)(async () => {
|
|
5591
|
+
if (!isReady()) {
|
|
5592
|
+
throw new Error("System not ready. Check isInitialized, isLoading, and error states.");
|
|
5564
5593
|
}
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5594
|
+
}, [isReady]);
|
|
5595
|
+
const readItems = (0, import_react24.useCallback)(async (moduleKey, filter, options) => {
|
|
5596
|
+
await ensureReady();
|
|
5597
|
+
return await import_crudify_browser10.default.readItems(moduleKey, filter || {}, options);
|
|
5598
|
+
}, [ensureReady]);
|
|
5599
|
+
const readItem = (0, import_react24.useCallback)(async (moduleKey, filter, options) => {
|
|
5600
|
+
await ensureReady();
|
|
5601
|
+
return await import_crudify_browser10.default.readItem(moduleKey, filter, options);
|
|
5602
|
+
}, [ensureReady]);
|
|
5603
|
+
const createItem = (0, import_react24.useCallback)(async (moduleKey, data, options) => {
|
|
5604
|
+
await ensureReady();
|
|
5605
|
+
return await import_crudify_browser10.default.createItem(moduleKey, data, options);
|
|
5606
|
+
}, [ensureReady]);
|
|
5607
|
+
const updateItem = (0, import_react24.useCallback)(async (moduleKey, data, options) => {
|
|
5608
|
+
await ensureReady();
|
|
5609
|
+
return await import_crudify_browser10.default.updateItem(moduleKey, data, options);
|
|
5610
|
+
}, [ensureReady]);
|
|
5611
|
+
const deleteItem = (0, import_react24.useCallback)(async (moduleKey, id, options) => {
|
|
5612
|
+
await ensureReady();
|
|
5613
|
+
return await import_crudify_browser10.default.deleteItem(moduleKey, id, options);
|
|
5614
|
+
}, [ensureReady]);
|
|
5615
|
+
const transaction = (0, import_react24.useCallback)(async (operations, options) => {
|
|
5616
|
+
await ensureReady();
|
|
5617
|
+
return await import_crudify_browser10.default.transaction(operations, options);
|
|
5618
|
+
}, [ensureReady]);
|
|
5619
|
+
const login = (0, import_react24.useCallback)(async (email, password) => {
|
|
5620
|
+
try {
|
|
5621
|
+
const result = await sessionLogin(email, password);
|
|
5622
|
+
if (result.success) {
|
|
5623
|
+
return {
|
|
5624
|
+
success: true,
|
|
5625
|
+
data: result.tokens
|
|
5626
|
+
};
|
|
5627
|
+
} else {
|
|
5628
|
+
return {
|
|
5629
|
+
success: false,
|
|
5630
|
+
errors: result.error || "Login failed"
|
|
5631
|
+
};
|
|
5572
5632
|
}
|
|
5573
|
-
}
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5633
|
+
} catch (error2) {
|
|
5634
|
+
return {
|
|
5635
|
+
success: false,
|
|
5636
|
+
errors: error2 instanceof Error ? error2.message : "Login failed"
|
|
5637
|
+
};
|
|
5638
|
+
}
|
|
5639
|
+
}, [sessionLogin]);
|
|
5640
|
+
return {
|
|
5641
|
+
// CRUD operations
|
|
5642
|
+
readItems,
|
|
5643
|
+
readItem,
|
|
5644
|
+
createItem,
|
|
5645
|
+
updateItem,
|
|
5646
|
+
deleteItem,
|
|
5647
|
+
transaction,
|
|
5648
|
+
login,
|
|
5649
|
+
// Estado
|
|
5650
|
+
isInitialized,
|
|
5651
|
+
isInitializing: isLoading,
|
|
5652
|
+
// El nuevo sistema usa isLoading
|
|
5653
|
+
initializationError: error,
|
|
5654
|
+
// Utilidades
|
|
5655
|
+
isReady,
|
|
5656
|
+
waitForReady
|
|
5579
5657
|
};
|
|
5580
|
-
const arrayError = (() => {
|
|
5581
|
-
if (!errors) return null;
|
|
5582
|
-
if (typeof errors === "string") return errors;
|
|
5583
|
-
const msg = errors._error;
|
|
5584
|
-
return typeof msg === "string" ? msg : null;
|
|
5585
|
-
})();
|
|
5586
|
-
const usedActions = new Set((policies || []).map((p) => p.action));
|
|
5587
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
5588
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Divider, { sx: { borderColor: "#e0e4e7" } }),
|
|
5589
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { children: [
|
|
5590
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 3, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Box, { children: [
|
|
5591
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5592
|
-
import_material11.Typography,
|
|
5593
|
-
{
|
|
5594
|
-
variant: "h6",
|
|
5595
|
-
sx: {
|
|
5596
|
-
fontWeight: 600,
|
|
5597
|
-
color: "#111418",
|
|
5598
|
-
mb: 1
|
|
5599
|
-
},
|
|
5600
|
-
children: t("modules.form.publicPolicies.title")
|
|
5601
|
-
}
|
|
5602
|
-
),
|
|
5603
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5604
|
-
import_material11.Typography,
|
|
5605
|
-
{
|
|
5606
|
-
variant: "body2",
|
|
5607
|
-
color: "text.secondary",
|
|
5608
|
-
sx: { fontSize: "0.875rem" },
|
|
5609
|
-
children: t("modules.form.publicPolicies.description")
|
|
5610
|
-
}
|
|
5611
|
-
)
|
|
5612
|
-
] }) }),
|
|
5613
|
-
arrayError && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Alert, { severity: "error", sx: { mb: 3 }, children: arrayError }),
|
|
5614
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_material11.Stack, { spacing: 3, children: [
|
|
5615
|
-
(policies || []).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Alert, { severity: "info", children: t("modules.form.publicPolicies.noPolicies") }) : policies.map((policy, index) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5616
|
-
PolicyItem_default,
|
|
5617
|
-
{
|
|
5618
|
-
ref: (el) => {
|
|
5619
|
-
policyRefs.current[index] = el;
|
|
5620
|
-
},
|
|
5621
|
-
policy,
|
|
5622
|
-
onChange: (nextPolicy) => {
|
|
5623
|
-
const next = [...policies];
|
|
5624
|
-
next[index] = nextPolicy;
|
|
5625
|
-
onChange(next);
|
|
5626
|
-
},
|
|
5627
|
-
onRemove: () => removePolicy(index),
|
|
5628
|
-
availableFields,
|
|
5629
|
-
isSubmitting,
|
|
5630
|
-
usedActions,
|
|
5631
|
-
error: typeof errors === "object" && errors && policy.id in errors ? errors[policy.id] : void 0
|
|
5632
|
-
},
|
|
5633
|
-
policy.id
|
|
5634
|
-
)),
|
|
5635
|
-
canAddPolicy && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material11.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5636
|
-
import_material11.Button,
|
|
5637
|
-
{
|
|
5638
|
-
type: "button",
|
|
5639
|
-
variant: "outlined",
|
|
5640
|
-
startIcon: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_icons_material4.Add, {}),
|
|
5641
|
-
onClick: addPolicy,
|
|
5642
|
-
disabled: isSubmitting,
|
|
5643
|
-
sx: {
|
|
5644
|
-
borderColor: "#d0d7de",
|
|
5645
|
-
color: "#656d76",
|
|
5646
|
-
"&:hover": {
|
|
5647
|
-
borderColor: "#8c959f",
|
|
5648
|
-
backgroundColor: "transparent"
|
|
5649
|
-
}
|
|
5650
|
-
},
|
|
5651
|
-
children: t("modules.form.publicPolicies.addPolicy")
|
|
5652
|
-
}
|
|
5653
|
-
) })
|
|
5654
|
-
] })
|
|
5655
|
-
] })
|
|
5656
|
-
] });
|
|
5657
5658
|
};
|
|
5658
|
-
var Policies_default = Policies;
|
|
5659
5659
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5660
5660
|
0 && (module.exports = {
|
|
5661
5661
|
CrudifyDataProvider,
|