@pol-studios/db 1.0.38 → 1.0.39
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/auth/context.d.ts +1 -7
- package/dist/auth/context.js +2 -2
- package/dist/auth/hooks.js +3 -3
- package/dist/auth/index.js +3 -3
- package/dist/{chunk-QMHHKYZO.js → chunk-3UW5K5PL.js} +3 -3
- package/dist/{chunk-UBHORKBS.js → chunk-5SJ5O2NQ.js} +75 -2
- package/dist/chunk-5SJ5O2NQ.js.map +1 -0
- package/dist/{chunk-TO5QB4UM.js → chunk-AQ5JJKIN.js} +4 -4
- package/dist/{chunk-NP34C3O3.js → chunk-D2F3APBF.js} +30 -103
- package/dist/chunk-D2F3APBF.js.map +1 -0
- package/dist/{chunk-ILGWCJ6S.js → chunk-D7UZEYKO.js} +2 -2
- package/dist/{chunk-6OSNGHRE.js → chunk-MZLEDWJF.js} +414 -420
- package/dist/chunk-MZLEDWJF.js.map +1 -0
- package/dist/{chunk-INIX2V6L.js → chunk-Z6ZHXO2R.js} +4 -4
- package/dist/hooks/index.js +4 -4
- package/dist/index.js +9 -9
- package/dist/index.native.js +9 -9
- package/dist/index.web.js +8 -8
- package/dist/with-auth/index.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-6OSNGHRE.js.map +0 -1
- package/dist/chunk-NP34C3O3.js.map +0 -1
- package/dist/chunk-UBHORKBS.js.map +0 -1
- /package/dist/{chunk-QMHHKYZO.js.map → chunk-3UW5K5PL.js.map} +0 -0
- /package/dist/{chunk-TO5QB4UM.js.map → chunk-AQ5JJKIN.js.map} +0 -0
- /package/dist/{chunk-ILGWCJ6S.js.map → chunk-D7UZEYKO.js.map} +0 -0
- /package/dist/{chunk-INIX2V6L.js.map → chunk-Z6ZHXO2R.js.map} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
useDbQuery
|
|
3
|
-
|
|
2
|
+
useDbQuery,
|
|
3
|
+
useDbQueryById
|
|
4
|
+
} from "./chunk-5SJ5O2NQ.js";
|
|
4
5
|
import {
|
|
5
6
|
buildNormalizedQuery,
|
|
6
7
|
encode,
|
|
@@ -71,9 +72,292 @@ function useDbQuery2(query, config) {
|
|
|
71
72
|
import { createContext } from "react";
|
|
72
73
|
var setupAuthContext = createContext({});
|
|
73
74
|
|
|
74
|
-
// src/auth/context/
|
|
75
|
-
import {
|
|
75
|
+
// src/auth/context/AuthProvider.tsx
|
|
76
|
+
import { useCallback, useEffect, useMemo as useMemo2, useRef as useRef2, useState } from "react";
|
|
77
|
+
import { isUsable, newUuid } from "@pol-studios/utils";
|
|
76
78
|
import { jsx } from "react/jsx-runtime";
|
|
79
|
+
var SESSION_FETCH_TIMEOUT_MS = 3e3;
|
|
80
|
+
function getPermissionLevel(action) {
|
|
81
|
+
switch (action.toLowerCase()) {
|
|
82
|
+
case "view":
|
|
83
|
+
case "read":
|
|
84
|
+
return 1;
|
|
85
|
+
case "edit":
|
|
86
|
+
case "write":
|
|
87
|
+
return 2;
|
|
88
|
+
case "admin":
|
|
89
|
+
case "delete":
|
|
90
|
+
case "share":
|
|
91
|
+
return 3;
|
|
92
|
+
default:
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function isNotExpired(expiresAt) {
|
|
97
|
+
return !expiresAt || new Date(expiresAt) > /* @__PURE__ */ new Date();
|
|
98
|
+
}
|
|
99
|
+
function matchesAccessPattern(pattern, requestedKey) {
|
|
100
|
+
if (pattern === requestedKey) return true;
|
|
101
|
+
if (pattern === "*:*:*") return true;
|
|
102
|
+
const patternParts = pattern.split(":");
|
|
103
|
+
const keyParts = requestedKey.split(":");
|
|
104
|
+
if (patternParts.length !== keyParts.length) return false;
|
|
105
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
106
|
+
if (patternParts[i] === "*") continue;
|
|
107
|
+
if (patternParts[i] !== keyParts[i]) return false;
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
function AuthProvider({
|
|
112
|
+
children
|
|
113
|
+
}) {
|
|
114
|
+
const supabase = useSupabase();
|
|
115
|
+
const [currentUser, setCurrentUser] = useState(void 0);
|
|
116
|
+
const [userNeedsChange, setUserNeedsChange] = useState(true);
|
|
117
|
+
const [onSignOutCallbacks, setOnSignOutCallbacks] = useState(/* @__PURE__ */ new Map());
|
|
118
|
+
async function registerAsync(register) {
|
|
119
|
+
const response = await supabase.auth.signUp(register);
|
|
120
|
+
if (response.data.user) {
|
|
121
|
+
setCurrentUser((prev) => prev?.id === response.data.user?.id ? prev : response.data.user);
|
|
122
|
+
}
|
|
123
|
+
return response;
|
|
124
|
+
}
|
|
125
|
+
async function signInAsync(username, password) {
|
|
126
|
+
const response_0 = await supabase.auth.signInWithPassword({
|
|
127
|
+
email: username,
|
|
128
|
+
password
|
|
129
|
+
});
|
|
130
|
+
if (response_0.data.user) {
|
|
131
|
+
setCurrentUser((prev_0) => prev_0?.id === response_0.data.user?.id ? prev_0 : response_0.data.user);
|
|
132
|
+
}
|
|
133
|
+
return response_0;
|
|
134
|
+
}
|
|
135
|
+
const signOutAsync = useCallback(async () => {
|
|
136
|
+
const response_1 = await supabase.auth.signOut();
|
|
137
|
+
if (!response_1.error) {
|
|
138
|
+
Array.from(onSignOutCallbacks.values()).forEach((cb) => cb());
|
|
139
|
+
}
|
|
140
|
+
return response_1;
|
|
141
|
+
}, [supabase.auth, onSignOutCallbacks]);
|
|
142
|
+
function onSignOut(action) {
|
|
143
|
+
const id = newUuid();
|
|
144
|
+
setOnSignOutCallbacks((x) => new Map(x).set(id, action));
|
|
145
|
+
return id;
|
|
146
|
+
}
|
|
147
|
+
function removeOnSignOut(id_0) {
|
|
148
|
+
setOnSignOutCallbacks((x_0) => {
|
|
149
|
+
const map = new Map(x_0);
|
|
150
|
+
map.delete(id_0);
|
|
151
|
+
return map;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
async function refreshAsync() {
|
|
155
|
+
}
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
const {
|
|
158
|
+
data: {
|
|
159
|
+
subscription
|
|
160
|
+
}
|
|
161
|
+
} = supabase.auth.onAuthStateChange((event) => {
|
|
162
|
+
if (event === "SIGNED_IN" || event === "SIGNED_OUT") {
|
|
163
|
+
setUserNeedsChange(true);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return () => subscription.unsubscribe();
|
|
167
|
+
}, [supabase.auth]);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
if (!userNeedsChange) return;
|
|
170
|
+
let cancelled = false;
|
|
171
|
+
async function fetchSessionWithTimeout() {
|
|
172
|
+
try {
|
|
173
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
reject(new Error(`Session fetch timed out after ${SESSION_FETCH_TIMEOUT_MS}ms`));
|
|
176
|
+
}, SESSION_FETCH_TIMEOUT_MS);
|
|
177
|
+
});
|
|
178
|
+
const result = await Promise.race([supabase.auth.getSession(), timeoutPromise]);
|
|
179
|
+
if (cancelled) return;
|
|
180
|
+
const newUser = result?.data?.session?.user ?? null;
|
|
181
|
+
setCurrentUser((prev_2) => {
|
|
182
|
+
if (newUser === null) return null;
|
|
183
|
+
if (prev_2?.id === newUser?.id) return prev_2;
|
|
184
|
+
return newUser;
|
|
185
|
+
});
|
|
186
|
+
setUserNeedsChange(false);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (cancelled) return;
|
|
189
|
+
console.error("Failed to get session (timeout or error):", error);
|
|
190
|
+
setCurrentUser((prev_1) => prev_1 === null ? prev_1 : null);
|
|
191
|
+
setUserNeedsChange(false);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
fetchSessionWithTimeout();
|
|
195
|
+
return () => {
|
|
196
|
+
cancelled = true;
|
|
197
|
+
};
|
|
198
|
+
}, [userNeedsChange, supabase.auth]);
|
|
199
|
+
const isUserReady = isUsable(currentUser);
|
|
200
|
+
const {
|
|
201
|
+
data: profile,
|
|
202
|
+
isLoading: profileLoading
|
|
203
|
+
} = useDbQueryById("core.Profile", currentUser?.id ?? "", {
|
|
204
|
+
enabled: isUserReady
|
|
205
|
+
});
|
|
206
|
+
const {
|
|
207
|
+
data: directAccess,
|
|
208
|
+
isLoading: directAccessLoading
|
|
209
|
+
} = useDbQuery("core.UserAccess", {
|
|
210
|
+
where: {
|
|
211
|
+
userId: currentUser?.id
|
|
212
|
+
},
|
|
213
|
+
enabled: isUserReady,
|
|
214
|
+
realtime: true
|
|
215
|
+
});
|
|
216
|
+
const {
|
|
217
|
+
data: userGroups,
|
|
218
|
+
isLoading: userGroupsLoading
|
|
219
|
+
} = useDbQuery("core.UserGroup", {
|
|
220
|
+
where: {
|
|
221
|
+
userId: currentUser?.id
|
|
222
|
+
},
|
|
223
|
+
enabled: isUserReady,
|
|
224
|
+
realtime: true
|
|
225
|
+
});
|
|
226
|
+
const {
|
|
227
|
+
data: groups,
|
|
228
|
+
isLoading: groupsLoading
|
|
229
|
+
} = useDbQuery("core.Group", {
|
|
230
|
+
where: {
|
|
231
|
+
isActive: 1
|
|
232
|
+
},
|
|
233
|
+
enabled: isUserReady,
|
|
234
|
+
realtime: true
|
|
235
|
+
});
|
|
236
|
+
const groupIds = useMemo2(() => userGroups?.map((ug) => ug.groupId) ?? [], [userGroups]);
|
|
237
|
+
const groupsMap = useMemo2(() => new Map(groups?.map((g) => [g.id, g]) ?? []), [groups]);
|
|
238
|
+
const {
|
|
239
|
+
data: groupAccess,
|
|
240
|
+
isLoading: groupAccessLoading
|
|
241
|
+
} = useDbQuery("core.GroupAccessKey", {
|
|
242
|
+
where: groupIds.length > 0 ? {
|
|
243
|
+
groupId: {
|
|
244
|
+
in: groupIds
|
|
245
|
+
}
|
|
246
|
+
} : void 0,
|
|
247
|
+
enabled: groupIds.length > 0,
|
|
248
|
+
realtime: true
|
|
249
|
+
});
|
|
250
|
+
const prevProfileStatusRef = useRef2(void 0);
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
const currentStatus = profile?.status;
|
|
253
|
+
const prevStatus = prevProfileStatusRef.current;
|
|
254
|
+
if (prevStatus === "active" && (currentStatus === "archived" || currentStatus === "suspended")) {
|
|
255
|
+
signOutAsync();
|
|
256
|
+
}
|
|
257
|
+
prevProfileStatusRef.current = currentStatus;
|
|
258
|
+
}, [profile?.status, signOutAsync]);
|
|
259
|
+
const allAccessKeys = useMemo2(() => {
|
|
260
|
+
const keys = [];
|
|
261
|
+
directAccess?.forEach((a) => {
|
|
262
|
+
if (isNotExpired(a.expiresAt)) {
|
|
263
|
+
keys.push({
|
|
264
|
+
accessKey: a.accessKey,
|
|
265
|
+
effect: a.effect ?? "allow",
|
|
266
|
+
source: "direct",
|
|
267
|
+
expiresAt: a.expiresAt
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
const activeGroupIds = new Set(userGroups?.filter((ug_0) => {
|
|
272
|
+
const group = groupsMap.get(ug_0.groupId);
|
|
273
|
+
return group?.isActive === 1 && isNotExpired(ug_0.expiresAt);
|
|
274
|
+
}).map((ug_1) => ug_1.groupId) ?? []);
|
|
275
|
+
groupAccess?.forEach((ga) => {
|
|
276
|
+
if (activeGroupIds.has(ga.groupId) && isNotExpired(ga.expiresAt)) {
|
|
277
|
+
keys.push({
|
|
278
|
+
accessKey: ga.accessKey,
|
|
279
|
+
effect: ga.effect ?? "allow",
|
|
280
|
+
source: "group",
|
|
281
|
+
expiresAt: ga.expiresAt
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
return keys;
|
|
286
|
+
}, [directAccess, userGroups, groupsMap, groupAccess]);
|
|
287
|
+
const combinedAccess = useMemo2(() => {
|
|
288
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
289
|
+
for (const item of allAccessKeys) {
|
|
290
|
+
if (item.accessKey && item.effect === "allow") {
|
|
291
|
+
uniqueKeys.add(item.accessKey);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return Array.from(uniqueKeys);
|
|
295
|
+
}, [allAccessKeys]);
|
|
296
|
+
const effectivePermissions = useMemo2(() => {
|
|
297
|
+
const permissions = [];
|
|
298
|
+
for (const item_0 of allAccessKeys) {
|
|
299
|
+
if (item_0.effect !== "allow") continue;
|
|
300
|
+
const parts = item_0.accessKey.split(":");
|
|
301
|
+
if (parts.length === 3) {
|
|
302
|
+
const [resourceType, resourceId, permission] = parts;
|
|
303
|
+
permissions.push({
|
|
304
|
+
resourceType,
|
|
305
|
+
resourceId,
|
|
306
|
+
permission,
|
|
307
|
+
permissionLevel: getPermissionLevel(permission),
|
|
308
|
+
source: item_0.source,
|
|
309
|
+
inheritedFrom: null,
|
|
310
|
+
expiresAt: item_0.expiresAt ?? null
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return permissions;
|
|
315
|
+
}, [allAccessKeys]);
|
|
316
|
+
const profileStatus = profile?.status;
|
|
317
|
+
const isArchived = profileStatus === "archived";
|
|
318
|
+
const isSuspended = profileStatus === "suspended";
|
|
319
|
+
const hasAccess = useCallback((key) => {
|
|
320
|
+
if (isArchived || isSuspended) return false;
|
|
321
|
+
if (!isUsable(combinedAccess)) return false;
|
|
322
|
+
if (combinedAccess.includes("*:*:*")) return true;
|
|
323
|
+
if (combinedAccess.includes(key)) return true;
|
|
324
|
+
if (!isUsable(key)) return true;
|
|
325
|
+
for (const pattern of combinedAccess) {
|
|
326
|
+
if (matchesAccessPattern(pattern, key)) return true;
|
|
327
|
+
}
|
|
328
|
+
const parts_0 = key.split(":");
|
|
329
|
+
if (parts_0.length === 3) {
|
|
330
|
+
const [type, id_1, action_0] = parts_0;
|
|
331
|
+
const requiredLevel = getPermissionLevel(action_0);
|
|
332
|
+
const hasPermission = effectivePermissions.some((p) => p.resourceType === type && p.resourceId === id_1 && p.permissionLevel >= requiredLevel);
|
|
333
|
+
if (hasPermission) return true;
|
|
334
|
+
}
|
|
335
|
+
return false;
|
|
336
|
+
}, [combinedAccess, effectivePermissions, isArchived, isSuspended]);
|
|
337
|
+
const isAccessLoading = directAccessLoading || userGroupsLoading || groupsLoading || groupAccessLoading;
|
|
338
|
+
const authState = useMemo2(() => ({
|
|
339
|
+
hasAccess,
|
|
340
|
+
user: currentUser,
|
|
341
|
+
profile,
|
|
342
|
+
access: combinedAccess,
|
|
343
|
+
effectivePermissions,
|
|
344
|
+
profileStatus,
|
|
345
|
+
isArchived,
|
|
346
|
+
isSuspended,
|
|
347
|
+
isLoading: currentUser === null ? false : profileLoading || isAccessLoading || currentUser === void 0,
|
|
348
|
+
signInAsync,
|
|
349
|
+
signOutAsync,
|
|
350
|
+
onSignOut,
|
|
351
|
+
removeOnSignOut,
|
|
352
|
+
registerAsync,
|
|
353
|
+
refreshAsync
|
|
354
|
+
}), [hasAccess, currentUser, profile, combinedAccess, effectivePermissions, profileStatus, isArchived, isSuspended, profileLoading, isAccessLoading]);
|
|
355
|
+
return /* @__PURE__ */ jsx(setupAuthContext.Provider, { value: authState, children });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/auth/context/PermissionContext.tsx
|
|
359
|
+
import { createContext as createContext2, useCallback as useCallback2, useContext, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef3, useState as useState2 } from "react";
|
|
360
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
77
361
|
function getCacheKey(userId, entityType, entityId) {
|
|
78
362
|
return `${userId || "anon"}:${entityType}:${entityId}`;
|
|
79
363
|
}
|
|
@@ -188,13 +472,13 @@ function PermissionProvider({
|
|
|
188
472
|
const supabase = useSupabase();
|
|
189
473
|
const setupAuth = useContext(setupAuthContext);
|
|
190
474
|
const user = setupAuth?.user;
|
|
191
|
-
const cacheRef =
|
|
192
|
-
const pendingLookupsRef =
|
|
193
|
-
const inFlightRef =
|
|
194
|
-
const batchTimerRef =
|
|
195
|
-
const [isLoading, setIsLoading] =
|
|
196
|
-
const [, forceUpdate] =
|
|
197
|
-
const cleanupExpiredEntries =
|
|
475
|
+
const cacheRef = useRef3(/* @__PURE__ */ new Map());
|
|
476
|
+
const pendingLookupsRef = useRef3(/* @__PURE__ */ new Set());
|
|
477
|
+
const inFlightRef = useRef3(/* @__PURE__ */ new Set());
|
|
478
|
+
const batchTimerRef = useRef3(null);
|
|
479
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
480
|
+
const [, forceUpdate] = useState2(0);
|
|
481
|
+
const cleanupExpiredEntries = useCallback2(() => {
|
|
198
482
|
const now = Date.now();
|
|
199
483
|
const cache = cacheRef.current;
|
|
200
484
|
let hasExpired = false;
|
|
@@ -208,11 +492,11 @@ function PermissionProvider({
|
|
|
208
492
|
forceUpdate((prev) => prev + 1);
|
|
209
493
|
}
|
|
210
494
|
}, []);
|
|
211
|
-
|
|
495
|
+
useEffect2(() => {
|
|
212
496
|
const cleanupInterval = setInterval(cleanupExpiredEntries, 60 * 1e3);
|
|
213
497
|
return () => clearInterval(cleanupInterval);
|
|
214
498
|
}, [cleanupExpiredEntries]);
|
|
215
|
-
const executeBatchLookup =
|
|
499
|
+
const executeBatchLookup = useCallback2(async () => {
|
|
216
500
|
const pending = Array.from(pendingLookupsRef.current);
|
|
217
501
|
pendingLookupsRef.current.clear();
|
|
218
502
|
if (pending.length === 0 || !user?.id) {
|
|
@@ -272,7 +556,7 @@ function PermissionProvider({
|
|
|
272
556
|
setIsLoading(false);
|
|
273
557
|
}
|
|
274
558
|
}, [supabase, user?.id]);
|
|
275
|
-
const scheduleBatchLookup =
|
|
559
|
+
const scheduleBatchLookup = useCallback2(() => {
|
|
276
560
|
if (batchTimerRef.current) {
|
|
277
561
|
clearTimeout(batchTimerRef.current);
|
|
278
562
|
}
|
|
@@ -281,7 +565,7 @@ function PermissionProvider({
|
|
|
281
565
|
executeBatchLookup();
|
|
282
566
|
}, BATCH_DELAY_MS);
|
|
283
567
|
}, [executeBatchLookup]);
|
|
284
|
-
const getPermission =
|
|
568
|
+
const getPermission = useCallback2((entityType_0, entityId) => {
|
|
285
569
|
const key_4 = getCacheKey(user?.id, entityType_0, entityId);
|
|
286
570
|
const cache_2 = cacheRef.current;
|
|
287
571
|
const cached = cache_2.get(key_4);
|
|
@@ -295,7 +579,7 @@ function PermissionProvider({
|
|
|
295
579
|
}
|
|
296
580
|
return loadingPermission;
|
|
297
581
|
}, [scheduleBatchLookup, user?.id]);
|
|
298
|
-
const checkPermission =
|
|
582
|
+
const checkPermission = useCallback2((entityType_1, entityId_0, action) => {
|
|
299
583
|
const permission = getPermission(entityType_1, entityId_0);
|
|
300
584
|
if (permission.isLoading) {
|
|
301
585
|
return false;
|
|
@@ -317,7 +601,7 @@ function PermissionProvider({
|
|
|
317
601
|
return false;
|
|
318
602
|
}
|
|
319
603
|
}, [getPermission]);
|
|
320
|
-
const prefetchPermissions =
|
|
604
|
+
const prefetchPermissions = useCallback2(async (entities_0) => {
|
|
321
605
|
if (!user?.id || entities_0.length === 0) {
|
|
322
606
|
return;
|
|
323
607
|
}
|
|
@@ -347,416 +631,126 @@ function PermissionProvider({
|
|
|
347
631
|
p_entities: entitiesParam
|
|
348
632
|
});
|
|
349
633
|
if (error_0) {
|
|
350
|
-
console.error("Failed to prefetch entity permissions:", error_0);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
if (data_0) {
|
|
354
|
-
const cacheTimestamp = Date.now();
|
|
355
|
-
const resultsMap_0 = /* @__PURE__ */ new Map();
|
|
356
|
-
const results_0 = data_0;
|
|
357
|
-
for (const result_0 of results_0) {
|
|
358
|
-
const key_6 = getCacheKey(user?.id, result_0.entity_type, result_0.entity_id);
|
|
359
|
-
resultsMap_0.set(key_6, result_0.permission);
|
|
360
|
-
}
|
|
361
|
-
for (const entity_0 of toFetch) {
|
|
362
|
-
const key_7 = getCacheKey(user?.id, entity_0.entityType, entity_0.entityId);
|
|
363
|
-
const permissionLevel_0 = resultsMap_0.get(key_7) || null;
|
|
364
|
-
cache_3.set(key_7, {
|
|
365
|
-
permission: mapPermissionLevel(permissionLevel_0),
|
|
366
|
-
expiresAt: cacheTimestamp + CACHE_TTL_MS
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
forceUpdate((prev_1) => prev_1 + 1);
|
|
370
|
-
}
|
|
371
|
-
} catch (err_0) {
|
|
372
|
-
console.error("Unexpected error prefetching entity permissions:", err_0);
|
|
373
|
-
} finally {
|
|
374
|
-
setIsLoading(false);
|
|
375
|
-
}
|
|
376
|
-
}, [supabase, user?.id]);
|
|
377
|
-
const invalidatePermission = useCallback((entityType_2, entityId_1) => {
|
|
378
|
-
const key_8 = getCacheKey(user?.id, entityType_2, entityId_1);
|
|
379
|
-
cacheRef.current.delete(key_8);
|
|
380
|
-
forceUpdate((prev_2) => prev_2 + 1);
|
|
381
|
-
}, [user?.id]);
|
|
382
|
-
const parseScopedAccessKey = useCallback((key_9) => {
|
|
383
|
-
if (!key_9 || typeof key_9 !== "string") {
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
386
|
-
const parts_0 = key_9.split(":");
|
|
387
|
-
if (parts_0.length < 2) {
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
390
|
-
const entityType_3 = parts_0[0];
|
|
391
|
-
const entityId_2 = parseInt(parts_0[1], 10);
|
|
392
|
-
if (isNaN(entityId_2)) {
|
|
393
|
-
return null;
|
|
394
|
-
}
|
|
395
|
-
const entityTypeMap = {
|
|
396
|
-
client: "Client",
|
|
397
|
-
project: "Project",
|
|
398
|
-
database: "ProjectDatabase",
|
|
399
|
-
projectdatabase: "ProjectDatabase"
|
|
400
|
-
};
|
|
401
|
-
const normalizedEntityType = entityTypeMap[entityType_3.toLowerCase()];
|
|
402
|
-
if (!normalizedEntityType) {
|
|
403
|
-
return null;
|
|
404
|
-
}
|
|
405
|
-
return {
|
|
406
|
-
entityType: normalizedEntityType,
|
|
407
|
-
entityId: entityId_2
|
|
408
|
-
};
|
|
409
|
-
}, []);
|
|
410
|
-
useEffect(() => {
|
|
411
|
-
if (!user?.id) {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
const channel = supabase.channel(`entity-permissions-${user.id}`).on("postgres_changes", {
|
|
415
|
-
event: "*",
|
|
416
|
-
schema: "core",
|
|
417
|
-
table: "UserAccess",
|
|
418
|
-
filter: `userId=eq.${user.id}`
|
|
419
|
-
}, (payload) => {
|
|
420
|
-
if (payload.new && typeof payload.new === "object" && "scopedAccessKey" in payload.new && typeof payload.new.scopedAccessKey === "string") {
|
|
421
|
-
const parsed = parseScopedAccessKey(payload.new.scopedAccessKey);
|
|
422
|
-
if (parsed) {
|
|
423
|
-
invalidatePermission(parsed.entityType, parsed.entityId);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
if (payload.old && typeof payload.old === "object" && "scopedAccessKey" in payload.old && typeof payload.old.scopedAccessKey === "string") {
|
|
427
|
-
const parsed_0 = parseScopedAccessKey(payload.old.scopedAccessKey);
|
|
428
|
-
if (parsed_0) {
|
|
429
|
-
invalidatePermission(parsed_0.entityType, parsed_0.entityId);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}).subscribe();
|
|
433
|
-
return () => {
|
|
434
|
-
channel.unsubscribe();
|
|
435
|
-
supabase.removeChannel(channel);
|
|
436
|
-
};
|
|
437
|
-
}, [supabase, user?.id, invalidatePermission, parseScopedAccessKey]);
|
|
438
|
-
useEffect(() => {
|
|
439
|
-
cacheRef.current.clear();
|
|
440
|
-
pendingLookupsRef.current.clear();
|
|
441
|
-
inFlightRef.current.clear();
|
|
442
|
-
if (batchTimerRef.current) {
|
|
443
|
-
clearTimeout(batchTimerRef.current);
|
|
444
|
-
batchTimerRef.current = null;
|
|
445
|
-
}
|
|
446
|
-
forceUpdate((prev_3) => prev_3 + 1);
|
|
447
|
-
}, [user?.id]);
|
|
448
|
-
useEffect(() => {
|
|
449
|
-
return () => {
|
|
450
|
-
if (batchTimerRef.current) {
|
|
451
|
-
clearTimeout(batchTimerRef.current);
|
|
452
|
-
}
|
|
453
|
-
};
|
|
454
|
-
}, []);
|
|
455
|
-
const value = useMemo2(() => ({
|
|
456
|
-
getPermission,
|
|
457
|
-
checkPermission,
|
|
458
|
-
prefetchPermissions,
|
|
459
|
-
invalidatePermission,
|
|
460
|
-
isLoading
|
|
461
|
-
}), [getPermission, checkPermission, prefetchPermissions, invalidatePermission, isLoading]);
|
|
462
|
-
return /* @__PURE__ */ jsx(permissionContext.Provider, { value, children });
|
|
463
|
-
}
|
|
464
|
-
function usePermissions() {
|
|
465
|
-
const context = useContext(permissionContext);
|
|
466
|
-
if (!context || Object.keys(context).length === 0) {
|
|
467
|
-
throw new Error("usePermissions must be used within a PermissionProvider");
|
|
468
|
-
}
|
|
469
|
-
return context;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// src/auth/context/AuthProvider.tsx
|
|
473
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef3, useState as useState2 } from "react";
|
|
474
|
-
import { isUsable, newUuid } from "@pol-studios/utils";
|
|
475
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
476
|
-
var SESSION_FETCH_TIMEOUT_MS = 3e3;
|
|
477
|
-
function getPermissionLevel(action) {
|
|
478
|
-
switch (action.toLowerCase()) {
|
|
479
|
-
case "view":
|
|
480
|
-
case "read":
|
|
481
|
-
return 1;
|
|
482
|
-
case "edit":
|
|
483
|
-
case "write":
|
|
484
|
-
return 2;
|
|
485
|
-
case "admin":
|
|
486
|
-
case "delete":
|
|
487
|
-
case "share":
|
|
488
|
-
return 3;
|
|
489
|
-
default:
|
|
490
|
-
return 0;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
function isNotExpired(expiresAt) {
|
|
494
|
-
return !expiresAt || new Date(expiresAt) > /* @__PURE__ */ new Date();
|
|
495
|
-
}
|
|
496
|
-
function matchesAccessPattern(pattern, requestedKey) {
|
|
497
|
-
if (pattern === requestedKey) return true;
|
|
498
|
-
if (pattern === "*:*:*") return true;
|
|
499
|
-
const patternParts = pattern.split(":");
|
|
500
|
-
const keyParts = requestedKey.split(":");
|
|
501
|
-
if (patternParts.length !== keyParts.length) return false;
|
|
502
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
503
|
-
if (patternParts[i] === "*") continue;
|
|
504
|
-
if (patternParts[i] !== keyParts[i]) return false;
|
|
505
|
-
}
|
|
506
|
-
return true;
|
|
507
|
-
}
|
|
508
|
-
function AuthProvider({
|
|
509
|
-
children,
|
|
510
|
-
enableEntityPermissions = false
|
|
511
|
-
}) {
|
|
512
|
-
const supabase = useSupabase();
|
|
513
|
-
const [currentUser, setCurrentUser] = useState2(void 0);
|
|
514
|
-
const [userNeedsChange, setUserNeedsChange] = useState2(true);
|
|
515
|
-
const [onSignOutCallbacks, setOnSignOutCallbacks] = useState2(/* @__PURE__ */ new Map());
|
|
516
|
-
async function registerAsync(register) {
|
|
517
|
-
const response = await supabase.auth.signUp(register);
|
|
518
|
-
if (response.data.user) {
|
|
519
|
-
setCurrentUser((prev) => prev?.id === response.data.user?.id ? prev : response.data.user);
|
|
520
|
-
}
|
|
521
|
-
return response;
|
|
522
|
-
}
|
|
523
|
-
async function signInAsync(username, password) {
|
|
524
|
-
const response_0 = await supabase.auth.signInWithPassword({
|
|
525
|
-
email: username,
|
|
526
|
-
password
|
|
527
|
-
});
|
|
528
|
-
if (response_0.data.user) {
|
|
529
|
-
setCurrentUser((prev_0) => prev_0?.id === response_0.data.user?.id ? prev_0 : response_0.data.user);
|
|
530
|
-
}
|
|
531
|
-
return response_0;
|
|
532
|
-
}
|
|
533
|
-
const signOutAsync = useCallback2(async () => {
|
|
534
|
-
const response_1 = await supabase.auth.signOut();
|
|
535
|
-
if (!response_1.error) {
|
|
536
|
-
Array.from(onSignOutCallbacks.values()).forEach((cb) => cb());
|
|
537
|
-
}
|
|
538
|
-
return response_1;
|
|
539
|
-
}, [supabase.auth, onSignOutCallbacks]);
|
|
540
|
-
function onSignOut(action) {
|
|
541
|
-
const id = newUuid();
|
|
542
|
-
setOnSignOutCallbacks((x) => new Map(x).set(id, action));
|
|
543
|
-
return id;
|
|
544
|
-
}
|
|
545
|
-
function removeOnSignOut(id_0) {
|
|
546
|
-
setOnSignOutCallbacks((x_0) => {
|
|
547
|
-
const map = new Map(x_0);
|
|
548
|
-
map.delete(id_0);
|
|
549
|
-
return map;
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
async function refreshAsync() {
|
|
553
|
-
}
|
|
554
|
-
useEffect2(() => {
|
|
555
|
-
const {
|
|
556
|
-
data: {
|
|
557
|
-
subscription
|
|
558
|
-
}
|
|
559
|
-
} = supabase.auth.onAuthStateChange((event) => {
|
|
560
|
-
if (event === "SIGNED_IN" || event === "SIGNED_OUT") {
|
|
561
|
-
setUserNeedsChange(true);
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
return () => subscription.unsubscribe();
|
|
565
|
-
}, [supabase.auth]);
|
|
566
|
-
useEffect2(() => {
|
|
567
|
-
if (!userNeedsChange) return;
|
|
568
|
-
let cancelled = false;
|
|
569
|
-
async function fetchSessionWithTimeout() {
|
|
570
|
-
try {
|
|
571
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
572
|
-
setTimeout(() => {
|
|
573
|
-
reject(new Error(`Session fetch timed out after ${SESSION_FETCH_TIMEOUT_MS}ms`));
|
|
574
|
-
}, SESSION_FETCH_TIMEOUT_MS);
|
|
575
|
-
});
|
|
576
|
-
const result = await Promise.race([supabase.auth.getSession(), timeoutPromise]);
|
|
577
|
-
if (cancelled) return;
|
|
578
|
-
const newUser = result?.data?.session?.user ?? null;
|
|
579
|
-
setCurrentUser((prev_2) => {
|
|
580
|
-
if (newUser === null) return null;
|
|
581
|
-
if (prev_2?.id === newUser?.id) return prev_2;
|
|
582
|
-
return newUser;
|
|
583
|
-
});
|
|
584
|
-
setUserNeedsChange(false);
|
|
585
|
-
} catch (error) {
|
|
586
|
-
if (cancelled) return;
|
|
587
|
-
console.error("Failed to get session (timeout or error):", error);
|
|
588
|
-
setCurrentUser((prev_1) => prev_1 === null ? prev_1 : null);
|
|
589
|
-
setUserNeedsChange(false);
|
|
634
|
+
console.error("Failed to prefetch entity permissions:", error_0);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (data_0) {
|
|
638
|
+
const cacheTimestamp = Date.now();
|
|
639
|
+
const resultsMap_0 = /* @__PURE__ */ new Map();
|
|
640
|
+
const results_0 = data_0;
|
|
641
|
+
for (const result_0 of results_0) {
|
|
642
|
+
const key_6 = getCacheKey(user?.id, result_0.entity_type, result_0.entity_id);
|
|
643
|
+
resultsMap_0.set(key_6, result_0.permission);
|
|
644
|
+
}
|
|
645
|
+
for (const entity_0 of toFetch) {
|
|
646
|
+
const key_7 = getCacheKey(user?.id, entity_0.entityType, entity_0.entityId);
|
|
647
|
+
const permissionLevel_0 = resultsMap_0.get(key_7) || null;
|
|
648
|
+
cache_3.set(key_7, {
|
|
649
|
+
permission: mapPermissionLevel(permissionLevel_0),
|
|
650
|
+
expiresAt: cacheTimestamp + CACHE_TTL_MS
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
forceUpdate((prev_1) => prev_1 + 1);
|
|
590
654
|
}
|
|
655
|
+
} catch (err_0) {
|
|
656
|
+
console.error("Unexpected error prefetching entity permissions:", err_0);
|
|
657
|
+
} finally {
|
|
658
|
+
setIsLoading(false);
|
|
591
659
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
660
|
+
}, [supabase, user?.id]);
|
|
661
|
+
const invalidatePermission = useCallback2((entityType_2, entityId_1) => {
|
|
662
|
+
const key_8 = getCacheKey(user?.id, entityType_2, entityId_1);
|
|
663
|
+
cacheRef.current.delete(key_8);
|
|
664
|
+
forceUpdate((prev_2) => prev_2 + 1);
|
|
665
|
+
}, [user?.id]);
|
|
666
|
+
const parseScopedAccessKey = useCallback2((key_9) => {
|
|
667
|
+
if (!key_9 || typeof key_9 !== "string") {
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
const parts_0 = key_9.split(":");
|
|
671
|
+
if (parts_0.length < 2) {
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
const entityType_3 = parts_0[0];
|
|
675
|
+
const entityId_2 = parseInt(parts_0[1], 10);
|
|
676
|
+
if (isNaN(entityId_2)) {
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
const entityTypeMap = {
|
|
680
|
+
client: "Client",
|
|
681
|
+
project: "Project",
|
|
682
|
+
database: "ProjectDatabase",
|
|
683
|
+
projectdatabase: "ProjectDatabase"
|
|
595
684
|
};
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
enabled: isUserReady,
|
|
606
|
-
realtime: true
|
|
607
|
-
});
|
|
608
|
-
const {
|
|
609
|
-
data: directAccess,
|
|
610
|
-
isLoading: directAccessLoading
|
|
611
|
-
} = useDbQuery("core.UserAccess", {
|
|
612
|
-
where: {
|
|
613
|
-
userId: currentUser?.id
|
|
614
|
-
},
|
|
615
|
-
enabled: isUserReady,
|
|
616
|
-
realtime: true
|
|
617
|
-
});
|
|
618
|
-
const {
|
|
619
|
-
data: userGroups,
|
|
620
|
-
isLoading: userGroupsLoading
|
|
621
|
-
} = useDbQuery("core.UserGroup", {
|
|
622
|
-
where: {
|
|
623
|
-
userId: currentUser?.id
|
|
624
|
-
},
|
|
625
|
-
enabled: isUserReady,
|
|
626
|
-
realtime: true
|
|
627
|
-
});
|
|
628
|
-
const {
|
|
629
|
-
data: groups,
|
|
630
|
-
isLoading: groupsLoading
|
|
631
|
-
} = useDbQuery("core.Group", {
|
|
632
|
-
where: {
|
|
633
|
-
isActive: 1
|
|
634
|
-
},
|
|
635
|
-
enabled: isUserReady,
|
|
636
|
-
realtime: true
|
|
637
|
-
});
|
|
638
|
-
const groupIds = useMemo3(() => userGroups?.map((ug) => ug.groupId) ?? [], [userGroups]);
|
|
639
|
-
const groupsMap = useMemo3(() => new Map(groups?.map((g) => [g.id, g]) ?? []), [groups]);
|
|
640
|
-
const {
|
|
641
|
-
data: groupAccess,
|
|
642
|
-
isLoading: groupAccessLoading
|
|
643
|
-
} = useDbQuery("core.GroupAccessKey", {
|
|
644
|
-
where: groupIds.length > 0 ? {
|
|
645
|
-
groupId: {
|
|
646
|
-
in: groupIds
|
|
647
|
-
}
|
|
648
|
-
} : void 0,
|
|
649
|
-
enabled: groupIds.length > 0,
|
|
650
|
-
realtime: true
|
|
651
|
-
});
|
|
652
|
-
const profile = profileData?.[0] ?? null;
|
|
653
|
-
const prevProfileStatusRef = useRef3(void 0);
|
|
685
|
+
const normalizedEntityType = entityTypeMap[entityType_3.toLowerCase()];
|
|
686
|
+
if (!normalizedEntityType) {
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
entityType: normalizedEntityType,
|
|
691
|
+
entityId: entityId_2
|
|
692
|
+
};
|
|
693
|
+
}, []);
|
|
654
694
|
useEffect2(() => {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
if (prevStatus === "active" && (currentStatus === "archived" || currentStatus === "suspended")) {
|
|
658
|
-
signOutAsync();
|
|
695
|
+
if (!user?.id) {
|
|
696
|
+
return;
|
|
659
697
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
});
|
|
674
|
-
const activeGroupIds = new Set(userGroups?.filter((ug_0) => {
|
|
675
|
-
const group = groupsMap.get(ug_0.groupId);
|
|
676
|
-
return group?.isActive === 1 && isNotExpired(ug_0.expiresAt);
|
|
677
|
-
}).map((ug_1) => ug_1.groupId) ?? []);
|
|
678
|
-
groupAccess?.forEach((ga) => {
|
|
679
|
-
if (activeGroupIds.has(ga.groupId) && isNotExpired(ga.expiresAt)) {
|
|
680
|
-
keys.push({
|
|
681
|
-
accessKey: ga.accessKey,
|
|
682
|
-
effect: ga.effect ?? "allow",
|
|
683
|
-
source: "group",
|
|
684
|
-
expiresAt: ga.expiresAt
|
|
685
|
-
});
|
|
698
|
+
const channel = supabase.channel(`entity-permissions-${user.id}`).on("postgres_changes", {
|
|
699
|
+
event: "*",
|
|
700
|
+
schema: "core",
|
|
701
|
+
table: "UserAccess",
|
|
702
|
+
filter: `userId=eq.${user.id}`
|
|
703
|
+
}, (payload) => {
|
|
704
|
+
if (payload.new && typeof payload.new === "object" && "scopedAccessKey" in payload.new && typeof payload.new.scopedAccessKey === "string") {
|
|
705
|
+
const parsed = parseScopedAccessKey(payload.new.scopedAccessKey);
|
|
706
|
+
if (parsed) {
|
|
707
|
+
invalidatePermission(parsed.entityType, parsed.entityId);
|
|
708
|
+
}
|
|
686
709
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
for (const item of allAccessKeys) {
|
|
693
|
-
if (item.accessKey && item.effect === "allow") {
|
|
694
|
-
uniqueKeys.add(item.accessKey);
|
|
710
|
+
if (payload.old && typeof payload.old === "object" && "scopedAccessKey" in payload.old && typeof payload.old.scopedAccessKey === "string") {
|
|
711
|
+
const parsed_0 = parseScopedAccessKey(payload.old.scopedAccessKey);
|
|
712
|
+
if (parsed_0) {
|
|
713
|
+
invalidatePermission(parsed_0.entityType, parsed_0.entityId);
|
|
714
|
+
}
|
|
695
715
|
}
|
|
716
|
+
}).subscribe();
|
|
717
|
+
return () => {
|
|
718
|
+
channel.unsubscribe();
|
|
719
|
+
supabase.removeChannel(channel);
|
|
720
|
+
};
|
|
721
|
+
}, [supabase, user?.id, invalidatePermission, parseScopedAccessKey]);
|
|
722
|
+
useEffect2(() => {
|
|
723
|
+
cacheRef.current.clear();
|
|
724
|
+
pendingLookupsRef.current.clear();
|
|
725
|
+
inFlightRef.current.clear();
|
|
726
|
+
if (batchTimerRef.current) {
|
|
727
|
+
clearTimeout(batchTimerRef.current);
|
|
728
|
+
batchTimerRef.current = null;
|
|
696
729
|
}
|
|
697
|
-
|
|
698
|
-
}, [
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
const parts = item_0.accessKey.split(":");
|
|
704
|
-
if (parts.length === 3) {
|
|
705
|
-
const [resourceType, resourceId, permission] = parts;
|
|
706
|
-
permissions.push({
|
|
707
|
-
resourceType,
|
|
708
|
-
resourceId,
|
|
709
|
-
permission,
|
|
710
|
-
permissionLevel: getPermissionLevel(permission),
|
|
711
|
-
source: item_0.source,
|
|
712
|
-
inheritedFrom: null,
|
|
713
|
-
expiresAt: item_0.expiresAt ?? null
|
|
714
|
-
});
|
|
730
|
+
forceUpdate((prev_3) => prev_3 + 1);
|
|
731
|
+
}, [user?.id]);
|
|
732
|
+
useEffect2(() => {
|
|
733
|
+
return () => {
|
|
734
|
+
if (batchTimerRef.current) {
|
|
735
|
+
clearTimeout(batchTimerRef.current);
|
|
715
736
|
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
const [type, id_1, action_0] = parts_0;
|
|
734
|
-
const requiredLevel = getPermissionLevel(action_0);
|
|
735
|
-
const hasPermission = effectivePermissions.some((p) => p.resourceType === type && p.resourceId === id_1 && p.permissionLevel >= requiredLevel);
|
|
736
|
-
if (hasPermission) return true;
|
|
737
|
-
}
|
|
738
|
-
return false;
|
|
739
|
-
}, [combinedAccess, effectivePermissions, isArchived, isSuspended]);
|
|
740
|
-
const isAccessLoading = directAccessLoading || userGroupsLoading || groupsLoading || groupAccessLoading;
|
|
741
|
-
const authState = useMemo3(() => ({
|
|
742
|
-
hasAccess,
|
|
743
|
-
user: currentUser,
|
|
744
|
-
profile,
|
|
745
|
-
access: combinedAccess,
|
|
746
|
-
effectivePermissions,
|
|
747
|
-
profileStatus,
|
|
748
|
-
isArchived,
|
|
749
|
-
isSuspended,
|
|
750
|
-
isLoading: currentUser === null ? false : profileLoading || isAccessLoading || currentUser === void 0,
|
|
751
|
-
signInAsync,
|
|
752
|
-
signOutAsync,
|
|
753
|
-
onSignOut,
|
|
754
|
-
removeOnSignOut,
|
|
755
|
-
registerAsync,
|
|
756
|
-
refreshAsync
|
|
757
|
-
}), [hasAccess, currentUser, profile, combinedAccess, effectivePermissions, profileStatus, isArchived, isSuspended, profileLoading, isAccessLoading]);
|
|
758
|
-
const content = enableEntityPermissions ? /* @__PURE__ */ jsx2(PermissionProvider, { children }) : children;
|
|
759
|
-
return /* @__PURE__ */ jsx2(setupAuthContext.Provider, { value: authState, children: content });
|
|
737
|
+
};
|
|
738
|
+
}, []);
|
|
739
|
+
const value = useMemo3(() => ({
|
|
740
|
+
getPermission,
|
|
741
|
+
checkPermission,
|
|
742
|
+
prefetchPermissions,
|
|
743
|
+
invalidatePermission,
|
|
744
|
+
isLoading
|
|
745
|
+
}), [getPermission, checkPermission, prefetchPermissions, invalidatePermission, isLoading]);
|
|
746
|
+
return /* @__PURE__ */ jsx2(permissionContext.Provider, { value, children });
|
|
747
|
+
}
|
|
748
|
+
function usePermissions() {
|
|
749
|
+
const context = useContext(permissionContext);
|
|
750
|
+
if (!context || Object.keys(context).length === 0) {
|
|
751
|
+
throw new Error("usePermissions must be used within a PermissionProvider");
|
|
752
|
+
}
|
|
753
|
+
return context;
|
|
760
754
|
}
|
|
761
755
|
|
|
762
756
|
// src/auth/context/UserMetadataContext.tsx
|
|
@@ -1100,11 +1094,11 @@ export {
|
|
|
1100
1094
|
isTimeoutError,
|
|
1101
1095
|
useDbQuery2 as useDbQuery,
|
|
1102
1096
|
setupAuthContext,
|
|
1097
|
+
AuthProvider,
|
|
1103
1098
|
permissionContext,
|
|
1104
1099
|
entityPermissionContext,
|
|
1105
1100
|
PermissionProvider,
|
|
1106
1101
|
usePermissions,
|
|
1107
|
-
AuthProvider,
|
|
1108
1102
|
userMetadataContext,
|
|
1109
1103
|
UserMetadataProvider,
|
|
1110
1104
|
useUserMetadata,
|
|
@@ -1112,4 +1106,4 @@ export {
|
|
|
1112
1106
|
useSetUserMetadata,
|
|
1113
1107
|
useUserMetadataState
|
|
1114
1108
|
};
|
|
1115
|
-
//# sourceMappingURL=chunk-
|
|
1109
|
+
//# sourceMappingURL=chunk-MZLEDWJF.js.map
|