@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/dist/index.js CHANGED
@@ -3324,173 +3324,752 @@ var UserProfileDisplay = ({
3324
3324
  };
3325
3325
  var UserProfileDisplay_default = UserProfileDisplay;
3326
3326
 
3327
- // src/index.ts
3328
- init_CrudifyDataProvider();
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/hooks/useCrudifyUser.ts
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 import_crudify_browser5 = __toESM(require("@nocios/crudify-browser"));
3333
- init_CrudifyDataProvider();
3334
- var useCrudifyUser = (options = {}) => {
3335
- const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
3336
- const { isAuthenticated, isInitialized, user: jwtUser, token } = useCrudifyDataContext();
3337
- const [userData, setUserData] = (0, import_react13.useState)(null);
3338
- const [loading, setLoading] = (0, import_react13.useState)(false);
3339
- const [error, setError] = (0, import_react13.useState)(null);
3340
- const abortControllerRef = (0, import_react13.useRef)(null);
3341
- const mountedRef = (0, import_react13.useRef)(true);
3342
- const requestIdRef = (0, import_react13.useRef)(0);
3343
- const retryCountRef = (0, import_react13.useRef)(0);
3344
- const getUserEmailFromJWT = (0, import_react13.useCallback)(() => {
3345
- if (!jwtUser) return null;
3346
- return jwtUser.email || jwtUser["cognito:username"] || null;
3347
- }, [jwtUser]);
3348
- const clearProfile = (0, import_react13.useCallback)(() => {
3349
- setUserData(null);
3350
- setError(null);
3351
- setLoading(false);
3352
- retryCountRef.current = 0;
3353
- }, []);
3354
- const refreshProfile = (0, import_react13.useCallback)(async () => {
3355
- const userEmail = getUserEmailFromJWT();
3356
- console.log("\u{1F464} useCrudifyUser - Refreshing profile for:", userEmail);
3357
- if (!userEmail) {
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
- const abortController = new AbortController();
3375
- abortControllerRef.current = abortController;
3376
- const currentRequestId = ++requestIdRef.current;
3377
- try {
3378
- if (mountedRef.current) {
3379
- setLoading(true);
3380
- setError(null);
3381
- }
3382
- console.log("\u{1F464} useCrudifyUser - Fetching profile data from database");
3383
- const response = await import_crudify_browser5.default.readItems("users", {
3384
- filter: { email: userEmail },
3385
- pagination: { limit: 1 }
3386
- });
3387
- console.log("\u{1F464} useCrudifyUser - Database response:", response);
3388
- console.log("\u{1F464} useCrudifyUser - response.data:", response.data);
3389
- console.log("\u{1F464} useCrudifyUser - response.data type:", typeof response.data);
3390
- if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
3391
- let userData2 = null;
3392
- if (response.success) {
3393
- console.log("\u{1F464} useCrudifyUser - Processing successful response:", {
3394
- dataType: typeof response.data,
3395
- isArray: Array.isArray(response.data),
3396
- hasResponse: !!response.data?.response,
3397
- hasResponseData: !!response.data?.response?.data,
3398
- responseDataType: typeof response.data?.response?.data
3399
- });
3400
- if (Array.isArray(response.data) && response.data.length > 0) {
3401
- console.log("\u{1F464} useCrudifyUser - Found direct array format");
3402
- userData2 = response.data[0];
3403
- } else if (response.data?.response?.data) {
3404
- console.log("\u{1F464} useCrudifyUser - Found nested response.data format");
3405
- try {
3406
- const rawData = response.data.response.data;
3407
- console.log("\u{1F464} useCrudifyUser - Raw nested data:", rawData);
3408
- console.log("\u{1F464} useCrudifyUser - Raw data type:", typeof rawData);
3409
- const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
3410
- console.log("\u{1F464} useCrudifyUser - Parsed nested data:", parsedData);
3411
- if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
3412
- userData2 = parsedData.items[0];
3413
- console.log("\u{1F464} useCrudifyUser - Extracted user from nested items:", userData2);
3414
- } else {
3415
- console.log("\u{1F464} useCrudifyUser - No items found in parsed data or items array is empty");
3416
- }
3417
- } catch (parseError) {
3418
- console.error("\u{1F464} useCrudifyUser - Error parsing nested response data:", parseError);
3419
- }
3420
- } else if (response.data && typeof response.data === "object") {
3421
- console.log("\u{1F464} useCrudifyUser - Found object format, checking for items");
3422
- if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
3423
- console.log("\u{1F464} useCrudifyUser - Found items in object format");
3424
- userData2 = response.data.items[0];
3425
- } else {
3426
- console.log("\u{1F464} useCrudifyUser - No items found in object format");
3427
- }
3428
- } else if (response.data?.data?.response?.data) {
3429
- console.log("\u{1F464} useCrudifyUser - Found double-nested data.data.response.data format");
3430
- try {
3431
- const rawData = response.data.data.response.data;
3432
- console.log("\u{1F464} useCrudifyUser - Raw double-nested data:", rawData);
3433
- const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
3434
- console.log("\u{1F464} useCrudifyUser - Parsed double-nested data:", parsedData);
3435
- if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
3436
- userData2 = parsedData.items[0];
3437
- console.log("\u{1F464} useCrudifyUser - Extracted user from double-nested items:", userData2);
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
- const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
3464
- if (shouldRetry) {
3465
- retryCountRef.current++;
3466
- console.log(`\u{1F464} useCrudifyUser - Retrying profile fetch (${retryCountRef.current}/${maxRetries})`);
3467
- setTimeout(() => {
3468
- if (mountedRef.current) {
3469
- refreshProfile();
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
- }, 1e3 * retryCountRef.current);
3472
- } else {
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
- } finally {
3478
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
3479
- setLoading(false);
3480
- }
3481
- if (abortControllerRef.current === abortController) {
3482
- abortControllerRef.current = null;
3483
- }
3484
- }
3485
- }, [isInitialized, getUserEmailFromJWT, retryOnError, maxRetries]);
3486
- (0, import_react13.useEffect)(() => {
3487
- if (autoFetch && isAuthenticated && isInitialized) {
3488
- refreshProfile();
3489
- } else if (!isAuthenticated) {
3490
- clearProfile();
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, import_react13.useEffect)(() => {
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 import_react14 = require("react");
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, import_react14.useCallback)(() => {
4105
+ const isReady = (0, import_react17.useCallback)(() => {
3527
4106
  return isInitialized && !initializationError && !isInitializing;
3528
4107
  }, [isInitialized, initializationError, isInitializing]);
3529
- const waitForReady = (0, import_react14.useCallback)(async () => {
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, import_react14.useCallback)((operationName) => {
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, import_react14.useCallback)(async (moduleKey, filter, options) => {
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, import_react14.useCallback)(async (moduleKey, filter, options) => {
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, import_react14.useCallback)(async (moduleKey, data, options) => {
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, import_react14.useCallback)(async (moduleKey, data, options) => {
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, import_react14.useCallback)(async (moduleKey, id, options) => {
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, import_react14.useCallback)(async (operations, options) => {
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, import_react14.useCallback)(async (email, password) => {
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 import_react15 = require("react");
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, import_react15.useCallback)(async () => {
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, import_react15.useCallback)(async (operationName) => {
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, import_react15.useCallback)(async () => {
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, import_react15.useCallback)(async (options) => {
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
- return import_crypto_js2.default.AES.encrypt(data, _TokenStorage.ENCRYPTION_KEY).toString();
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("Crudify: Encryption failed", error);
3939
- return data;
4327
+ console.error("\u{1F4E1} useCrudifyInstance - getStructure: Error", error);
4328
+ throw error;
3940
4329
  }
3941
- }
3942
- /**
3943
- * Desencriptar datos
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
- const bytes = import_crypto_js2.default.AES.decrypt(encryptedData, _TokenStorage.ENCRYPTION_KEY);
3948
- const decrypted = bytes.toString(import_crypto_js2.default.enc.Utf8);
3949
- return decrypted || encryptedData;
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("Crudify: Decryption failed", error);
3952
- return encryptedData;
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 tokenData = {
3963
- accessToken: tokens.accessToken,
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("Crudify: Failed to save tokens", error);
4355
+ console.error("\u{1F4CA} useCrudifyInstance - readItems error:", error);
4356
+ throw error;
3974
4357
  }
3975
- }
3976
- /**
3977
- * Obtener tokens guardados
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 encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
3984
- if (!encrypted) return null;
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("Crudify: Failed to retrieve tokens", error);
4005
- _TokenStorage.clearTokens();
4006
- return null;
4365
+ console.error("\u{1F4CA} useCrudifyInstance - readItem error:", error);
4366
+ throw error;
4007
4367
  }
4008
- }
4009
- /**
4010
- * Limpiar tokens almacenados
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
- storage.removeItem(_TokenStorage.TOKEN_KEY);
4017
- console.debug("Crudify: Tokens cleared from storage");
4372
+ const response = await import_crudify_browser7.default.createItem(moduleKey, data, options);
4373
+ return response;
4018
4374
  } catch (error) {
4019
- console.error("Crudify: Failed to clear tokens", 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
- if (this.config.autoRestore) {
4094
- await this.restoreSession();
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
- this.initialized = true;
4097
- this.log("SessionManager initialized successfully");
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
- this.log("Attempting login...");
4105
- const response = await import_crudify_browser8.default.login(email, password);
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
- this.log("Login error:", error);
4128
- return {
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
- * Logout con limpieza de tokens
4136
- */
4137
- async logout() {
4398
+ }, [ensureReady]);
4399
+ const transaction = (0, import_react18.useCallback)(async (operations, options) => {
4400
+ await ensureReady("transaction");
4138
4401
  try {
4139
- this.log("Logging out...");
4140
- await import_crudify_browser8.default.logout();
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
- this.log("Logout error:", error);
4146
- TokenStorage.clearTokens();
4405
+ console.error("\u{1F4CA} useCrudifyInstance - transaction error:", error);
4406
+ throw error;
4147
4407
  }
4148
- }
4149
- /**
4150
- * Restaurar sesión desde storage
4151
- */
4152
- async restoreSession() {
4408
+ }, [ensureReady]);
4409
+ const login = (0, import_react18.useCallback)(async (email, password) => {
4410
+ await ensureReady("login");
4153
4411
  try {
4154
- this.log("Attempting to restore session...");
4155
- const savedTokens = TokenStorage.getTokens();
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
- this.log("Session restore error:", error);
4171
- TokenStorage.clearTokens();
4172
- return false;
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
- * Verificar si el usuario está autenticado
4177
- */
4178
- isAuthenticated() {
4179
- return import_crudify_browser8.default.isLogin() || TokenStorage.hasValidTokens();
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
- * Obtener información de tokens actuales
4480
+ * Configurar tipo de almacenamiento
4183
4481
  */
4184
- getTokenInfo() {
4185
- const crudifyTokens = import_crudify_browser8.default.getTokenData();
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
- * Refrescar tokens manualmente
4486
+ * Verificar si el storage está disponible
4196
4487
  */
4197
- async refreshTokens() {
4488
+ static isStorageAvailable(type) {
4198
4489
  try {
4199
- this.log("Manually refreshing tokens...");
4200
- const response = await import_crudify_browser8.default.refreshAccessToken();
4201
- if (!response.success) {
4202
- this.log("Token refresh failed:", response.errors);
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 (error) {
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
- * Configurar interceptor de respuesta para manejo automático de errores
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
- clearSession() {
4249
- TokenStorage.clearTokens();
4250
- import_crudify_browser8.default.logout();
4251
- this.log("Session cleared completely");
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 "Authentication failed";
4508
+ return window[_TokenStorage.storageType];
4267
4509
  }
4268
- };
4269
-
4270
- // src/hooks/useSession.ts
4271
- var import_react16 = require("react");
4272
- function useSession(options = {}) {
4273
- const [state, setState] = (0, import_react16.useState)({
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
- setState((prev) => ({
4340
- ...prev,
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
- }, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
4347
- const login = (0, import_react16.useCallback)(async (email, password) => {
4348
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
4520
+ }
4521
+ /**
4522
+ * Desencriptar datos
4523
+ */
4524
+ static decrypt(encryptedData) {
4349
4525
  try {
4350
- const result = await sessionManager.login(email, password);
4351
- if (result.success && result.tokens) {
4352
- setState((prev) => ({
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
- const errorMsg = error instanceof Error ? error.message : "Login failed";
4371
- setState((prev) => ({
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
- }, [sessionManager]);
4384
- const logout = (0, import_react16.useCallback)(async () => {
4385
- setState((prev) => ({ ...prev, isLoading: true }));
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
- await sessionManager.logout();
4388
- setState((prev) => ({
4389
- ...prev,
4390
- isAuthenticated: false,
4391
- tokens: null,
4392
- isLoading: false,
4393
- error: null
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
- setState((prev) => ({
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
- }, [sessionManager]);
4405
- const refreshTokens = (0, import_react16.useCallback)(async () => {
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 success = await sessionManager.refreshTokens();
4408
- if (success) {
4409
- const tokenInfo = sessionManager.getTokenInfo();
4410
- setState((prev) => ({
4411
- ...prev,
4412
- tokens: tokenInfo.crudifyTokens.accessToken ? {
4413
- accessToken: tokenInfo.crudifyTokens.accessToken,
4414
- refreshToken: tokenInfo.crudifyTokens.refreshToken,
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
- return success;
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
- setState((prev) => ({
4431
- ...prev,
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
- const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
4478
- if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
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("Error decoding JWT token for sessionData:", 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
- return context;
4508
- }
4509
- function ProtectedRoute({
4510
- children,
4511
- fallback = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: "Please log in to access this content" }),
4512
- redirectTo
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
- if (!isAuthenticated) {
4519
- if (redirectTo) {
4520
- redirectTo();
4521
- return null;
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
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: fallback });
4524
- }
4525
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children });
4526
- }
4527
- function SessionDebugInfo() {
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
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
4533
- padding: "10px",
4534
- margin: "10px",
4535
- border: "1px solid #ccc",
4536
- borderRadius: "4px",
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/components/LoginComponent.tsx
4591
- var import_react18 = require("react");
4592
- var import_material8 = require("@mui/material");
4593
- var import_jsx_runtime13 = require("react/jsx-runtime");
4594
- function LoginComponent() {
4595
- const [email, setEmail] = (0, import_react18.useState)("");
4596
- const [password, setPassword] = (0, import_react18.useState)("");
4597
- const [showForm, setShowForm] = (0, import_react18.useState)(false);
4598
- const {
4599
- isAuthenticated,
4600
- isLoading,
4601
- error,
4602
- login,
4603
- logout,
4604
- refreshTokens,
4605
- clearError,
4606
- isExpiringSoon,
4607
- expiresIn
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
- const result = await login(email, password);
4615
- if (result.success) {
4616
- setEmail("");
4617
- setPassword("");
4618
- setShowForm(false);
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
- const handleLogout = async () => {
4622
- await logout();
4623
- };
4624
- const handleRefreshTokens = async () => {
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
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { maxWidth: 400, mx: "auto", p: 3 }, children: [
4666
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "h4", gutterBottom: true, align: "center", children: "Login with Refresh Tokens" }),
4667
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "info", sx: { mb: 3 }, children: "This demo shows the new Refresh Token Pattern with automatic session management" }),
4668
- !showForm ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4669
- import_material8.Button,
4670
- {
4671
- fullWidth: true,
4672
- variant: "contained",
4673
- size: "large",
4674
- onClick: () => setShowForm(true),
4675
- sx: { mt: 2 },
4676
- children: "Show Login Form"
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
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("form", { onSubmit: handleLogin, children: [
4679
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4680
- import_material8.TextField,
4681
- {
4682
- fullWidth: true,
4683
- label: "Email",
4684
- type: "email",
4685
- value: email,
4686
- onChange: (e) => setEmail(e.target.value),
4687
- margin: "normal",
4688
- required: true,
4689
- autoComplete: "email"
4690
- }
4691
- ),
4692
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4693
- import_material8.TextField,
4694
- {
4695
- fullWidth: true,
4696
- label: "Password",
4697
- type: "password",
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
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { children: [
4734
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "caption", color: "success.main", children: "\u2713 Authenticated" }),
4735
- isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Typography, { variant: "caption", color: "warning.main", display: "block", children: [
4736
- "\u26A0 Token expires in ",
4737
- Math.round(expiresIn / 1e3 / 60),
4738
- " min"
4739
- ] })
4740
- ] });
4741
- }
4742
-
4743
- // src/hooks/useUserData.ts
4744
- var import_react19 = require("react");
4745
- var import_crudify_browser9 = __toESM(require("@nocios/crudify-browser"));
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
- if (!isInitialized) {
4777
- if (mountedRef.current) {
4778
- setError("Session not initialized");
4779
- setLoading(false);
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
- return;
4782
- }
4783
- if (abortControllerRef.current) {
4784
- abortControllerRef.current.abort();
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
- const abortController = new AbortController();
4787
- abortControllerRef.current = abortController;
4788
- const currentRequestId = ++requestIdRef.current;
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
- if (mountedRef.current) {
4791
- setLoading(true);
4792
- setError(null);
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
- console.log("\u{1F464} useUserData - Fetching profile data from database");
4795
- const response = await import_crudify_browser9.default.readItems("users", {
4796
- filter: { email: userEmail },
4797
- pagination: { limit: 1 }
4798
- });
4799
- console.log("\u{1F464} useUserData - Database response:", response);
4800
- console.log("\u{1F464} useUserData - response.data:", response.data);
4801
- console.log("\u{1F464} useUserData - response.data type:", typeof response.data);
4802
- if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
4803
- let userData2 = null;
4804
- if (response.success) {
4805
- console.log("\u{1F464} useUserData - Processing successful response:", {
4806
- dataType: typeof response.data,
4807
- isArray: Array.isArray(response.data),
4808
- hasResponse: !!response.data?.response,
4809
- hasResponseData: !!response.data?.response?.data,
4810
- responseDataType: typeof response.data?.response?.data
4811
- });
4812
- if (Array.isArray(response.data) && response.data.length > 0) {
4813
- console.log("\u{1F464} useUserData - Found direct array format");
4814
- userData2 = response.data[0];
4815
- } else if (response.data?.response?.data) {
4816
- console.log("\u{1F464} useUserData - Found nested response.data format");
4817
- try {
4818
- const rawData = response.data.response.data;
4819
- console.log("\u{1F464} useUserData - Raw nested data:", rawData);
4820
- console.log("\u{1F464} useUserData - Raw data type:", typeof rawData);
4821
- const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
4822
- console.log("\u{1F464} useUserData - Parsed nested data:", parsedData);
4823
- if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
4824
- userData2 = parsedData.items[0];
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
- } catch (err) {
4869
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
4870
- const error2 = err;
4871
- console.error("\u{1F464} useUserData - Error fetching profile:", error2);
4872
- if (error2.name === "AbortError") {
4873
- return;
4874
- }
4875
- const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
4876
- if (shouldRetry) {
4877
- retryCountRef.current++;
4878
- console.log(`\u{1F464} useUserData - Retrying profile fetch (${retryCountRef.current}/${maxRetries})`);
4879
- setTimeout(() => {
4880
- if (mountedRef.current) {
4881
- refreshProfile();
4882
- }
4883
- }, 1e3 * retryCountRef.current);
4884
- } else {
4885
- setError("Failed to load user profile from database");
4886
- setUserData(null);
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
- } finally {
4890
- if (currentRequestId === requestIdRef.current && mountedRef.current) {
4891
- setLoading(false);
4892
- }
4893
- if (abortControllerRef.current === abortController) {
4894
- abortControllerRef.current = null;
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
- }, [isInitialized, getUserEmail, retryOnError, maxRetries]);
4898
- (0, import_react19.useEffect)(() => {
4899
- if (autoFetch && isAuthenticated && isInitialized) {
4900
- refreshProfile();
4901
- } else if (!isAuthenticated) {
4902
- clearProfile();
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
- }, [autoFetch, isAuthenticated, isInitialized, refreshProfile, clearProfile]);
4905
- (0, import_react19.useEffect)(() => {
4906
- mountedRef.current = true;
4907
- return () => {
4908
- mountedRef.current = false;
4909
- if (abortControllerRef.current) {
4910
- abortControllerRef.current.abort();
4911
- abortControllerRef.current = null;
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 user = {
4916
- session: sessionData,
4917
- // Usar sessionData del nuevo sistema
4918
- data: userData
4919
- // Mantener userData del database igual que legacy
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
- user,
4923
- loading,
4924
- error,
4925
- refreshProfile,
4926
- clearProfile
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/hooks/useAuth.ts
4931
- var import_react20 = require("react");
4932
- var useAuth = () => {
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 isReady = (0, import_react21.useCallback)(() => {
4995
- return isInitialized && !isLoading && !error;
4996
- }, [isInitialized, isLoading, error]);
4997
- const waitForReady = (0, import_react21.useCallback)(async () => {
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
- }, [sessionLogin]);
5061
- return {
5062
- // CRUD operations
5063
- readItems,
5064
- readItem,
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 getFieldState = (fieldName) => {
5143
- if (value?.allow?.includes(fieldName)) return "allow";
5144
- if (value?.owner_allow?.includes(fieldName)) return "owner_allow";
5145
- return "deny";
5200
+ const handleLogout = async () => {
5201
+ await logout();
5146
5202
  };
5147
- const setFieldState = (fieldName, state) => {
5148
- isUpdatingRef.current = true;
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 (availableFields.length === 0) {
5165
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material9.Box, { children: [
5166
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
5167
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { fontStyle: "italic" }, children: t("modules.form.publicPolicies.fields.conditions.noFieldsAvailable") }),
5168
- error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.FormHelperText, { error: true, sx: { mt: 1 }, children: error })
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, import_jsx_runtime14.jsxs)(import_material9.Box, { children: [
5172
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material9.Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: t("modules.form.publicPolicies.fields.conditions.label") }),
5173
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_material9.Stack, { direction: "row", spacing: 1, sx: { mb: 3 }, children: [
5174
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5175
- import_material9.Button,
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
- variant: mode === "all" ? "contained" : "outlined",
5178
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material2.SelectAll, {}),
5179
- onClick: setAllAllow,
5180
- disabled,
5181
- size: "small",
5182
- sx: {
5183
- minWidth: 120,
5184
- ...mode === "all" && {
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, import_jsx_runtime14.jsx)(
5193
- import_material9.Button,
5271
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5272
+ import_material11.TextField,
5194
5273
  {
5195
- variant: mode === "none" ? "contained" : "outlined",
5196
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_icons_material2.ClearAll, {}),
5197
- onClick: setAllDeny,
5198
- disabled,
5199
- size: "small",
5200
- sx: {
5201
- minWidth: 120,
5202
- ...mode === "none" && {
5203
- backgroundColor: "#cf222e",
5204
- "&:hover": { backgroundColor: "#bc1f2c" }
5205
- }
5206
- },
5207
- children: t("modules.form.publicPolicies.fields.conditions.noFields")
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, import_jsx_runtime14.jsxs)(import_material9.Box, { sx: { p: 2, border: "1px solid #d1d9e0", borderRadius: 1, backgroundColor: "#f6f8fa" }, children: [
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
- var FieldSelector_default = FieldSelector;
5310
-
5311
- // src/components/PublicPolicies/constants.ts
5312
- var POLICY_ACTIONS = ["create", "read", "update", "delete"];
5313
- var PREFERRED_POLICY_ORDER = [
5314
- "create",
5315
- "read",
5316
- "update",
5317
- "delete"
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/components/PublicPolicies/PolicyItem/PolicyItem.tsx
5321
- var import_jsx_runtime15 = require("react/jsx-runtime");
5322
- var PolicyItem = (0, import_react23.forwardRef)(({
5323
- policy,
5324
- onChange,
5325
- onRemove,
5326
- availableFields,
5327
- isSubmitting = false,
5328
- usedActions,
5329
- error
5330
- }, ref) => {
5331
- const { t } = (0, import_react_i18next2.useTranslation)();
5332
- const takenActions = new Set(Array.from(usedActions || []));
5333
- takenActions.delete(policy.action);
5334
- const actionOptions = POLICY_ACTIONS.map((a) => ({
5335
- value: a,
5336
- label: t(`modules.form.publicPolicies.fields.action.options.${a}`)
5337
- }));
5338
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5339
- import_material10.Paper,
5340
- {
5341
- ref,
5342
- sx: {
5343
- p: 3,
5344
- border: "1px solid #d1d9e0",
5345
- borderRadius: 2,
5346
- position: "relative",
5347
- backgroundColor: "#ffffff"
5348
- },
5349
- children: [
5350
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Box, { sx: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", mb: 3 }, children: [
5351
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5352
- import_material10.Typography,
5353
- {
5354
- variant: "subtitle1",
5355
- sx: {
5356
- fontWeight: 600,
5357
- color: "#111418",
5358
- fontSize: "1rem"
5359
- },
5360
- children: t("modules.form.publicPolicies.policyTitle")
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
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5364
- import_material10.IconButton,
5365
- {
5366
- onClick: onRemove,
5367
- size: "small",
5368
- disabled: isSubmitting,
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
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Stack, { spacing: 3, children: [
5382
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.Stack, { direction: { xs: "column", md: "row" }, spacing: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.Box, { sx: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.FormControl, { fullWidth: true, children: [
5383
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.InputLabel, { children: t("modules.form.publicPolicies.fields.action.label") }),
5384
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5385
- import_material10.Select,
5386
- {
5387
- value: policy.action,
5388
- label: t("modules.form.publicPolicies.fields.action.label"),
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
- error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.FormHelperText, { error: true, children: error })
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
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.Paper, { variant: "outlined", sx: { p: 2, backgroundColor: "#f9fafb" }, children: policy.action === "delete" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
5490
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Box, { component: "span", sx: {
5491
- color: policy.permission === "*" ? "#16a34a" : policy.permission === "owner" ? "#0ea5e9" : "#dc2626"
5492
- }, children: [
5493
- t("modules.form.publicPolicies.fields.conditions.states.allow"),
5494
- ":"
5495
- ] }),
5496
- " ",
5497
- policy.permission || "-"
5498
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Stack, { spacing: 0.5, divider: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_material10.Divider, { sx: { borderColor: "#e5e7eb" } }), children: [
5499
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
5500
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Box, { component: "span", sx: { color: "#16a34a" }, children: [
5501
- t("modules.form.publicPolicies.fields.conditions.states.allow"),
5502
- ":"
5503
- ] }),
5504
- " ",
5505
- (policy?.fields?.allow || []).join(", ") || "-"
5506
- ] }),
5507
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
5508
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Box, { component: "span", sx: { color: "#0ea5e9" }, children: [
5509
- t("modules.form.publicPolicies.fields.conditions.states.ownerAllow"),
5510
- ":"
5511
- ] }),
5512
- " ",
5513
- (policy?.fields?.owner_allow || []).join(", ") || "-"
5514
- ] }),
5515
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Typography, { variant: "body2", sx: { fontFamily: "monospace", color: "text.secondary" }, children: [
5516
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_material10.Box, { component: "span", sx: { color: "#dc2626" }, children: [
5517
- t("modules.form.publicPolicies.fields.conditions.states.deny"),
5518
- ":"
5519
- ] }),
5520
- " ",
5521
- (policy?.fields?.deny || []).join(", ") || "-"
5522
- ] })
5523
- ] }) })
5524
- ] })
5525
- ]
5526
- }
5527
- );
5528
- });
5529
- var PolicyItem_default = PolicyItem;
5530
-
5531
- // src/components/PublicPolicies/Policies.tsx
5532
- var import_jsx_runtime16 = require("react/jsx-runtime");
5533
- var generateId = () => {
5534
- const c = globalThis?.crypto;
5535
- if (c && typeof c.randomUUID === "function") return c.randomUUID();
5536
- return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
5537
- };
5538
- var Policies = ({
5539
- policies,
5540
- onChange,
5541
- availableFields,
5542
- errors,
5543
- isSubmitting = false
5544
- }) => {
5545
- const { t } = (0, import_react_i18next3.useTranslation)();
5546
- const policyRefs = (0, import_react24.useRef)({});
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
- if (defaultAction === "delete") {
5557
- newPolicy.permission = "deny";
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
- newPolicy.fields = {
5560
- allow: [],
5561
- owner_allow: [],
5562
- deny: availableFields
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
- const next = [...policies || [], newPolicy];
5566
- onChange(next);
5567
- setTimeout(() => {
5568
- const newIndex = next.length - 1;
5569
- const el = policyRefs.current[newIndex];
5570
- if (el) {
5571
- el.scrollIntoView({ behavior: "smooth", block: "center" });
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
- }, 100);
5574
- };
5575
- const removePolicy = (index) => {
5576
- const next = [...policies];
5577
- next.splice(index, 1);
5578
- onChange(next);
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,