@pol-studios/db 1.0.10 → 1.0.12
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/DataLayerContext-CL6alnkb.d.ts +755 -0
- package/dist/UserMetadataContext-B8gVWGMl.d.ts +35 -0
- package/dist/UserMetadataContext-DntmpK41.d.ts +33 -0
- package/dist/auth/context.d.ts +3 -2
- package/dist/auth/context.js +5 -4
- package/dist/auth/guards.js +2 -2
- package/dist/auth/hooks.d.ts +3 -3
- package/dist/auth/hooks.js +6 -5
- package/dist/auth/index.d.ts +3 -2
- package/dist/auth/index.js +8 -6
- package/dist/{canvas-UVNDA54X.node → canvas-C4TBBDUL.node} +0 -0
- package/dist/{canvas-75Y7XMF3.js → canvas-ZQNCL7JL.js} +2 -2
- package/dist/chunk-5EFDS7SR.js +205 -0
- package/dist/chunk-5EFDS7SR.js.map +1 -0
- package/dist/{chunk-BRTW7CO5.js → chunk-7SCJNYTE.js} +1 -9
- package/dist/chunk-7SCJNYTE.js.map +1 -0
- package/dist/chunk-DJ6VLEAL.js +247 -0
- package/dist/chunk-DJ6VLEAL.js.map +1 -0
- package/dist/{chunk-Y3INY2CS.js → chunk-GC3TBUWE.js} +1 -1
- package/dist/chunk-GC3TBUWE.js.map +1 -0
- package/dist/{chunk-7HG6G25H.js → chunk-H3LNH2NT.js} +169 -268
- package/dist/chunk-H3LNH2NT.js.map +1 -0
- package/dist/{chunk-USJYMRUO.js → chunk-HAWJTZCK.js} +2 -2
- package/dist/chunk-HAWJTZCK.js.map +1 -0
- package/dist/chunk-JAATANS3.js +429 -0
- package/dist/chunk-JAATANS3.js.map +1 -0
- package/dist/chunk-LNJ3WF7V.js +470 -0
- package/dist/chunk-LNJ3WF7V.js.map +1 -0
- package/dist/chunk-N26IEHZT.js +79 -0
- package/dist/chunk-N26IEHZT.js.map +1 -0
- package/dist/chunk-NSIAAYW3.js +1 -0
- package/dist/chunk-NSIAAYW3.js.map +1 -0
- package/dist/chunk-NZON56CB.js +3864 -0
- package/dist/chunk-NZON56CB.js.map +1 -0
- package/dist/{chunk-O3K7R32P.js → chunk-OQ7U6EQ3.js} +118 -123
- package/dist/chunk-OQ7U6EQ3.js.map +1 -0
- package/dist/chunk-SM73S2DY.js +11 -0
- package/dist/chunk-SM73S2DY.js.map +1 -0
- package/dist/{chunk-JUVE3DWY.js → chunk-TKWR5AAY.js} +47 -65
- package/dist/chunk-TKWR5AAY.js.map +1 -0
- package/dist/{chunk-2IFGILT3.js → chunk-U5UNPBKB.js} +76 -107
- package/dist/chunk-U5UNPBKB.js.map +1 -0
- package/dist/chunk-WGDJ4IXR.js +921 -0
- package/dist/chunk-WGDJ4IXR.js.map +1 -0
- package/dist/chunk-WVF7RUW5.js +186 -0
- package/dist/chunk-WVF7RUW5.js.map +1 -0
- package/dist/{chunk-ZTSBF536.js → chunk-X3HZLNBV.js} +637 -435
- package/dist/chunk-X3HZLNBV.js.map +1 -0
- package/dist/{chunk-EL45Z26M.js → chunk-XU3SBFAG.js} +1219 -208
- package/dist/chunk-XU3SBFAG.js.map +1 -0
- package/dist/chunk-ZVBHWU7O.js +1412 -0
- package/dist/chunk-ZVBHWU7O.js.map +1 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +42 -23
- package/dist/client/index.js.map +1 -1
- package/dist/core/index.d.ts +19 -0
- package/dist/{index-BFu5_dS8.d.ts → database.types-ChFCG-4M.d.ts} +1 -177
- package/dist/gen/index.js +4 -2
- package/dist/hooks/index.d.ts +10 -3
- package/dist/hooks/index.js +8 -10
- package/dist/index-CQLyNG6A.d.ts +433 -0
- package/dist/index.d.ts +12 -8
- package/dist/index.js +92 -48
- package/dist/index.native.d.ts +373 -33
- package/dist/index.native.js +79 -47
- package/dist/index.web.d.ts +10 -7
- package/dist/index.web.js +83 -78
- package/dist/index.web.js.map +1 -1
- package/dist/mutation/index.d.ts +2 -2
- package/dist/mutation/index.js +307 -122
- package/dist/mutation/index.js.map +1 -1
- package/dist/parser/index.js +2 -2
- package/dist/{pdf-3TIGQRLA.js → pdf-PHXP7RHD.js} +2 -2
- package/dist/powersync-bridge/index.d.ts +284 -0
- package/dist/powersync-bridge/index.js +22 -0
- package/dist/powersync-bridge/index.js.map +1 -0
- package/dist/query/index.js +5 -5
- package/dist/realtime/index.js +252 -128
- package/dist/realtime/index.js.map +1 -1
- package/dist/{UserMetadataContext-BYYqA6LI.d.ts → setupAuthContext-Kv-THH-h.d.ts} +1 -29
- package/dist/types/index.d.ts +5 -1
- package/dist/types/index.js +10 -5
- package/dist/{useBatchUpsert-CSQVX7w8.d.ts → useBatchUpsert-9OYjibLh.d.ts} +1 -1
- package/dist/{useDbCount-RGCuHmHp.d.ts → useDbCount-BG356T9i.d.ts} +3 -719
- package/dist/{useReceiptAI-Bn0czE7C.d.ts → useReceiptAI-6HkRpRml.d.ts} +1 -1
- package/dist/{useResolveFeedback-CpZPP8Pw.d.ts → useResolveFeedback-BWmatBlE.d.ts} +26 -45
- package/dist/{useSupabase-pPhUZHcl.d.ts → useSupabase-DvWVuHHE.d.ts} +2 -1
- package/dist/with-auth/index.d.ts +704 -0
- package/dist/with-auth/index.js +1221 -0
- package/dist/with-auth/index.js.map +1 -0
- package/package.json +25 -10
- package/dist/chunk-2IFGILT3.js.map +0 -1
- package/dist/chunk-3M2U6TXH.js +0 -928
- package/dist/chunk-3M2U6TXH.js.map +0 -1
- package/dist/chunk-5ZYAEGCJ.js +0 -416
- package/dist/chunk-5ZYAEGCJ.js.map +0 -1
- package/dist/chunk-7HG6G25H.js.map +0 -1
- package/dist/chunk-7XT7K4QT.js +0 -2687
- package/dist/chunk-7XT7K4QT.js.map +0 -1
- package/dist/chunk-AWFMICFV.js +0 -158
- package/dist/chunk-AWFMICFV.js.map +0 -1
- package/dist/chunk-BRTW7CO5.js.map +0 -1
- package/dist/chunk-EL45Z26M.js.map +0 -1
- package/dist/chunk-ERGF2FCE.js +0 -903
- package/dist/chunk-ERGF2FCE.js.map +0 -1
- package/dist/chunk-GK7B66LY.js +0 -135
- package/dist/chunk-GK7B66LY.js.map +0 -1
- package/dist/chunk-GQI6WJGI.js +0 -172
- package/dist/chunk-GQI6WJGI.js.map +0 -1
- package/dist/chunk-JUVE3DWY.js.map +0 -1
- package/dist/chunk-O3K7R32P.js.map +0 -1
- package/dist/chunk-SEY5UO2T.js +0 -89
- package/dist/chunk-SEY5UO2T.js.map +0 -1
- package/dist/chunk-USJYMRUO.js.map +0 -1
- package/dist/chunk-XX3IWSPM.js +0 -189
- package/dist/chunk-XX3IWSPM.js.map +0 -1
- package/dist/chunk-Y3INY2CS.js.map +0 -1
- package/dist/chunk-ZTSBF536.js.map +0 -1
- /package/dist/{canvas-75Y7XMF3.js.map → canvas-ZQNCL7JL.js.map} +0 -0
- /package/dist/{pdf-3TIGQRLA.js.map → pdf-PHXP7RHD.js.map} +0 -0
|
@@ -0,0 +1,921 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useDbUpsert
|
|
3
|
+
} from "./chunk-ZVBHWU7O.js";
|
|
4
|
+
import {
|
|
5
|
+
isUsable,
|
|
6
|
+
newUuid,
|
|
7
|
+
omit
|
|
8
|
+
} from "./chunk-OQ7U6EQ3.js";
|
|
9
|
+
import {
|
|
10
|
+
encode
|
|
11
|
+
} from "./chunk-H6365JPC.js";
|
|
12
|
+
import {
|
|
13
|
+
typedSupabase,
|
|
14
|
+
useSupabase
|
|
15
|
+
} from "./chunk-5EFDS7SR.js";
|
|
16
|
+
|
|
17
|
+
// src/errors/TimeoutError.ts
|
|
18
|
+
var TIMEOUT_ERROR_MESSAGE = "Request timed out";
|
|
19
|
+
var DEFAULT_QUERY_TIMEOUT = 15e3;
|
|
20
|
+
function isTimeoutError(error) {
|
|
21
|
+
if (!error) return false;
|
|
22
|
+
return error.name === "AbortError" || error.message === TIMEOUT_ERROR_MESSAGE || error.message.toLowerCase().includes("timed out");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/useDbQuery.ts
|
|
26
|
+
import { useMemo, useRef } from "react";
|
|
27
|
+
import { useQuery } from "@tanstack/react-query";
|
|
28
|
+
import { useDelayedValue } from "@pol-studios/hooks/state";
|
|
29
|
+
function useDbQuery(query, config) {
|
|
30
|
+
const queryKey = encode(query, false);
|
|
31
|
+
const queryKeyString = queryKey.join("-");
|
|
32
|
+
const debouncedKeyString = useDelayedValue(queryKeyString, 50);
|
|
33
|
+
const isKeyStable = queryKeyString === debouncedKeyString;
|
|
34
|
+
const effectiveEnabled = config?.enabled !== false && isKeyStable;
|
|
35
|
+
const timeoutMs = config?.timeout ?? DEFAULT_QUERY_TIMEOUT;
|
|
36
|
+
const countRef = useRef(null);
|
|
37
|
+
const request = useQuery(useMemo(() => ({
|
|
38
|
+
queryKey,
|
|
39
|
+
queryFn: async ({
|
|
40
|
+
signal
|
|
41
|
+
}) => {
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
signal.addEventListener("abort", () => controller.abort());
|
|
44
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
45
|
+
try {
|
|
46
|
+
const queryWithSignal = query.abortSignal?.(controller.signal) ?? query;
|
|
47
|
+
const result = await queryWithSignal;
|
|
48
|
+
if (result.error) throw result.error;
|
|
49
|
+
countRef.current = result.count ?? null;
|
|
50
|
+
return result.data;
|
|
51
|
+
} catch (err) {
|
|
52
|
+
if (err.name === "AbortError") {
|
|
53
|
+
throw new Error(TIMEOUT_ERROR_MESSAGE);
|
|
54
|
+
}
|
|
55
|
+
throw err;
|
|
56
|
+
} finally {
|
|
57
|
+
clearTimeout(timeoutId);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
...omit({
|
|
61
|
+
retry: 1,
|
|
62
|
+
...config,
|
|
63
|
+
enabled: effectiveEnabled
|
|
64
|
+
}, ["queryKey", "timeout"])
|
|
65
|
+
}), [queryKey, config, effectiveEnabled, timeoutMs, query]));
|
|
66
|
+
return useMemo(() => ({
|
|
67
|
+
...request,
|
|
68
|
+
count: countRef.current
|
|
69
|
+
}), [request, countRef.current]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/auth/context/setupAuthContext.tsx
|
|
73
|
+
import { c as _c } from "react/compiler-runtime";
|
|
74
|
+
import { createContext } from "react";
|
|
75
|
+
import { jsx } from "react/jsx-runtime";
|
|
76
|
+
var setupAuthContext = createContext({});
|
|
77
|
+
function SetupAuthContextProvider(t0) {
|
|
78
|
+
const $ = _c(3);
|
|
79
|
+
const {
|
|
80
|
+
children,
|
|
81
|
+
auth
|
|
82
|
+
} = t0;
|
|
83
|
+
let t1;
|
|
84
|
+
if ($[0] !== auth || $[1] !== children) {
|
|
85
|
+
t1 = /* @__PURE__ */ jsx(setupAuthContext.Provider, { value: auth, children });
|
|
86
|
+
$[0] = auth;
|
|
87
|
+
$[1] = children;
|
|
88
|
+
$[2] = t1;
|
|
89
|
+
} else {
|
|
90
|
+
t1 = $[2];
|
|
91
|
+
}
|
|
92
|
+
return t1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/auth/context/PermissionContext.tsx
|
|
96
|
+
import { createContext as createContext2, useCallback, useContext, useEffect, useMemo as useMemo2, useRef as useRef2, useState } from "react";
|
|
97
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
98
|
+
function getCacheKey(userId, entityType, entityId) {
|
|
99
|
+
return `${userId || "anon"}:${entityType}:${entityId}`;
|
|
100
|
+
}
|
|
101
|
+
var loadingPermission = {
|
|
102
|
+
canView: false,
|
|
103
|
+
canAdminView: false,
|
|
104
|
+
canEdit: false,
|
|
105
|
+
canCreate: false,
|
|
106
|
+
canDelete: false,
|
|
107
|
+
canShare: false,
|
|
108
|
+
permissionLevel: null,
|
|
109
|
+
isLoading: true
|
|
110
|
+
};
|
|
111
|
+
var noPermission = {
|
|
112
|
+
canView: false,
|
|
113
|
+
canAdminView: false,
|
|
114
|
+
canEdit: false,
|
|
115
|
+
canCreate: false,
|
|
116
|
+
canDelete: false,
|
|
117
|
+
canShare: false,
|
|
118
|
+
permissionLevel: null,
|
|
119
|
+
isLoading: false,
|
|
120
|
+
isDenied: false
|
|
121
|
+
};
|
|
122
|
+
var deniedPermission = {
|
|
123
|
+
canView: false,
|
|
124
|
+
canAdminView: false,
|
|
125
|
+
canEdit: false,
|
|
126
|
+
canCreate: false,
|
|
127
|
+
canDelete: false,
|
|
128
|
+
canShare: false,
|
|
129
|
+
permissionLevel: null,
|
|
130
|
+
isLoading: false,
|
|
131
|
+
isDenied: true
|
|
132
|
+
};
|
|
133
|
+
function mapPermissionLevel(level) {
|
|
134
|
+
if (!level) {
|
|
135
|
+
return noPermission;
|
|
136
|
+
}
|
|
137
|
+
const normalizedLevel = level.toLowerCase();
|
|
138
|
+
switch (normalizedLevel) {
|
|
139
|
+
// Legacy format: ReadOnly, New format: view
|
|
140
|
+
case "readonly":
|
|
141
|
+
case "view":
|
|
142
|
+
return {
|
|
143
|
+
canView: true,
|
|
144
|
+
canAdminView: false,
|
|
145
|
+
canEdit: false,
|
|
146
|
+
canCreate: false,
|
|
147
|
+
canDelete: false,
|
|
148
|
+
canShare: false,
|
|
149
|
+
permissionLevel: "ReadOnly",
|
|
150
|
+
isLoading: false,
|
|
151
|
+
isDenied: false
|
|
152
|
+
};
|
|
153
|
+
// Legacy format: AdminReadOnly (no new equivalent, keep for backwards compatibility)
|
|
154
|
+
case "adminreadonly":
|
|
155
|
+
return {
|
|
156
|
+
canView: true,
|
|
157
|
+
canAdminView: true,
|
|
158
|
+
canEdit: false,
|
|
159
|
+
canCreate: false,
|
|
160
|
+
canDelete: false,
|
|
161
|
+
canShare: false,
|
|
162
|
+
permissionLevel: "AdminReadOnly",
|
|
163
|
+
isLoading: false,
|
|
164
|
+
isDenied: false
|
|
165
|
+
};
|
|
166
|
+
// Legacy format: ReadWrite, New format: edit
|
|
167
|
+
case "readwrite":
|
|
168
|
+
case "edit":
|
|
169
|
+
return {
|
|
170
|
+
canView: true,
|
|
171
|
+
canAdminView: false,
|
|
172
|
+
canEdit: true,
|
|
173
|
+
canCreate: true,
|
|
174
|
+
canDelete: false,
|
|
175
|
+
canShare: false,
|
|
176
|
+
permissionLevel: "ReadWrite",
|
|
177
|
+
isLoading: false,
|
|
178
|
+
isDenied: false
|
|
179
|
+
};
|
|
180
|
+
// Legacy format: Admin, New format: admin
|
|
181
|
+
case "admin":
|
|
182
|
+
return {
|
|
183
|
+
canView: true,
|
|
184
|
+
canAdminView: true,
|
|
185
|
+
canEdit: true,
|
|
186
|
+
canCreate: true,
|
|
187
|
+
canDelete: true,
|
|
188
|
+
canShare: true,
|
|
189
|
+
permissionLevel: "Admin",
|
|
190
|
+
isLoading: false,
|
|
191
|
+
isDenied: false
|
|
192
|
+
};
|
|
193
|
+
// New format: denied - explicit access denial
|
|
194
|
+
case "denied":
|
|
195
|
+
return deniedPermission;
|
|
196
|
+
default:
|
|
197
|
+
console.warn(`Unknown permission level: ${level}`);
|
|
198
|
+
return noPermission;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
var permissionContext = createContext2({});
|
|
202
|
+
var entityPermissionContext = permissionContext;
|
|
203
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
204
|
+
var ERROR_CACHE_TTL_MS = 30 * 1e3;
|
|
205
|
+
var BATCH_DELAY_MS = 50;
|
|
206
|
+
function PermissionProvider({
|
|
207
|
+
children
|
|
208
|
+
}) {
|
|
209
|
+
const supabase = useSupabase();
|
|
210
|
+
const setupAuth = useContext(setupAuthContext);
|
|
211
|
+
const user = setupAuth?.user;
|
|
212
|
+
const cacheRef = useRef2(/* @__PURE__ */ new Map());
|
|
213
|
+
const pendingLookupsRef = useRef2(/* @__PURE__ */ new Set());
|
|
214
|
+
const inFlightRef = useRef2(/* @__PURE__ */ new Set());
|
|
215
|
+
const batchTimerRef = useRef2(null);
|
|
216
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
217
|
+
const [, forceUpdate] = useState(0);
|
|
218
|
+
const cleanupExpiredEntries = useCallback(() => {
|
|
219
|
+
const now = Date.now();
|
|
220
|
+
const cache = cacheRef.current;
|
|
221
|
+
let hasExpired = false;
|
|
222
|
+
for (const [key, entry] of cache.entries()) {
|
|
223
|
+
if (entry.expiresAt < now) {
|
|
224
|
+
cache.delete(key);
|
|
225
|
+
hasExpired = true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (hasExpired) {
|
|
229
|
+
forceUpdate((prev) => prev + 1);
|
|
230
|
+
}
|
|
231
|
+
}, []);
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
const cleanupInterval = setInterval(cleanupExpiredEntries, 60 * 1e3);
|
|
234
|
+
return () => clearInterval(cleanupInterval);
|
|
235
|
+
}, [cleanupExpiredEntries]);
|
|
236
|
+
const executeBatchLookup = useCallback(async () => {
|
|
237
|
+
const pending = Array.from(pendingLookupsRef.current);
|
|
238
|
+
pendingLookupsRef.current.clear();
|
|
239
|
+
if (pending.length === 0 || !user?.id) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
pending.forEach((k) => inFlightRef.current.add(k));
|
|
243
|
+
setIsLoading(true);
|
|
244
|
+
try {
|
|
245
|
+
const entities = pending.map((key_0) => {
|
|
246
|
+
const parts = key_0.split(":");
|
|
247
|
+
const entityType = parts[1];
|
|
248
|
+
const entityIdStr = parts[2];
|
|
249
|
+
return {
|
|
250
|
+
entity_type: entityType,
|
|
251
|
+
entity_id: parseInt(entityIdStr, 10)
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
const {
|
|
255
|
+
data,
|
|
256
|
+
error
|
|
257
|
+
} = await supabase.rpc("get_user_entity_permissions", {
|
|
258
|
+
p_user_id: user.id,
|
|
259
|
+
p_entities: entities
|
|
260
|
+
});
|
|
261
|
+
if (error) {
|
|
262
|
+
console.error("Failed to fetch entity permissions:", error);
|
|
263
|
+
const cache_0 = cacheRef.current;
|
|
264
|
+
const now_0 = Date.now();
|
|
265
|
+
for (const key_1 of pending) {
|
|
266
|
+
cache_0.set(key_1, {
|
|
267
|
+
permission: noPermission,
|
|
268
|
+
expiresAt: now_0 + ERROR_CACHE_TTL_MS
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
} else if (data) {
|
|
272
|
+
const cache_1 = cacheRef.current;
|
|
273
|
+
const now_1 = Date.now();
|
|
274
|
+
const resultsMap = /* @__PURE__ */ new Map();
|
|
275
|
+
const results = data;
|
|
276
|
+
for (const result of results) {
|
|
277
|
+
const key_2 = getCacheKey(user?.id, result.entity_type, result.entity_id);
|
|
278
|
+
resultsMap.set(key_2, result.permission);
|
|
279
|
+
}
|
|
280
|
+
for (const key_3 of pending) {
|
|
281
|
+
const permissionLevel = resultsMap.get(key_3) || null;
|
|
282
|
+
cache_1.set(key_3, {
|
|
283
|
+
permission: mapPermissionLevel(permissionLevel),
|
|
284
|
+
expiresAt: now_1 + CACHE_TTL_MS
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
forceUpdate((prev_0) => prev_0 + 1);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
console.error("Unexpected error fetching entity permissions:", err);
|
|
291
|
+
} finally {
|
|
292
|
+
pending.forEach((k) => inFlightRef.current.delete(k));
|
|
293
|
+
setIsLoading(false);
|
|
294
|
+
}
|
|
295
|
+
}, [supabase, user?.id]);
|
|
296
|
+
const scheduleBatchLookup = useCallback(() => {
|
|
297
|
+
if (batchTimerRef.current) {
|
|
298
|
+
clearTimeout(batchTimerRef.current);
|
|
299
|
+
}
|
|
300
|
+
batchTimerRef.current = setTimeout(() => {
|
|
301
|
+
batchTimerRef.current = null;
|
|
302
|
+
executeBatchLookup();
|
|
303
|
+
}, BATCH_DELAY_MS);
|
|
304
|
+
}, [executeBatchLookup]);
|
|
305
|
+
const getPermission = useCallback((entityType_0, entityId) => {
|
|
306
|
+
const key_4 = getCacheKey(user?.id, entityType_0, entityId);
|
|
307
|
+
const cache_2 = cacheRef.current;
|
|
308
|
+
const cached = cache_2.get(key_4);
|
|
309
|
+
const now_2 = Date.now();
|
|
310
|
+
if (cached && cached.expiresAt > now_2) {
|
|
311
|
+
return cached.permission;
|
|
312
|
+
}
|
|
313
|
+
if (!pendingLookupsRef.current.has(key_4) && !inFlightRef.current.has(key_4)) {
|
|
314
|
+
pendingLookupsRef.current.add(key_4);
|
|
315
|
+
scheduleBatchLookup();
|
|
316
|
+
}
|
|
317
|
+
return loadingPermission;
|
|
318
|
+
}, [scheduleBatchLookup, user?.id]);
|
|
319
|
+
const checkPermission = useCallback((entityType_1, entityId_0, action) => {
|
|
320
|
+
const permission = getPermission(entityType_1, entityId_0);
|
|
321
|
+
if (permission.isLoading) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
switch (action) {
|
|
325
|
+
case "view":
|
|
326
|
+
return permission.canView;
|
|
327
|
+
case "adminView":
|
|
328
|
+
return permission.canAdminView;
|
|
329
|
+
case "edit":
|
|
330
|
+
return permission.canEdit;
|
|
331
|
+
case "create":
|
|
332
|
+
return permission.canCreate;
|
|
333
|
+
case "delete":
|
|
334
|
+
return permission.canDelete;
|
|
335
|
+
case "share":
|
|
336
|
+
return permission.canShare;
|
|
337
|
+
default:
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
}, [getPermission]);
|
|
341
|
+
const prefetchPermissions = useCallback(async (entities_0) => {
|
|
342
|
+
if (!user?.id || entities_0.length === 0) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const cache_3 = cacheRef.current;
|
|
346
|
+
const now_3 = Date.now();
|
|
347
|
+
const toFetch = entities_0.filter((entity) => {
|
|
348
|
+
const key_5 = getCacheKey(user?.id, entity.entityType, entity.entityId);
|
|
349
|
+
const cached_0 = cache_3.get(key_5);
|
|
350
|
+
const isPending = pendingLookupsRef.current.has(key_5);
|
|
351
|
+
const isInFlight = inFlightRef.current.has(key_5);
|
|
352
|
+
return !isPending && !isInFlight && (!cached_0 || cached_0.expiresAt <= now_3);
|
|
353
|
+
});
|
|
354
|
+
if (toFetch.length === 0) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
setIsLoading(true);
|
|
358
|
+
try {
|
|
359
|
+
const entitiesParam = toFetch.map((e) => ({
|
|
360
|
+
entity_type: e.entityType,
|
|
361
|
+
entity_id: e.entityId
|
|
362
|
+
}));
|
|
363
|
+
const {
|
|
364
|
+
data: data_0,
|
|
365
|
+
error: error_0
|
|
366
|
+
} = await supabase.rpc("get_user_entity_permissions", {
|
|
367
|
+
p_user_id: user.id,
|
|
368
|
+
p_entities: entitiesParam
|
|
369
|
+
});
|
|
370
|
+
if (error_0) {
|
|
371
|
+
console.error("Failed to prefetch entity permissions:", error_0);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (data_0) {
|
|
375
|
+
const cacheTimestamp = Date.now();
|
|
376
|
+
const resultsMap_0 = /* @__PURE__ */ new Map();
|
|
377
|
+
const results_0 = data_0;
|
|
378
|
+
for (const result_0 of results_0) {
|
|
379
|
+
const key_6 = getCacheKey(user?.id, result_0.entity_type, result_0.entity_id);
|
|
380
|
+
resultsMap_0.set(key_6, result_0.permission);
|
|
381
|
+
}
|
|
382
|
+
for (const entity_0 of toFetch) {
|
|
383
|
+
const key_7 = getCacheKey(user?.id, entity_0.entityType, entity_0.entityId);
|
|
384
|
+
const permissionLevel_0 = resultsMap_0.get(key_7) || null;
|
|
385
|
+
cache_3.set(key_7, {
|
|
386
|
+
permission: mapPermissionLevel(permissionLevel_0),
|
|
387
|
+
expiresAt: cacheTimestamp + CACHE_TTL_MS
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
forceUpdate((prev_1) => prev_1 + 1);
|
|
391
|
+
}
|
|
392
|
+
} catch (err_0) {
|
|
393
|
+
console.error("Unexpected error prefetching entity permissions:", err_0);
|
|
394
|
+
} finally {
|
|
395
|
+
setIsLoading(false);
|
|
396
|
+
}
|
|
397
|
+
}, [supabase, user?.id]);
|
|
398
|
+
const invalidatePermission = useCallback((entityType_2, entityId_1) => {
|
|
399
|
+
const key_8 = getCacheKey(user?.id, entityType_2, entityId_1);
|
|
400
|
+
cacheRef.current.delete(key_8);
|
|
401
|
+
forceUpdate((prev_2) => prev_2 + 1);
|
|
402
|
+
}, [user?.id]);
|
|
403
|
+
const parseScopedAccessKey = useCallback((key_9) => {
|
|
404
|
+
if (!key_9 || typeof key_9 !== "string") {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
const parts_0 = key_9.split(":");
|
|
408
|
+
if (parts_0.length < 2) {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
const entityType_3 = parts_0[0];
|
|
412
|
+
const entityId_2 = parseInt(parts_0[1], 10);
|
|
413
|
+
if (isNaN(entityId_2)) {
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
const entityTypeMap = {
|
|
417
|
+
client: "Client",
|
|
418
|
+
project: "Project",
|
|
419
|
+
database: "ProjectDatabase",
|
|
420
|
+
projectdatabase: "ProjectDatabase"
|
|
421
|
+
};
|
|
422
|
+
const normalizedEntityType = entityTypeMap[entityType_3.toLowerCase()];
|
|
423
|
+
if (!normalizedEntityType) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
entityType: normalizedEntityType,
|
|
428
|
+
entityId: entityId_2
|
|
429
|
+
};
|
|
430
|
+
}, []);
|
|
431
|
+
useEffect(() => {
|
|
432
|
+
if (!user?.id) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const channel = supabase.channel(`entity-permissions-${user.id}`).on("postgres_changes", {
|
|
436
|
+
event: "*",
|
|
437
|
+
schema: "core",
|
|
438
|
+
table: "UserAccess",
|
|
439
|
+
filter: `userId=eq.${user.id}`
|
|
440
|
+
}, (payload) => {
|
|
441
|
+
if (payload.new && typeof payload.new === "object" && "scopedAccessKey" in payload.new && typeof payload.new.scopedAccessKey === "string") {
|
|
442
|
+
const parsed = parseScopedAccessKey(payload.new.scopedAccessKey);
|
|
443
|
+
if (parsed) {
|
|
444
|
+
invalidatePermission(parsed.entityType, parsed.entityId);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (payload.old && typeof payload.old === "object" && "scopedAccessKey" in payload.old && typeof payload.old.scopedAccessKey === "string") {
|
|
448
|
+
const parsed_0 = parseScopedAccessKey(payload.old.scopedAccessKey);
|
|
449
|
+
if (parsed_0) {
|
|
450
|
+
invalidatePermission(parsed_0.entityType, parsed_0.entityId);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}).subscribe();
|
|
454
|
+
return () => {
|
|
455
|
+
channel.unsubscribe();
|
|
456
|
+
supabase.removeChannel(channel);
|
|
457
|
+
};
|
|
458
|
+
}, [supabase, user?.id, invalidatePermission, parseScopedAccessKey]);
|
|
459
|
+
useEffect(() => {
|
|
460
|
+
cacheRef.current.clear();
|
|
461
|
+
pendingLookupsRef.current.clear();
|
|
462
|
+
inFlightRef.current.clear();
|
|
463
|
+
if (batchTimerRef.current) {
|
|
464
|
+
clearTimeout(batchTimerRef.current);
|
|
465
|
+
batchTimerRef.current = null;
|
|
466
|
+
}
|
|
467
|
+
forceUpdate((prev_3) => prev_3 + 1);
|
|
468
|
+
}, [user?.id]);
|
|
469
|
+
useEffect(() => {
|
|
470
|
+
return () => {
|
|
471
|
+
if (batchTimerRef.current) {
|
|
472
|
+
clearTimeout(batchTimerRef.current);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
}, []);
|
|
476
|
+
const value = useMemo2(() => ({
|
|
477
|
+
getPermission,
|
|
478
|
+
checkPermission,
|
|
479
|
+
prefetchPermissions,
|
|
480
|
+
invalidatePermission,
|
|
481
|
+
isLoading
|
|
482
|
+
}), [getPermission, checkPermission, prefetchPermissions, invalidatePermission, isLoading]);
|
|
483
|
+
return /* @__PURE__ */ jsx2(permissionContext.Provider, { value, children });
|
|
484
|
+
}
|
|
485
|
+
function usePermissions() {
|
|
486
|
+
const context = useContext(permissionContext);
|
|
487
|
+
if (!context || Object.keys(context).length === 0) {
|
|
488
|
+
throw new Error("usePermissions must be used within a PermissionProvider");
|
|
489
|
+
}
|
|
490
|
+
return context;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// src/auth/context/AuthProvider.tsx
|
|
494
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef3, useState as useState2 } from "react";
|
|
495
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
496
|
+
var profileQuery = typedSupabase?.schema("core").from("Profile").select("*, UserAccess(accessKey), status").single();
|
|
497
|
+
function AuthProvider({
|
|
498
|
+
children,
|
|
499
|
+
enableEntityPermissions = false
|
|
500
|
+
}) {
|
|
501
|
+
const supabase = useSupabase();
|
|
502
|
+
const [currentUser, setCurrentUser] = useState2(void 0);
|
|
503
|
+
const [userNeedsChange, setUserNeedsChange] = useState2(true);
|
|
504
|
+
const [onSignOutCallbacks, setOnSignOutCallbacks] = useState2(/* @__PURE__ */ new Map());
|
|
505
|
+
async function registerAsync(register) {
|
|
506
|
+
const response = await supabase.auth.signUp(register);
|
|
507
|
+
setCurrentUser(response.data.user);
|
|
508
|
+
return response;
|
|
509
|
+
}
|
|
510
|
+
async function signInAsync(username, password) {
|
|
511
|
+
const response_0 = await supabase.auth.signInWithPassword({
|
|
512
|
+
email: username,
|
|
513
|
+
password
|
|
514
|
+
});
|
|
515
|
+
if (response_0.data) {
|
|
516
|
+
setCurrentUser(response_0.data.user);
|
|
517
|
+
}
|
|
518
|
+
return response_0;
|
|
519
|
+
}
|
|
520
|
+
async function signOutAsync() {
|
|
521
|
+
const response_1 = await supabase.auth.signOut();
|
|
522
|
+
if (isUsable(response_1.error) === false) {
|
|
523
|
+
Array.from(onSignOutCallbacks.values()).forEach((x) => {
|
|
524
|
+
x();
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
return response_1;
|
|
528
|
+
}
|
|
529
|
+
function onSignOut(action) {
|
|
530
|
+
const id = newUuid();
|
|
531
|
+
setOnSignOutCallbacks((x_0) => new Map(x_0).set(id, action));
|
|
532
|
+
return id;
|
|
533
|
+
}
|
|
534
|
+
function removeOnSignOut(id_0) {
|
|
535
|
+
setOnSignOutCallbacks((x_1) => {
|
|
536
|
+
const map = new Map(x_1);
|
|
537
|
+
map.delete(id_0);
|
|
538
|
+
return map;
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
async function refreshAsync() {
|
|
542
|
+
}
|
|
543
|
+
useEffect2(() => {
|
|
544
|
+
const request = supabase.auth.onAuthStateChange((event) => {
|
|
545
|
+
if (event === "SIGNED_IN" || event === "SIGNED_OUT") {
|
|
546
|
+
setUserNeedsChange(true);
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
return () => {
|
|
550
|
+
request.data.subscription.unsubscribe();
|
|
551
|
+
};
|
|
552
|
+
}, [supabase.auth]);
|
|
553
|
+
useEffect2(() => {
|
|
554
|
+
if (userNeedsChange === false) return;
|
|
555
|
+
supabase.auth.getSession().then((x_2) => {
|
|
556
|
+
setCurrentUser(x_2?.data?.session?.user ?? null);
|
|
557
|
+
setUserNeedsChange(false);
|
|
558
|
+
});
|
|
559
|
+
}, [userNeedsChange]);
|
|
560
|
+
const profileRequest = useDbQuery(supabase.schema("core").from("Profile").select("*, UserAccess(accessKey), status").eq("id", currentUser?.id).limit(1).maybeSingle(), {
|
|
561
|
+
enabled: isUsable(currentUser),
|
|
562
|
+
crossOrganization: true
|
|
563
|
+
});
|
|
564
|
+
const accessKeysRequest = useDbQuery(supabase.schema("core").rpc("get_user_access_keys", {
|
|
565
|
+
user_id: currentUser?.id
|
|
566
|
+
}), {
|
|
567
|
+
enabled: isUsable(currentUser),
|
|
568
|
+
crossOrganization: true
|
|
569
|
+
});
|
|
570
|
+
const refetchAccessKeys = useCallback2(() => {
|
|
571
|
+
accessKeysRequest.refetch();
|
|
572
|
+
}, [accessKeysRequest.refetch]);
|
|
573
|
+
const userGroupIdsRef = useRef3(/* @__PURE__ */ new Set());
|
|
574
|
+
useEffect2(() => {
|
|
575
|
+
if (accessKeysRequest.data) {
|
|
576
|
+
const groupIds = /* @__PURE__ */ new Set();
|
|
577
|
+
for (const item of accessKeysRequest.data) {
|
|
578
|
+
if (item.source === "group" && item.source_id) {
|
|
579
|
+
groupIds.add(item.source_id);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
userGroupIdsRef.current = groupIds;
|
|
583
|
+
}
|
|
584
|
+
}, [accessKeysRequest.data]);
|
|
585
|
+
useEffect2(() => {
|
|
586
|
+
if (!currentUser?.id) return;
|
|
587
|
+
const channel = supabase.channel(`user-access-keys-${currentUser.id}`).on("postgres_changes", {
|
|
588
|
+
event: "*",
|
|
589
|
+
schema: "core",
|
|
590
|
+
table: "UserAccess",
|
|
591
|
+
filter: `userId=eq.${currentUser.id}`
|
|
592
|
+
}, () => {
|
|
593
|
+
refetchAccessKeys();
|
|
594
|
+
}).on("postgres_changes", {
|
|
595
|
+
event: "*",
|
|
596
|
+
schema: "core",
|
|
597
|
+
table: "UserGroup",
|
|
598
|
+
filter: `userId=eq.${currentUser.id}`
|
|
599
|
+
}, () => {
|
|
600
|
+
refetchAccessKeys();
|
|
601
|
+
}).on("postgres_changes", {
|
|
602
|
+
event: "*",
|
|
603
|
+
schema: "core",
|
|
604
|
+
table: "GroupAccessKey"
|
|
605
|
+
}, (payload) => {
|
|
606
|
+
const groupId = payload.new?.groupId || payload.old?.groupId;
|
|
607
|
+
if (groupId && userGroupIdsRef.current.has(groupId)) {
|
|
608
|
+
refetchAccessKeys();
|
|
609
|
+
}
|
|
610
|
+
}).on("postgres_changes", {
|
|
611
|
+
event: "UPDATE",
|
|
612
|
+
schema: "core",
|
|
613
|
+
table: "Group"
|
|
614
|
+
}, (payload_0) => {
|
|
615
|
+
const oldActive = payload_0.old?.isActive;
|
|
616
|
+
const newActive = payload_0.new?.isActive;
|
|
617
|
+
const groupId_0 = payload_0.new?.id;
|
|
618
|
+
if (oldActive !== newActive && groupId_0 && userGroupIdsRef.current.has(groupId_0)) {
|
|
619
|
+
refetchAccessKeys();
|
|
620
|
+
}
|
|
621
|
+
}).subscribe();
|
|
622
|
+
return () => {
|
|
623
|
+
channel.unsubscribe();
|
|
624
|
+
supabase.removeChannel(channel);
|
|
625
|
+
};
|
|
626
|
+
}, [supabase, currentUser?.id, refetchAccessKeys]);
|
|
627
|
+
useEffect2(() => {
|
|
628
|
+
if (!currentUser?.id) return;
|
|
629
|
+
const profileChannel = supabase.channel(`profile-status-${currentUser.id}`).on("postgres_changes", {
|
|
630
|
+
event: "UPDATE",
|
|
631
|
+
schema: "core",
|
|
632
|
+
table: "Profile",
|
|
633
|
+
filter: `id=eq.${currentUser.id}`
|
|
634
|
+
}, (payload_1) => {
|
|
635
|
+
const newStatus = payload_1.new?.status;
|
|
636
|
+
const oldStatus = payload_1.old?.status;
|
|
637
|
+
if (oldStatus === "active" && (newStatus === "archived" || newStatus === "suspended")) {
|
|
638
|
+
signOutAsync();
|
|
639
|
+
}
|
|
640
|
+
profileRequest.refetch();
|
|
641
|
+
}).subscribe();
|
|
642
|
+
return () => {
|
|
643
|
+
profileChannel.unsubscribe();
|
|
644
|
+
supabase.removeChannel(profileChannel);
|
|
645
|
+
};
|
|
646
|
+
}, [supabase, currentUser?.id, profileRequest.refetch]);
|
|
647
|
+
const combinedAccess = useMemo3(() => {
|
|
648
|
+
if (accessKeysRequest.data) {
|
|
649
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
650
|
+
for (const item_0 of accessKeysRequest.data) {
|
|
651
|
+
if (item_0.access_key) {
|
|
652
|
+
uniqueKeys.add(item_0.access_key);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return Array.from(uniqueKeys);
|
|
656
|
+
}
|
|
657
|
+
return profileRequest.data?.UserAccess?.map((x_3) => x_3.accessKey) || [];
|
|
658
|
+
}, [accessKeysRequest.data, profileRequest.data?.UserAccess]);
|
|
659
|
+
const profileStatus = profileRequest.data?.status;
|
|
660
|
+
const isArchived = profileStatus === "archived";
|
|
661
|
+
const isSuspended = profileStatus === "suspended";
|
|
662
|
+
const hasAccess = useCallback2((key) => {
|
|
663
|
+
if (isArchived || isSuspended) {
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
const accessGiven = combinedAccess;
|
|
667
|
+
if (isUsable(accessGiven) === false) return false;
|
|
668
|
+
if (accessGiven.includes("owner")) return true;
|
|
669
|
+
if (accessGiven.includes(key)) return true;
|
|
670
|
+
if (isUsable(key) === false) return true;
|
|
671
|
+
return false;
|
|
672
|
+
}, [combinedAccess, isArchived, isSuspended]);
|
|
673
|
+
const authStateWithLoading = useMemo3(() => ({
|
|
674
|
+
hasAccess,
|
|
675
|
+
user: currentUser,
|
|
676
|
+
profile: profileRequest.data,
|
|
677
|
+
access: combinedAccess,
|
|
678
|
+
profileStatus,
|
|
679
|
+
isArchived,
|
|
680
|
+
isSuspended,
|
|
681
|
+
isLoading: currentUser === null ? false : profileRequest.isLoading || accessKeysRequest.isLoading || currentUser === void 0,
|
|
682
|
+
signInAsync,
|
|
683
|
+
signOutAsync,
|
|
684
|
+
onSignOut,
|
|
685
|
+
removeOnSignOut,
|
|
686
|
+
registerAsync,
|
|
687
|
+
refreshAsync
|
|
688
|
+
}), [profileRequest.data, profileRequest.isLoading, accessKeysRequest.data, accessKeysRequest.isLoading, currentUser, combinedAccess, profileStatus, isArchived, isSuspended, hasAccess]);
|
|
689
|
+
const content = enableEntityPermissions ? /* @__PURE__ */ jsx3(PermissionProvider, { children }) : children;
|
|
690
|
+
return /* @__PURE__ */ jsx3(setupAuthContext.Provider, { value: authStateWithLoading, children: content });
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// src/auth/context/UserMetadataContext.tsx
|
|
694
|
+
import { c as _c2 } from "react/compiler-runtime";
|
|
695
|
+
import { createContext as createContext3, useContext as useContext2, useEffect as useEffect3, useMemo as useMemo4, useState as useState3, useCallback as useCallback3, useRef as useRef4 } from "react";
|
|
696
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
697
|
+
var UserMetadataQuery = {
|
|
698
|
+
schema: "core",
|
|
699
|
+
table: "UserMetadata",
|
|
700
|
+
defaultQuery: "key, userId, value"
|
|
701
|
+
};
|
|
702
|
+
var userMetadataContext = createContext3(null);
|
|
703
|
+
function UserMetadataProvider({
|
|
704
|
+
children
|
|
705
|
+
}) {
|
|
706
|
+
const supabase = useSupabase();
|
|
707
|
+
const [metadata, setMetadataState] = useState3({});
|
|
708
|
+
const [isLoading, setIsLoading] = useState3(true);
|
|
709
|
+
const [error, setError] = useState3(null);
|
|
710
|
+
const setupAuth = useContext2(setupAuthContext);
|
|
711
|
+
const userId = setupAuth?.user?.id;
|
|
712
|
+
const metadataQuery = useDbQuery(supabase.schema("core").from("UserMetadata").select(UserMetadataQuery.defaultQuery).eq("userId", userId).order("key"), {
|
|
713
|
+
enabled: isUsable(userId),
|
|
714
|
+
crossOrganization: true
|
|
715
|
+
});
|
|
716
|
+
const upsertMutation = useDbUpsert("UserMetadata", {
|
|
717
|
+
invalidateTables: ["UserMetadata"]
|
|
718
|
+
});
|
|
719
|
+
const upsertMutationRef = useRef4(upsertMutation);
|
|
720
|
+
upsertMutationRef.current = upsertMutation;
|
|
721
|
+
useEffect3(() => {
|
|
722
|
+
if (metadataQuery.data) {
|
|
723
|
+
const metadataMap = {};
|
|
724
|
+
metadataQuery.data.forEach((item) => {
|
|
725
|
+
metadataMap[item.key] = item.value;
|
|
726
|
+
});
|
|
727
|
+
setMetadataState(metadataMap);
|
|
728
|
+
setIsLoading(false);
|
|
729
|
+
setError(null);
|
|
730
|
+
} else if (metadataQuery.error) {
|
|
731
|
+
setError(metadataQuery.error);
|
|
732
|
+
setIsLoading(false);
|
|
733
|
+
} else if (metadataQuery.isLoading) {
|
|
734
|
+
setIsLoading(true);
|
|
735
|
+
}
|
|
736
|
+
}, [metadataQuery.data, metadataQuery.error, metadataQuery.isLoading]);
|
|
737
|
+
const setMetadata = useCallback3(async (key, value) => {
|
|
738
|
+
if (!userId) {
|
|
739
|
+
throw new Error("User not authenticated");
|
|
740
|
+
}
|
|
741
|
+
try {
|
|
742
|
+
await upsertMutationRef.current.mutateAsync({
|
|
743
|
+
userId,
|
|
744
|
+
key,
|
|
745
|
+
value
|
|
746
|
+
});
|
|
747
|
+
setMetadataState((prev) => ({
|
|
748
|
+
...prev,
|
|
749
|
+
[key]: value
|
|
750
|
+
}));
|
|
751
|
+
} catch (err) {
|
|
752
|
+
setError(err);
|
|
753
|
+
throw err;
|
|
754
|
+
}
|
|
755
|
+
}, [userId]);
|
|
756
|
+
const getMetadata = useCallback3((key_0) => {
|
|
757
|
+
return metadata[key_0];
|
|
758
|
+
}, [metadata]);
|
|
759
|
+
const removeMetadata = useCallback3(async (key_1) => {
|
|
760
|
+
if (!userId) {
|
|
761
|
+
throw new Error("User not authenticated");
|
|
762
|
+
}
|
|
763
|
+
try {
|
|
764
|
+
await supabase.schema("core").from("UserMetadata").delete().eq("userId", userId).eq("key", key_1);
|
|
765
|
+
setMetadataState((prev_0) => {
|
|
766
|
+
const newState = {
|
|
767
|
+
...prev_0
|
|
768
|
+
};
|
|
769
|
+
delete newState[key_1];
|
|
770
|
+
return newState;
|
|
771
|
+
});
|
|
772
|
+
} catch (err_0) {
|
|
773
|
+
setError(err_0);
|
|
774
|
+
throw err_0;
|
|
775
|
+
}
|
|
776
|
+
}, [userId, supabase]);
|
|
777
|
+
const refreshMetadata = useCallback3(async () => {
|
|
778
|
+
await metadataQuery.refetch();
|
|
779
|
+
}, [metadataQuery]);
|
|
780
|
+
const contextValue = useMemo4(() => ({
|
|
781
|
+
metadata,
|
|
782
|
+
isLoading,
|
|
783
|
+
error,
|
|
784
|
+
setMetadata,
|
|
785
|
+
getMetadata,
|
|
786
|
+
removeMetadata,
|
|
787
|
+
refreshMetadata
|
|
788
|
+
}), [metadata, isLoading, error, setMetadata, getMetadata, removeMetadata, refreshMetadata]);
|
|
789
|
+
return /* @__PURE__ */ jsx4(userMetadataContext.Provider, { value: contextValue, children });
|
|
790
|
+
}
|
|
791
|
+
function useUserMetadata() {
|
|
792
|
+
const context = useContext2(userMetadataContext);
|
|
793
|
+
if (!context) {
|
|
794
|
+
throw new Error("useUserMetadata must be used within a UserMetadataProvider");
|
|
795
|
+
}
|
|
796
|
+
return context;
|
|
797
|
+
}
|
|
798
|
+
function useUserMetadataValue(key) {
|
|
799
|
+
const $ = _c2(3);
|
|
800
|
+
const {
|
|
801
|
+
getMetadata
|
|
802
|
+
} = useUserMetadata();
|
|
803
|
+
let t0;
|
|
804
|
+
if ($[0] !== getMetadata || $[1] !== key) {
|
|
805
|
+
t0 = getMetadata(key);
|
|
806
|
+
$[0] = getMetadata;
|
|
807
|
+
$[1] = key;
|
|
808
|
+
$[2] = t0;
|
|
809
|
+
} else {
|
|
810
|
+
t0 = $[2];
|
|
811
|
+
}
|
|
812
|
+
return t0;
|
|
813
|
+
}
|
|
814
|
+
function useSetUserMetadata() {
|
|
815
|
+
const $ = _c2(3);
|
|
816
|
+
const {
|
|
817
|
+
setMetadata,
|
|
818
|
+
removeMetadata
|
|
819
|
+
} = useUserMetadata();
|
|
820
|
+
let t0;
|
|
821
|
+
if ($[0] !== removeMetadata || $[1] !== setMetadata) {
|
|
822
|
+
t0 = {
|
|
823
|
+
setMetadata,
|
|
824
|
+
removeMetadata
|
|
825
|
+
};
|
|
826
|
+
$[0] = removeMetadata;
|
|
827
|
+
$[1] = setMetadata;
|
|
828
|
+
$[2] = t0;
|
|
829
|
+
} else {
|
|
830
|
+
t0 = $[2];
|
|
831
|
+
}
|
|
832
|
+
return t0;
|
|
833
|
+
}
|
|
834
|
+
function useUserMetadataState(key, defaultValue, options) {
|
|
835
|
+
const $ = _c2(11);
|
|
836
|
+
const {
|
|
837
|
+
metadata,
|
|
838
|
+
setMetadata,
|
|
839
|
+
isLoading
|
|
840
|
+
} = useUserMetadata();
|
|
841
|
+
const serialize = options?.serialize ?? _temp;
|
|
842
|
+
const deserialize = options?.deserialize ?? _temp2;
|
|
843
|
+
let t0;
|
|
844
|
+
bb0: {
|
|
845
|
+
const rawValue = metadata[key];
|
|
846
|
+
if (!rawValue) {
|
|
847
|
+
t0 = defaultValue;
|
|
848
|
+
break bb0;
|
|
849
|
+
}
|
|
850
|
+
;
|
|
851
|
+
try {
|
|
852
|
+
let t22;
|
|
853
|
+
if ($[0] !== deserialize || $[1] !== rawValue) {
|
|
854
|
+
t22 = deserialize(rawValue);
|
|
855
|
+
$[0] = deserialize;
|
|
856
|
+
$[1] = rawValue;
|
|
857
|
+
$[2] = t22;
|
|
858
|
+
} else {
|
|
859
|
+
t22 = $[2];
|
|
860
|
+
}
|
|
861
|
+
t0 = t22;
|
|
862
|
+
} catch (t12) {
|
|
863
|
+
const error = t12;
|
|
864
|
+
console.warn(`Failed to deserialize metadata for key "${key}":`, error);
|
|
865
|
+
t0 = defaultValue;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
const currentValue = t0;
|
|
869
|
+
let t1;
|
|
870
|
+
if ($[3] !== key || $[4] !== serialize || $[5] !== setMetadata) {
|
|
871
|
+
t1 = async (value_1) => {
|
|
872
|
+
const serializedValue = serialize(value_1);
|
|
873
|
+
await setMetadata(key, serializedValue);
|
|
874
|
+
};
|
|
875
|
+
$[3] = key;
|
|
876
|
+
$[4] = serialize;
|
|
877
|
+
$[5] = setMetadata;
|
|
878
|
+
$[6] = t1;
|
|
879
|
+
} else {
|
|
880
|
+
t1 = $[6];
|
|
881
|
+
}
|
|
882
|
+
const setValue = t1;
|
|
883
|
+
let t2;
|
|
884
|
+
if ($[7] !== currentValue || $[8] !== isLoading || $[9] !== setValue) {
|
|
885
|
+
t2 = [currentValue, setValue, isLoading];
|
|
886
|
+
$[7] = currentValue;
|
|
887
|
+
$[8] = isLoading;
|
|
888
|
+
$[9] = setValue;
|
|
889
|
+
$[10] = t2;
|
|
890
|
+
} else {
|
|
891
|
+
t2 = $[10];
|
|
892
|
+
}
|
|
893
|
+
return t2;
|
|
894
|
+
}
|
|
895
|
+
function _temp2(value_0) {
|
|
896
|
+
return JSON.parse(value_0);
|
|
897
|
+
}
|
|
898
|
+
function _temp(value) {
|
|
899
|
+
return JSON.stringify(value);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
export {
|
|
903
|
+
TIMEOUT_ERROR_MESSAGE,
|
|
904
|
+
DEFAULT_QUERY_TIMEOUT,
|
|
905
|
+
isTimeoutError,
|
|
906
|
+
useDbQuery,
|
|
907
|
+
setupAuthContext,
|
|
908
|
+
SetupAuthContextProvider,
|
|
909
|
+
permissionContext,
|
|
910
|
+
entityPermissionContext,
|
|
911
|
+
PermissionProvider,
|
|
912
|
+
usePermissions,
|
|
913
|
+
AuthProvider,
|
|
914
|
+
userMetadataContext,
|
|
915
|
+
UserMetadataProvider,
|
|
916
|
+
useUserMetadata,
|
|
917
|
+
useUserMetadataValue,
|
|
918
|
+
useSetUserMetadata,
|
|
919
|
+
useUserMetadataState
|
|
920
|
+
};
|
|
921
|
+
//# sourceMappingURL=chunk-WGDJ4IXR.js.map
|