@pol-studios/db 1.0.25 → 1.0.28

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.
Files changed (39) hide show
  1. package/dist/{DataLayerContext-BnDyYvkg.d.ts → DataLayerContext-Dc7nF2IG.d.ts} +1 -1
  2. package/dist/auth/context.js +2 -2
  3. package/dist/auth/hooks.js +3 -3
  4. package/dist/auth/index.js +3 -3
  5. package/dist/{chunk-U4NPP76X.js → chunk-3LPQFO2S.js} +4 -4
  6. package/dist/{chunk-DJWC43OA.js → chunk-66AGXIV5.js} +4 -4
  7. package/dist/{chunk-PZLVL7DU.js → chunk-7ANPMUR5.js} +33 -7
  8. package/dist/chunk-7ANPMUR5.js.map +1 -0
  9. package/dist/{chunk-BXSOHOQ2.js → chunk-CNIGRBRE.js} +67 -34
  10. package/dist/chunk-CNIGRBRE.js.map +1 -0
  11. package/dist/{chunk-LVUK5USN.js → chunk-EKUDGIQZ.js} +133 -35
  12. package/dist/chunk-EKUDGIQZ.js.map +1 -0
  13. package/dist/{chunk-IZX7ZEUF.js → chunk-H5T2DJ7G.js} +2 -2
  14. package/dist/{chunk-GXMSZ5S6.js → chunk-PHNBHM7X.js} +3 -3
  15. package/dist/{executor-CB4KHyYG.d.ts → executor-Br27YZvl.d.ts} +22 -1
  16. package/dist/hooks/index.d.ts +3 -3
  17. package/dist/hooks/index.js +1 -1
  18. package/dist/{index-B6xGmPRV.d.ts → index-CYFdO0iB.d.ts} +1 -1
  19. package/dist/index.d.ts +5 -5
  20. package/dist/index.js +7 -7
  21. package/dist/index.native.d.ts +6 -6
  22. package/dist/index.native.js +7 -7
  23. package/dist/index.web.d.ts +7 -7
  24. package/dist/index.web.js +6 -6
  25. package/dist/powersync-bridge/index.d.ts +1 -1
  26. package/dist/query/index.d.ts +1 -1
  27. package/dist/query/index.js +1 -1
  28. package/dist/types/index.d.ts +3 -3
  29. package/dist/{useDbCount-Dn_1uI69.d.ts → useDbCount-Dk0yCKlT.d.ts} +1 -1
  30. package/dist/{useResolveFeedback-CBHY2Z1Q.d.ts → useResolveFeedback-C1KucfdQ.d.ts} +3 -3
  31. package/dist/with-auth/index.js +4 -4
  32. package/package.json +1 -1
  33. package/dist/chunk-BXSOHOQ2.js.map +0 -1
  34. package/dist/chunk-LVUK5USN.js.map +0 -1
  35. package/dist/chunk-PZLVL7DU.js.map +0 -1
  36. /package/dist/{chunk-U4NPP76X.js.map → chunk-3LPQFO2S.js.map} +0 -0
  37. /package/dist/{chunk-DJWC43OA.js.map → chunk-66AGXIV5.js.map} +0 -0
  38. /package/dist/{chunk-IZX7ZEUF.js.map → chunk-H5T2DJ7G.js.map} +0 -0
  39. /package/dist/{chunk-GXMSZ5S6.js.map → chunk-PHNBHM7X.js.map} +0 -0
@@ -2,7 +2,7 @@ import * as react from 'react';
2
2
  import { SupabaseClient } from '@supabase/supabase-js';
3
3
  import { QueryClient } from '@tanstack/react-query';
4
4
  import { DatabaseSchema, QueryOptions, DataLayerConfig, TableStrategy, SyncStatus, SyncControl } from './core/index.js';
5
- import { P as PowerSyncDatabase } from './executor-CB4KHyYG.js';
5
+ import { P as PowerSyncDatabase } from './executor-Br27YZvl.js';
6
6
 
7
7
  /**
8
8
  * V3 Data Layer Adapter Types
@@ -12,8 +12,8 @@ import {
12
12
  useUserMetadataState,
13
13
  useUserMetadataValue,
14
14
  userMetadataContext
15
- } from "../chunk-PZLVL7DU.js";
16
- import "../chunk-LVUK5USN.js";
15
+ } from "../chunk-7ANPMUR5.js";
16
+ import "../chunk-EKUDGIQZ.js";
17
17
  import "../chunk-GC3TBUWE.js";
18
18
  import "../chunk-J4ZVCXZ4.js";
19
19
  import "../chunk-OQ7U6EQ3.js";
@@ -11,14 +11,14 @@ import {
11
11
  usePermissionLoading,
12
12
  usePermissionsBatch,
13
13
  useSetupAuth
14
- } from "../chunk-IZX7ZEUF.js";
14
+ } from "../chunk-H5T2DJ7G.js";
15
15
  import {
16
16
  useSetUserMetadata,
17
17
  useUserMetadata,
18
18
  useUserMetadataState,
19
19
  useUserMetadataValue
20
- } from "../chunk-PZLVL7DU.js";
21
- import "../chunk-LVUK5USN.js";
20
+ } from "../chunk-7ANPMUR5.js";
21
+ import "../chunk-EKUDGIQZ.js";
22
22
  import "../chunk-GC3TBUWE.js";
23
23
  import "../chunk-J4ZVCXZ4.js";
24
24
  import "../chunk-OQ7U6EQ3.js";
@@ -12,7 +12,7 @@ import {
12
12
  usePermissionLoading,
13
13
  usePermissionsBatch,
14
14
  useSetupAuth
15
- } from "../chunk-IZX7ZEUF.js";
15
+ } from "../chunk-H5T2DJ7G.js";
16
16
  import {
17
17
  AuthProvider,
18
18
  PermissionProvider,
@@ -27,8 +27,8 @@ import {
27
27
  useUserMetadataState,
28
28
  useUserMetadataValue,
29
29
  userMetadataContext
30
- } from "../chunk-PZLVL7DU.js";
31
- import "../chunk-LVUK5USN.js";
30
+ } from "../chunk-7ANPMUR5.js";
31
+ import "../chunk-EKUDGIQZ.js";
32
32
  import {
33
33
  hasAccess,
34
34
  hasAllAccess,
@@ -3,16 +3,16 @@ import {
3
3
  createAdapterRegistry,
4
4
  createSupabaseAdapter,
5
5
  stripSchemaPrefix
6
- } from "./chunk-GXMSZ5S6.js";
6
+ } from "./chunk-PHNBHM7X.js";
7
7
  import {
8
8
  DataLayerCoreContext,
9
9
  DataLayerStatusContext
10
- } from "./chunk-LVUK5USN.js";
10
+ } from "./chunk-EKUDGIQZ.js";
11
11
  import {
12
12
  QueryExecutor,
13
13
  extractRelationNames,
14
14
  parseSelect
15
- } from "./chunk-BXSOHOQ2.js";
15
+ } from "./chunk-CNIGRBRE.js";
16
16
  import {
17
17
  useSupabase
18
18
  } from "./chunk-5EFDS7SR.js";
@@ -5187,4 +5187,4 @@ object-assign/index.js:
5187
5187
  @license MIT
5188
5188
  *)
5189
5189
  */
5190
- //# sourceMappingURL=chunk-U4NPP76X.js.map
5190
+ //# sourceMappingURL=chunk-3LPQFO2S.js.map
@@ -3,13 +3,13 @@ import {
3
3
  } from "./chunk-SM73S2DY.js";
4
4
  import {
5
5
  useSetupAuth
6
- } from "./chunk-IZX7ZEUF.js";
6
+ } from "./chunk-H5T2DJ7G.js";
7
7
  import {
8
8
  useDbQuery
9
- } from "./chunk-PZLVL7DU.js";
9
+ } from "./chunk-7ANPMUR5.js";
10
10
  import {
11
11
  useDbUpsert
12
- } from "./chunk-LVUK5USN.js";
12
+ } from "./chunk-EKUDGIQZ.js";
13
13
  import {
14
14
  delay,
15
15
  isNullOrWhitespace,
@@ -467,4 +467,4 @@ export {
467
467
  useSetUserMetadata,
468
468
  useUserMetadataState
469
469
  };
470
- //# sourceMappingURL=chunk-DJWC43OA.js.map
470
+ //# sourceMappingURL=chunk-66AGXIV5.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useDbUpsert
3
- } from "./chunk-LVUK5USN.js";
3
+ } from "./chunk-EKUDGIQZ.js";
4
4
  import {
5
5
  isUsable,
6
6
  newUuid,
@@ -501,10 +501,17 @@ function AuthProvider({
501
501
  const supabase = useSupabase();
502
502
  const [currentUser, setCurrentUser] = useState2(void 0);
503
503
  const [userNeedsChange, setUserNeedsChange] = useState2(true);
504
+ const [isAuthTransitioning, setIsAuthTransitioning] = useState2(false);
504
505
  const [onSignOutCallbacks, setOnSignOutCallbacks] = useState2(/* @__PURE__ */ new Map());
505
506
  async function registerAsync(register) {
506
507
  const response = await supabase.auth.signUp(register);
507
- setCurrentUser(response.data.user);
508
+ setCurrentUser((prev) => {
509
+ const newUser = response.data.user;
510
+ if (prev?.id === newUser?.id) {
511
+ return prev;
512
+ }
513
+ return newUser;
514
+ });
508
515
  return response;
509
516
  }
510
517
  async function signInAsync(username, password) {
@@ -513,7 +520,13 @@ function AuthProvider({
513
520
  password
514
521
  });
515
522
  if (response_0.data) {
516
- setCurrentUser(response_0.data.user);
523
+ setCurrentUser((prev_0) => {
524
+ const newUser_0 = response_0.data.user;
525
+ if (prev_0?.id === newUser_0?.id) {
526
+ return prev_0;
527
+ }
528
+ return newUser_0;
529
+ });
517
530
  }
518
531
  return response_0;
519
532
  }
@@ -543,6 +556,7 @@ function AuthProvider({
543
556
  useEffect2(() => {
544
557
  const request = supabase.auth.onAuthStateChange((event) => {
545
558
  if (event === "SIGNED_IN" || event === "SIGNED_OUT") {
559
+ setIsAuthTransitioning(true);
546
560
  setUserNeedsChange(true);
547
561
  }
548
562
  });
@@ -553,8 +567,20 @@ function AuthProvider({
553
567
  useEffect2(() => {
554
568
  if (userNeedsChange === false) return;
555
569
  supabase.auth.getSession().then((x_2) => {
556
- setCurrentUser(x_2?.data?.session?.user ?? null);
570
+ setCurrentUser((prev_1) => {
571
+ const newUser_1 = x_2?.data?.session?.user ?? null;
572
+ if (prev_1?.id === newUser_1?.id) {
573
+ return prev_1;
574
+ }
575
+ return newUser_1;
576
+ });
577
+ setUserNeedsChange(false);
578
+ setIsAuthTransitioning(false);
579
+ }).catch((error) => {
580
+ console.error("Failed to get session:", error);
581
+ setCurrentUser((prev_2) => prev_2 === null ? prev_2 : null);
557
582
  setUserNeedsChange(false);
583
+ setIsAuthTransitioning(false);
558
584
  });
559
585
  }, [userNeedsChange]);
560
586
  const profileRequest = useDbQuery(supabase.schema("core").from("Profile").select("*, UserAccess(accessKey), status").eq("id", currentUser?.id).limit(1).maybeSingle(), {
@@ -678,14 +704,14 @@ function AuthProvider({
678
704
  profileStatus,
679
705
  isArchived,
680
706
  isSuspended,
681
- isLoading: currentUser === null ? false : profileRequest.isLoading || accessKeysRequest.isLoading || currentUser === void 0,
707
+ isLoading: isAuthTransitioning ? true : currentUser === null ? false : profileRequest.isLoading || accessKeysRequest.isLoading || currentUser === void 0,
682
708
  signInAsync,
683
709
  signOutAsync,
684
710
  onSignOut,
685
711
  removeOnSignOut,
686
712
  registerAsync,
687
713
  refreshAsync
688
- }), [profileRequest.data, profileRequest.isLoading, accessKeysRequest.data, accessKeysRequest.isLoading, currentUser, combinedAccess, profileStatus, isArchived, isSuspended, hasAccess]);
714
+ }), [profileRequest.data, profileRequest.isLoading, accessKeysRequest.data, accessKeysRequest.isLoading, currentUser, combinedAccess, profileStatus, isArchived, isSuspended, hasAccess, isAuthTransitioning]);
689
715
  const content = enableEntityPermissions ? /* @__PURE__ */ jsx3(PermissionProvider, { children }) : children;
690
716
  return /* @__PURE__ */ jsx3(setupAuthContext.Provider, { value: authStateWithLoading, children: content });
691
717
  }
@@ -918,4 +944,4 @@ export {
918
944
  useSetUserMetadata,
919
945
  useUserMetadataState
920
946
  };
921
- //# sourceMappingURL=chunk-PZLVL7DU.js.map
947
+ //# sourceMappingURL=chunk-7ANPMUR5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/TimeoutError.ts","../src/useDbQuery.ts","../src/auth/context/setupAuthContext.tsx","../src/auth/context/PermissionContext.tsx","../src/auth/context/AuthProvider.tsx","../src/auth/context/UserMetadataContext.tsx"],"sourcesContent":["export const TIMEOUT_ERROR_MESSAGE = \"Request timed out\";\nexport const DEFAULT_QUERY_TIMEOUT = 15_000; // 15 seconds\n\nexport function isTimeoutError(error: Error | null | undefined): boolean {\n if (!error) return false;\n return error.name === \"AbortError\" || error.message === TIMEOUT_ERROR_MESSAGE || error.message.toLowerCase().includes(\"timed out\");\n}","import { PostgrestError, PostgrestSingleResponse } from \"@supabase/supabase-js\";\nimport { useMemo, useRef } from \"react\";\nimport { ItemType } from \"@pol-studios/utils\";\nimport { encode, UseQuerySingleReturn } from \"@supabase-cache-helpers/postgrest-react-query\";\nimport { omit } from \"@pol-studios/utils\";\nimport { useQuery, UseQueryOptions } from \"@tanstack/react-query\";\nimport { useDelayedValue } from \"@pol-studios/hooks/state\";\nimport { DEFAULT_QUERY_TIMEOUT, TIMEOUT_ERROR_MESSAGE } from \"./errors/TimeoutError\";\ntype ConfigurationOptions<T> = {\n crossOrganization?: boolean;\n filter?: (item: ItemType<T>) => boolean;\n timeout?: number;\n};\nexport type UseDbQuerySingleReturn<T> = UseQuerySingleReturn<T> & {\n data: T | null | undefined;\n count?: number | null;\n};\nexport function useDbQuery<Result>(query: PromiseLike<PostgrestSingleResponse<Result>> & {\n abortSignal?: (signal: AbortSignal) => PromiseLike<PostgrestSingleResponse<Result>>;\n}, config?: Omit<UseQueryOptions<Result, PostgrestError>, \"queryKey\" | \"queryFn\"> & ConfigurationOptions<Result>) {\n // Debounce query key to prevent rapid query churn during fast navigation\n const queryKey = encode(query, false);\n const queryKeyString = queryKey.join(\"-\");\n const debouncedKeyString = useDelayedValue(queryKeyString, 50);\n\n // Only enable query when key has stabilized (debounced matches current)\n const isKeyStable = queryKeyString === debouncedKeyString;\n const effectiveEnabled = config?.enabled !== false && isKeyStable;\n const timeoutMs = config?.timeout ?? DEFAULT_QUERY_TIMEOUT;\n\n // Track count from Supabase response (for queries with count: \"exact\")\n const countRef = useRef<number | null>(null);\n const request = useQuery(useMemo(() => ({\n queryKey,\n queryFn: async ({\n signal\n }) => {\n const controller = new AbortController();\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n try {\n // Execute query with abort signal\n const queryWithSignal = query.abortSignal?.(controller.signal) ?? query;\n const result = await queryWithSignal;\n if (result.error) throw result.error;\n // Store count if available (from queries with count: \"exact\")\n countRef.current = result.count ?? null;\n return result.data;\n } catch (err: any) {\n if (err.name === \"AbortError\") {\n throw new Error(TIMEOUT_ERROR_MESSAGE);\n }\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n },\n ...omit({\n retry: 1,\n ...config,\n enabled: effectiveEnabled\n }, [\"queryKey\", \"timeout\"])\n }), [queryKey, config, effectiveEnabled, timeoutMs, query]));\n\n // Return request with count property added\n return useMemo(() => ({\n ...request,\n count: countRef.current\n }), [request, countRef.current]) as UseDbQuerySingleReturn<Result>;\n}","import { c as _c } from \"react/compiler-runtime\";\n/**\n * SetupAuthContext - Shared context for auth state\n *\n * This file is separate to avoid circular dependencies between\n * AuthProvider and PermissionContext.\n */\n\nimport { createContext, ReactNode } from \"react\";\nimport { AuthTokenResponsePassword, SignUpWithPasswordCredentials, User } from \"@supabase/supabase-js\";\nexport type ProfileStatus = \"active\" | \"archived\" | \"suspended\";\nexport interface SetupAuthContext {\n user?: User | null | undefined;\n isLoading: boolean;\n profile: Profile | null | undefined;\n access: string[];\n /** Whether the profile is archived */\n isArchived: boolean;\n /** Whether the profile is suspended */\n isSuspended: boolean;\n /** The profile status (active, archived, suspended) */\n profileStatus: ProfileStatus | undefined;\n registerAsync: (register: SignUpWithPasswordCredentials) => Promise<any>;\n signInAsync: (username: string, password: string) => Promise<AuthTokenResponsePassword>;\n signOutAsync: () => Promise<any>;\n refreshAsync: () => Promise<void>;\n onSignOut: (action: () => any) => string;\n removeOnSignOut: (id: string) => any;\n hasAccess?: (key: string) => boolean;\n}\n\n// Profile type - simplified version, the full type is in AuthProvider\nexport interface Profile {\n id: string;\n email?: string;\n fullName?: string;\n status?: ProfileStatus;\n UserAccess?: Array<{\n accessKey: string;\n }>;\n [key: string]: any;\n}\nexport const setupAuthContext = createContext({} as SetupAuthContext);\n\n/**\n * Props for SetupAuthContextProvider\n * A simpler provider that takes pre-computed auth state\n */\nexport interface SetupAuthContextProviderProps {\n children: ReactNode;\n auth: SetupAuthContext;\n}\n\n/**\n * Simple provider that takes auth state and provides it via context.\n * Use this when you already have the auth state and just need to provide it to children.\n *\n * @example\n * ```tsx\n * const auth = useSetupAuth();\n * return (\n * <SetupAuthContextProvider auth={auth}>\n * <MyComponent />\n * </SetupAuthContextProvider>\n * );\n * ```\n */\nexport function SetupAuthContextProvider(t0) {\n const $ = _c(3);\n const {\n children,\n auth\n } = t0;\n let t1;\n if ($[0] !== auth || $[1] !== children) {\n t1 = <setupAuthContext.Provider value={auth}>{children}</setupAuthContext.Provider>;\n $[0] = auth;\n $[1] = children;\n $[2] = t1;\n } else {\n t1 = $[2];\n }\n return t1;\n}","import { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport useSupabase from \"../../useSupabase\";\nimport { setupAuthContext } from \"./setupAuthContext\";\nimport { EntityType, EntityPermissionLevel, EntityAction, EntityPermissionCheck } from \"../types/EntityPermissions\";\n\n// Cache entry with TTL\ninterface CacheEntry {\n permission: EntityPermissionCheck;\n expiresAt: number;\n}\n\n// Entity identifier for batch lookups\ninterface EntityIdentifier {\n entityType: EntityType;\n entityId: number;\n}\n\n// Cache key helper\nfunction getCacheKey(userId: string | undefined, entityType: EntityType, entityId: number): string {\n return `${userId || \"anon\"}:${entityType}:${entityId}`;\n}\n\n// Default loading state\nconst loadingPermission: EntityPermissionCheck = {\n canView: false,\n canAdminView: false,\n canEdit: false,\n canCreate: false,\n canDelete: false,\n canShare: false,\n permissionLevel: null,\n isLoading: true\n};\n\n// No permission state\nconst noPermission: EntityPermissionCheck = {\n canView: false,\n canAdminView: false,\n canEdit: false,\n canCreate: false,\n canDelete: false,\n canShare: false,\n permissionLevel: null,\n isLoading: false,\n isDenied: false\n};\n\n// Denied permission state - explicitly blocked access\nconst deniedPermission: EntityPermissionCheck = {\n canView: false,\n canAdminView: false,\n canEdit: false,\n canCreate: false,\n canDelete: false,\n canShare: false,\n permissionLevel: null,\n isLoading: false,\n isDenied: true\n};\n\n// Map permission level to permission check\n// If permission is 'denied', it means access was explicitly blocked\n// Handles both legacy formats (ReadOnly, AdminReadOnly, ReadWrite, Admin)\n// and new formats (view, edit, admin, denied)\nfunction mapPermissionLevel(level: EntityPermissionLevel | \"denied\" | string | null): EntityPermissionCheck {\n if (!level) {\n return noPermission;\n }\n\n // Normalize to lowercase for comparison to handle both legacy and new formats\n const normalizedLevel = level.toLowerCase();\n switch (normalizedLevel) {\n // Legacy format: ReadOnly, New format: view\n case \"readonly\":\n case \"view\":\n return {\n canView: true,\n canAdminView: false,\n canEdit: false,\n canCreate: false,\n canDelete: false,\n canShare: false,\n permissionLevel: \"ReadOnly\",\n isLoading: false,\n isDenied: false\n };\n // Legacy format: AdminReadOnly (no new equivalent, keep for backwards compatibility)\n case \"adminreadonly\":\n return {\n canView: true,\n canAdminView: true,\n canEdit: false,\n canCreate: false,\n canDelete: false,\n canShare: false,\n permissionLevel: \"AdminReadOnly\",\n isLoading: false,\n isDenied: false\n };\n // Legacy format: ReadWrite, New format: edit\n case \"readwrite\":\n case \"edit\":\n return {\n canView: true,\n canAdminView: false,\n canEdit: true,\n canCreate: true,\n canDelete: false,\n canShare: false,\n permissionLevel: \"ReadWrite\",\n isLoading: false,\n isDenied: false\n };\n // Legacy format: Admin, New format: admin\n case \"admin\":\n return {\n canView: true,\n canAdminView: true,\n canEdit: true,\n canCreate: true,\n canDelete: true,\n canShare: true,\n permissionLevel: \"Admin\",\n isLoading: false,\n isDenied: false\n };\n // New format: denied - explicit access denial\n case \"denied\":\n return deniedPermission;\n default:\n console.warn(`Unknown permission level: ${level}`);\n return noPermission;\n }\n}\n\n// Context interface\nexport interface PermissionContextValue {\n getPermission: (entityType: EntityType, entityId: number) => EntityPermissionCheck;\n checkPermission: (entityType: EntityType, entityId: number, action: EntityAction) => boolean;\n prefetchPermissions: (entities: EntityIdentifier[]) => Promise<void>;\n invalidatePermission: (entityType: EntityType, entityId: number) => void;\n isLoading: boolean;\n}\n\n/**\n * @deprecated Use permissionContext instead\n */\nexport interface EntityPermissionContextValue extends PermissionContextValue {}\nexport const permissionContext = createContext<PermissionContextValue>({} as PermissionContextValue);\n\n/**\n * @deprecated Use permissionContext instead\n */\nexport const entityPermissionContext = permissionContext;\n\n// TTL for cache entries (5 minutes)\nconst CACHE_TTL_MS = 5 * 60 * 1000;\n\n// TTL for error cache entries (30 seconds) - shorter to allow quick retry\nconst ERROR_CACHE_TTL_MS = 30 * 1000;\n\n// Batch collection delay (50ms)\nconst BATCH_DELAY_MS = 50;\nexport function PermissionProvider({\n children\n}: {\n children: ReactNode;\n}) {\n const supabase = useSupabase();\n const setupAuth = useContext(setupAuthContext);\n const user = setupAuth?.user;\n\n // Permission cache\n const cacheRef = useRef<Map<string, CacheEntry>>(new Map());\n\n // Pending lookups for batching\n const pendingLookupsRef = useRef<Set<string>>(new Set());\n\n // In-flight lookups to prevent duplicate requests during async RPC calls\n const inFlightRef = useRef<Set<string>>(new Set());\n\n // Batch timer ref\n const batchTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Loading state\n const [isLoading, setIsLoading] = useState(false);\n\n // Force re-render trigger\n const [, forceUpdate] = useState(0);\n\n // Clean up expired cache entries\n const cleanupExpiredEntries = useCallback(() => {\n const now = Date.now();\n const cache = cacheRef.current;\n let hasExpired = false;\n for (const [key, entry] of cache.entries()) {\n if (entry.expiresAt < now) {\n cache.delete(key);\n hasExpired = true;\n }\n }\n if (hasExpired) {\n forceUpdate(prev => prev + 1);\n }\n }, []);\n\n // Periodic cleanup of expired entries\n useEffect(() => {\n const cleanupInterval = setInterval(cleanupExpiredEntries, 60 * 1000);\n return () => clearInterval(cleanupInterval);\n }, [cleanupExpiredEntries]);\n\n // Execute batch lookup\n const executeBatchLookup = useCallback(async () => {\n const pending = Array.from(pendingLookupsRef.current);\n pendingLookupsRef.current.clear();\n if (pending.length === 0 || !user?.id) {\n return;\n }\n\n // Move pending keys to in-flight to prevent duplicate requests\n pending.forEach(k => inFlightRef.current.add(k));\n setIsLoading(true);\n try {\n // Parse pending keys back to entities (format: userId:entityType:entityId)\n const entities = pending.map(key_0 => {\n const parts = key_0.split(\":\");\n // Skip the userId part (index 0), use entityType (index 1) and entityId (index 2)\n const entityType = parts[1];\n const entityIdStr = parts[2];\n return {\n entity_type: entityType as EntityType,\n entity_id: parseInt(entityIdStr, 10)\n };\n });\n\n // Call RPC for batch lookup\n // Using 'as any' because the RPC function type isn't in the generated database types\n const {\n data,\n error\n } = await (supabase.rpc as any)(\"get_user_entity_permissions\", {\n p_user_id: user.id,\n p_entities: entities\n });\n if (error) {\n console.error(\"Failed to fetch entity permissions:\", error);\n // Mark all pending as no permission with shorter TTL to allow quick retry\n const cache_0 = cacheRef.current;\n const now_0 = Date.now();\n for (const key_1 of pending) {\n cache_0.set(key_1, {\n permission: noPermission,\n expiresAt: now_0 + ERROR_CACHE_TTL_MS\n });\n }\n } else if (data) {\n // Update cache with results\n const cache_1 = cacheRef.current;\n const now_1 = Date.now();\n\n // Create a map of results for quick lookup\n // Permission can be a standard level or 'denied' for explicit deny\n const resultsMap = new Map<string, EntityPermissionLevel | \"denied\">();\n // Type the data as an array of permission results\n const results = data as Array<{\n entity_type: EntityType;\n entity_id: number;\n permission: EntityPermissionLevel | \"denied\";\n }>;\n for (const result of results) {\n const key_2 = getCacheKey(user?.id, result.entity_type, result.entity_id);\n resultsMap.set(key_2, result.permission);\n }\n\n // Update cache for all pending keys\n for (const key_3 of pending) {\n const permissionLevel = resultsMap.get(key_3) || null;\n cache_1.set(key_3, {\n permission: mapPermissionLevel(permissionLevel),\n expiresAt: now_1 + CACHE_TTL_MS\n });\n }\n }\n forceUpdate(prev_0 => prev_0 + 1);\n } catch (err) {\n console.error(\"Unexpected error fetching entity permissions:\", err);\n } finally {\n // Remove from in-flight after completion (success or error)\n pending.forEach(k => inFlightRef.current.delete(k));\n setIsLoading(false);\n }\n }, [supabase, user?.id]);\n\n // Schedule batch lookup\n const scheduleBatchLookup = useCallback(() => {\n if (batchTimerRef.current) {\n clearTimeout(batchTimerRef.current);\n }\n batchTimerRef.current = setTimeout(() => {\n batchTimerRef.current = null;\n executeBatchLookup();\n }, BATCH_DELAY_MS);\n }, [executeBatchLookup]);\n\n // Get permission for an entity\n const getPermission = useCallback((entityType_0: EntityType, entityId: number): EntityPermissionCheck => {\n const key_4 = getCacheKey(user?.id, entityType_0, entityId);\n const cache_2 = cacheRef.current;\n const cached = cache_2.get(key_4);\n const now_2 = Date.now();\n\n // Return cached if valid\n if (cached && cached.expiresAt > now_2) {\n return cached.permission;\n }\n\n // Don't add if already pending or in-flight to prevent duplicate requests\n if (!pendingLookupsRef.current.has(key_4) && !inFlightRef.current.has(key_4)) {\n pendingLookupsRef.current.add(key_4);\n scheduleBatchLookup();\n }\n return loadingPermission;\n }, [scheduleBatchLookup, user?.id]);\n\n // Check specific permission action\n const checkPermission = useCallback((entityType_1: EntityType, entityId_0: number, action: EntityAction): boolean => {\n const permission = getPermission(entityType_1, entityId_0);\n if (permission.isLoading) {\n return false;\n }\n switch (action) {\n case \"view\":\n return permission.canView;\n case \"adminView\":\n return permission.canAdminView;\n case \"edit\":\n return permission.canEdit;\n case \"create\":\n return permission.canCreate;\n case \"delete\":\n return permission.canDelete;\n case \"share\":\n return permission.canShare;\n default:\n return false;\n }\n }, [getPermission]);\n\n // Prefetch permissions for multiple entities\n const prefetchPermissions = useCallback(async (entities_0: EntityIdentifier[]): Promise<void> => {\n if (!user?.id || entities_0.length === 0) {\n return;\n }\n const cache_3 = cacheRef.current;\n const now_3 = Date.now();\n\n // Filter out already cached entries, items already pending, and items in-flight\n const toFetch = entities_0.filter(entity => {\n const key_5 = getCacheKey(user?.id, entity.entityType, entity.entityId);\n const cached_0 = cache_3.get(key_5);\n const isPending = pendingLookupsRef.current.has(key_5);\n const isInFlight = inFlightRef.current.has(key_5);\n return !isPending && !isInFlight && (!cached_0 || cached_0.expiresAt <= now_3);\n });\n if (toFetch.length === 0) {\n return;\n }\n setIsLoading(true);\n try {\n const entitiesParam = toFetch.map(e => ({\n entity_type: e.entityType,\n entity_id: e.entityId\n }));\n\n // Using 'as any' because the RPC function type isn't in the generated database types\n const {\n data: data_0,\n error: error_0\n } = await (supabase.rpc as any)(\"get_user_entity_permissions\", {\n p_user_id: user.id,\n p_entities: entitiesParam\n });\n if (error_0) {\n console.error(\"Failed to prefetch entity permissions:\", error_0);\n return;\n }\n if (data_0) {\n // Capture timestamp AFTER the RPC call completes\n const cacheTimestamp = Date.now();\n\n // Permission can be a standard level or 'denied' for explicit deny\n const resultsMap_0 = new Map<string, EntityPermissionLevel | \"denied\">();\n // Type the data as an array of permission results\n const results_0 = data_0 as Array<{\n entity_type: EntityType;\n entity_id: number;\n permission: EntityPermissionLevel | \"denied\";\n }>;\n for (const result_0 of results_0) {\n const key_6 = getCacheKey(user?.id, result_0.entity_type, result_0.entity_id);\n resultsMap_0.set(key_6, result_0.permission);\n }\n for (const entity_0 of toFetch) {\n const key_7 = getCacheKey(user?.id, entity_0.entityType, entity_0.entityId);\n const permissionLevel_0 = resultsMap_0.get(key_7) || null;\n cache_3.set(key_7, {\n permission: mapPermissionLevel(permissionLevel_0),\n expiresAt: cacheTimestamp + CACHE_TTL_MS\n });\n }\n forceUpdate(prev_1 => prev_1 + 1);\n }\n } catch (err_0) {\n console.error(\"Unexpected error prefetching entity permissions:\", err_0);\n } finally {\n setIsLoading(false);\n }\n }, [supabase, user?.id]);\n\n // Invalidate a specific permission\n const invalidatePermission = useCallback((entityType_2: EntityType, entityId_1: number): void => {\n const key_8 = getCacheKey(user?.id, entityType_2, entityId_1);\n cacheRef.current.delete(key_8);\n forceUpdate(prev_2 => prev_2 + 1);\n }, [user?.id]);\n\n // Parse scoped access key format: <entity_type>:<entity_id>:<permission_level>\n // Returns null if the key format is invalid\n const parseScopedAccessKey = useCallback((key_9: string): {\n entityType: EntityType;\n entityId: number;\n } | null => {\n if (!key_9 || typeof key_9 !== \"string\") {\n return null;\n }\n const parts_0 = key_9.split(\":\");\n if (parts_0.length < 2) {\n return null;\n }\n const entityType_3 = parts_0[0];\n const entityId_2 = parseInt(parts_0[1], 10);\n if (isNaN(entityId_2)) {\n return null;\n }\n // Use explicit mapping instead of string manipulation\n // This correctly handles \"database\" -> \"ProjectDatabase\" case\n const entityTypeMap: Record<string, EntityType> = {\n client: \"Client\",\n project: \"Project\",\n database: \"ProjectDatabase\",\n projectdatabase: \"ProjectDatabase\"\n };\n const normalizedEntityType = entityTypeMap[entityType_3.toLowerCase()];\n if (!normalizedEntityType) {\n return null;\n }\n return {\n entityType: normalizedEntityType,\n entityId: entityId_2\n };\n }, []);\n\n // Real-time subscription for permission changes\n useEffect(() => {\n if (!user?.id) {\n return;\n }\n\n // Subscribe to changes on UserAccess table for the current user\n // Use unique channel name per user to avoid collisions\n const channel = supabase.channel(`entity-permissions-${user.id}`).on(\"postgres_changes\", {\n event: \"*\",\n schema: \"core\",\n table: \"UserAccess\",\n filter: `userId=eq.${user.id}`\n }, payload => {\n // Parse the scoped access key from the new record\n if (payload.new && typeof payload.new === \"object\" && \"scopedAccessKey\" in payload.new && typeof payload.new.scopedAccessKey === \"string\") {\n const parsed = parseScopedAccessKey(payload.new.scopedAccessKey);\n if (parsed) {\n invalidatePermission(parsed.entityType, parsed.entityId);\n }\n }\n // Parse the scoped access key from the old record (for deletes/updates)\n if (payload.old && typeof payload.old === \"object\" && \"scopedAccessKey\" in payload.old && typeof payload.old.scopedAccessKey === \"string\") {\n const parsed_0 = parseScopedAccessKey(payload.old.scopedAccessKey);\n if (parsed_0) {\n invalidatePermission(parsed_0.entityType, parsed_0.entityId);\n }\n }\n }).subscribe();\n return () => {\n channel.unsubscribe();\n supabase.removeChannel(channel);\n };\n }, [supabase, user?.id, invalidatePermission, parseScopedAccessKey]);\n\n // Clear cache on user change\n useEffect(() => {\n cacheRef.current.clear();\n pendingLookupsRef.current.clear();\n inFlightRef.current.clear();\n if (batchTimerRef.current) {\n clearTimeout(batchTimerRef.current);\n batchTimerRef.current = null;\n }\n forceUpdate(prev_3 => prev_3 + 1);\n }, [user?.id]);\n\n // Cleanup batch timer on unmount\n useEffect(() => {\n return () => {\n if (batchTimerRef.current) {\n clearTimeout(batchTimerRef.current);\n }\n };\n }, []);\n const value = useMemo(() => ({\n getPermission,\n checkPermission,\n prefetchPermissions,\n invalidatePermission,\n isLoading\n }), [getPermission, checkPermission, prefetchPermissions, invalidatePermission, isLoading]);\n return <permissionContext.Provider value={value}>\n {children}\n </permissionContext.Provider>;\n}\nexport function usePermissions() {\n const context = useContext(permissionContext);\n if (!context || Object.keys(context).length === 0) {\n throw new Error(\"usePermissions must be used within a PermissionProvider\");\n }\n return context;\n}","import { useDbQuery as useQuery } from \"../../useDbQuery\";\nimport useSupabase, { typedSupabase } from \"../../useSupabase\";\nimport { isUsable, newUuid } from \"@pol-studios/utils\";\nimport { QueryData, SignUpWithPasswordCredentials, User } from \"@supabase/supabase-js\";\nimport { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { PermissionProvider } from \"./PermissionContext\";\n// Import from shared context to use internally\nimport { setupAuthContext, type ProfileStatus } from \"./setupAuthContext\";\n// Re-export from shared context to maintain API compatibility\nexport { setupAuthContext, SetupAuthContextProvider, type SetupAuthContext, type SetupAuthContextProviderProps, type ProfileStatus } from \"./setupAuthContext\";\nconst profileQuery = typedSupabase?.schema(\"core\").from(\"Profile\").select(\"*, UserAccess(accessKey), status\").single();\nexport type Profile = QueryData<typeof profileQuery>;\nexport interface AuthProviderProps {\n children: ReactNode;\n /**\n * Enable entity-level permissions system (Project, Client, ProjectDatabase access control).\n * When enabled, wraps children with PermissionProvider.\n * @default false\n */\n enableEntityPermissions?: boolean;\n}\nexport function AuthProvider({\n children,\n enableEntityPermissions = false\n}: AuthProviderProps) {\n const supabase = useSupabase();\n const [currentUser, setCurrentUser] = useState<User | null | undefined>(undefined);\n const [userNeedsChange, setUserNeedsChange] = useState(true);\n // Prevents premature isLoading=false during async gap between auth event and session fetch\n const [isAuthTransitioning, setIsAuthTransitioning] = useState(false);\n const [onSignOutCallbacks, setOnSignOutCallbacks] = useState(new Map<string, () => any>());\n async function registerAsync(register: SignUpWithPasswordCredentials) {\n const response = await supabase.auth.signUp(register);\n setCurrentUser(prev => {\n const newUser = response.data.user;\n if (prev?.id === newUser?.id) {\n return prev;\n }\n return newUser;\n });\n return response;\n }\n async function signInAsync(username: string, password: string) {\n const response_0 = await supabase.auth.signInWithPassword({\n email: username,\n password\n });\n if (response_0.data) {\n setCurrentUser(prev_0 => {\n const newUser_0 = response_0.data.user;\n if (prev_0?.id === newUser_0?.id) {\n return prev_0;\n }\n return newUser_0;\n });\n }\n return response_0;\n }\n async function signOutAsync() {\n const response_1 = await supabase.auth.signOut();\n if (isUsable(response_1.error) === false) {\n Array.from(onSignOutCallbacks.values()).forEach(x => {\n x();\n });\n }\n return response_1;\n }\n function onSignOut(action: () => any) {\n const id = newUuid();\n setOnSignOutCallbacks(x_0 => new Map(x_0).set(id, action));\n return id;\n }\n function removeOnSignOut(id_0: string) {\n setOnSignOutCallbacks(x_1 => {\n const map = new Map(x_1);\n map.delete(id_0);\n return map;\n });\n }\n async function refreshAsync() {}\n useEffect(() => {\n const request = supabase.auth.onAuthStateChange(event => {\n if (event === \"SIGNED_IN\" || event === \"SIGNED_OUT\") {\n setIsAuthTransitioning(true);\n setUserNeedsChange(true);\n }\n });\n return () => {\n request.data.subscription.unsubscribe();\n };\n }, [supabase.auth]);\n useEffect(() => {\n if (userNeedsChange === false) return;\n supabase.auth.getSession().then(x_2 => {\n setCurrentUser(prev_1 => {\n const newUser_1 = x_2?.data?.session?.user ?? null;\n // Only update reference if user actually changed\n if (prev_1?.id === newUser_1?.id) {\n return prev_1;\n }\n return newUser_1;\n });\n setUserNeedsChange(false);\n setIsAuthTransitioning(false);\n }).catch(error => {\n console.error(\"Failed to get session:\", error);\n setCurrentUser(prev_2 => prev_2 === null ? prev_2 : null);\n setUserNeedsChange(false);\n setIsAuthTransitioning(false);\n });\n }, [userNeedsChange]);\n const profileRequest = useQuery(supabase.schema(\"core\").from(\"Profile\").select(\"*, UserAccess(accessKey), status\").eq(\"id\", currentUser?.id!).limit(1).maybeSingle(), {\n enabled: isUsable(currentUser),\n crossOrganization: true\n });\n\n // Fetch all access keys (direct + group-based) using the database function\n const accessKeysRequest = useQuery(supabase.schema(\"core\").rpc(\"get_user_access_keys\", {\n user_id: currentUser?.id!\n }), {\n enabled: isUsable(currentUser),\n crossOrganization: true\n });\n\n // Stable refetch callback for real-time subscriptions\n const refetchAccessKeys = useCallback(() => {\n accessKeysRequest.refetch();\n }, [accessKeysRequest.refetch]);\n\n // Track user's group IDs for filtering GroupAccessKey changes\n const userGroupIdsRef = useRef<Set<number>>(new Set());\n\n // Update group IDs when access keys change\n useEffect(() => {\n if (accessKeysRequest.data) {\n const groupIds = new Set<number>();\n for (const item of accessKeysRequest.data) {\n if (item.source === \"group\" && item.source_id) {\n groupIds.add(item.source_id);\n }\n }\n userGroupIdsRef.current = groupIds;\n }\n }, [accessKeysRequest.data]);\n\n // Real-time subscription for access key changes (direct + group-based)\n useEffect(() => {\n if (!currentUser?.id) return;\n const channel = supabase.channel(`user-access-keys-${currentUser.id}`)\n // Direct access changes\n .on(\"postgres_changes\", {\n event: \"*\",\n schema: \"core\",\n table: \"UserAccess\",\n filter: `userId=eq.${currentUser.id}`\n }, () => {\n refetchAccessKeys();\n })\n // Group membership changes for this user\n .on(\"postgres_changes\", {\n event: \"*\",\n schema: \"core\",\n table: \"UserGroup\",\n filter: `userId=eq.${currentUser.id}`\n }, () => {\n refetchAccessKeys();\n })\n // Group access key changes (check if user is in affected group)\n .on(\"postgres_changes\", {\n event: \"*\",\n schema: \"core\",\n table: \"GroupAccessKey\"\n }, payload => {\n const groupId = (payload.new as {\n groupId?: number;\n })?.groupId || (payload.old as {\n groupId?: number;\n })?.groupId;\n if (groupId && userGroupIdsRef.current.has(groupId)) {\n refetchAccessKeys();\n }\n })\n // Group activation/deactivation\n .on(\"postgres_changes\", {\n event: \"UPDATE\",\n schema: \"core\",\n table: \"Group\"\n }, payload_0 => {\n const oldActive = (payload_0.old as {\n isActive?: boolean;\n })?.isActive;\n const newActive = (payload_0.new as {\n isActive?: boolean;\n })?.isActive;\n const groupId_0 = (payload_0.new as {\n id?: number;\n })?.id;\n // Refetch if activation status changed and user is in this group\n if (oldActive !== newActive && groupId_0 && userGroupIdsRef.current.has(groupId_0)) {\n refetchAccessKeys();\n }\n }).subscribe();\n return () => {\n channel.unsubscribe();\n supabase.removeChannel(channel);\n };\n }, [supabase, currentUser?.id, refetchAccessKeys]);\n\n // Real-time subscription for profile status changes (force signout if archived/suspended)\n useEffect(() => {\n if (!currentUser?.id) return;\n const profileChannel = supabase.channel(`profile-status-${currentUser.id}`).on(\"postgres_changes\", {\n event: \"UPDATE\",\n schema: \"core\",\n table: \"Profile\",\n filter: `id=eq.${currentUser.id}`\n }, payload_1 => {\n const newStatus = (payload_1.new as {\n status?: string;\n })?.status;\n const oldStatus = (payload_1.old as {\n status?: string;\n })?.status;\n\n // If status changed to archived/suspended, force sign out\n if (oldStatus === \"active\" && (newStatus === \"archived\" || newStatus === \"suspended\")) {\n signOutAsync();\n }\n\n // Refetch profile data to update UI\n profileRequest.refetch();\n }).subscribe();\n return () => {\n profileChannel.unsubscribe();\n supabase.removeChannel(profileChannel);\n };\n }, [supabase, currentUser?.id, profileRequest.refetch]);\n\n // Combine access keys from both sources, preferring the RPC result\n const combinedAccess: string[] = useMemo(() => {\n // If we have the RPC result, use it (includes both direct and group-based)\n if (accessKeysRequest.data) {\n const uniqueKeys = new Set<string>();\n for (const item_0 of accessKeysRequest.data) {\n if (item_0.access_key) {\n uniqueKeys.add(item_0.access_key);\n }\n }\n return Array.from(uniqueKeys);\n }\n // Fallback to direct access only (for backwards compatibility during loading)\n return profileRequest.data?.UserAccess?.map(x_3 => x_3.accessKey) || [];\n }, [accessKeysRequest.data, profileRequest.data?.UserAccess]);\n\n // Compute profile status values\n const profileStatus = profileRequest.data?.status as ProfileStatus | undefined;\n const isArchived = profileStatus === \"archived\";\n const isSuspended = profileStatus === \"suspended\";\n const hasAccess = useCallback((key: string) => {\n // Archived/suspended users have no access\n if (isArchived || isSuspended) {\n return false;\n }\n const accessGiven = combinedAccess;\n if (isUsable(accessGiven) === false) return false;\n if (accessGiven.includes(\"owner\")) return true;\n if (accessGiven.includes(key)) return true;\n if (isUsable(key) === false) return true;\n return false;\n }, [combinedAccess, isArchived, isSuspended]);\n const authStateWithLoading = useMemo(() => ({\n hasAccess,\n user: currentUser,\n profile: profileRequest.data,\n access: combinedAccess,\n profileStatus,\n isArchived,\n isSuspended,\n isLoading: isAuthTransitioning ? true : currentUser === null ? false : profileRequest.isLoading || accessKeysRequest.isLoading || currentUser === undefined,\n signInAsync,\n signOutAsync,\n onSignOut,\n removeOnSignOut,\n registerAsync,\n refreshAsync\n }), [profileRequest.data, profileRequest.isLoading, accessKeysRequest.data, accessKeysRequest.isLoading, currentUser, combinedAccess, profileStatus, isArchived, isSuspended, hasAccess, isAuthTransitioning]);\n const content = enableEntityPermissions ? <PermissionProvider>{children}</PermissionProvider> : children;\n return <setupAuthContext.Provider value={authStateWithLoading}>\n {content}\n </setupAuthContext.Provider>;\n}","import { c as _c } from \"react/compiler-runtime\";\nimport { ReactNode, createContext, useContext, useEffect, useMemo, useState, useCallback, useRef } from \"react\";\nimport { useDbQuery as useQuery } from \"../../useDbQuery\";\nimport { useDbUpsert as useUpsert } from \"../../hooks\";\nimport useSupabase, { Database } from \"../../useSupabase\";\nimport { isUsable } from \"@pol-studios/utils\";\nimport { setupAuthContext } from \"./AuthProvider\";\n\n// UserMetadata query constant\nconst UserMetadataQuery = {\n schema: \"core\",\n table: \"UserMetadata\",\n defaultQuery: \"key, userId, value\"\n} as const;\n\n// Type definitions for UserMetadata\nexport type UserMetadataRow = Database[\"core\"][\"Tables\"][\"UserMetadata\"][\"Row\"];\nexport type UserMetadataInsert = Database[\"core\"][\"Tables\"][\"UserMetadata\"][\"Insert\"];\nexport type UserMetadataUpdate = Database[\"core\"][\"Tables\"][\"UserMetadata\"][\"Update\"];\n\n// Context interface\nexport interface UserMetadataContextType {\n metadata: Record<string, string>;\n isLoading: boolean;\n error: Error | null;\n setMetadata: (key: string, value: string) => Promise<void>;\n getMetadata: (key: string) => string | undefined;\n removeMetadata: (key: string) => Promise<void>;\n refreshMetadata: () => Promise<void>;\n}\n\n// Create context\nexport const userMetadataContext = createContext<UserMetadataContextType | null>(null);\n\n// Provider component\nexport function UserMetadataProvider({\n children\n}: {\n children: ReactNode;\n}) {\n const supabase = useSupabase();\n const [metadata, setMetadataState] = useState<Record<string, string>>({});\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Get current user ID from auth context\n const setupAuth = useContext(setupAuthContext);\n const userId = setupAuth?.user?.id;\n\n // Query to fetch all user metadata\n const metadataQuery = useQuery(supabase.schema(\"core\").from(\"UserMetadata\").select(UserMetadataQuery.defaultQuery).eq(\"userId\", userId!).order(\"key\"), {\n enabled: isUsable(userId),\n crossOrganization: true\n });\n\n // Upsert mutation for updating metadata\n const upsertMutation = useUpsert(\"UserMetadata\", {\n invalidateTables: [\"UserMetadata\"]\n });\n\n // Ref to hold mutation to avoid infinite loops in useCallback dependencies\n const upsertMutationRef = useRef(upsertMutation);\n upsertMutationRef.current = upsertMutation;\n\n // Update local state when query data changes\n useEffect(() => {\n if (metadataQuery.data) {\n const metadataMap: Record<string, string> = {};\n metadataQuery.data.forEach((item: any) => {\n metadataMap[item.key] = item.value;\n });\n setMetadataState(metadataMap);\n setIsLoading(false);\n setError(null);\n } else if (metadataQuery.error) {\n setError(metadataQuery.error);\n setIsLoading(false);\n } else if (metadataQuery.isLoading) {\n setIsLoading(true);\n }\n }, [metadataQuery.data, metadataQuery.error, metadataQuery.isLoading]);\n\n // Set metadata function\n const setMetadata = useCallback(async (key: string, value: string) => {\n if (!userId) {\n throw new Error(\"User not authenticated\");\n }\n try {\n await upsertMutationRef.current.mutateAsync({\n userId,\n key,\n value\n });\n\n // Update local state optimistically\n setMetadataState(prev => ({\n ...prev,\n [key]: value\n }));\n } catch (err) {\n setError(err as Error);\n throw err;\n }\n }, [userId]);\n\n // Get metadata function\n const getMetadata = useCallback((key_0: string): string | undefined => {\n return metadata[key_0];\n }, [metadata]);\n\n // Remove metadata function\n const removeMetadata = useCallback(async (key_1: string) => {\n if (!userId) {\n throw new Error(\"User not authenticated\");\n }\n try {\n await supabase.schema(\"core\").from(\"UserMetadata\").delete().eq(\"userId\", userId).eq(\"key\", key_1);\n\n // Update local state\n setMetadataState(prev_0 => {\n const newState = {\n ...prev_0\n };\n delete newState[key_1];\n return newState;\n });\n } catch (err_0) {\n setError(err_0 as Error);\n throw err_0;\n }\n }, [userId, supabase]);\n\n // Refresh metadata function\n const refreshMetadata = useCallback(async () => {\n await metadataQuery.refetch();\n }, [metadataQuery]);\n\n // Context value\n const contextValue = useMemo(() => ({\n metadata,\n isLoading,\n error,\n setMetadata,\n getMetadata,\n removeMetadata,\n refreshMetadata\n }), [metadata, isLoading, error, setMetadata, getMetadata, removeMetadata, refreshMetadata]);\n return <userMetadataContext.Provider value={contextValue}>\n {children}\n </userMetadataContext.Provider>;\n}\n\n// Hook to use the context\nexport function useUserMetadata() {\n const context = useContext(userMetadataContext);\n if (!context) {\n throw new Error(\"useUserMetadata must be used within a UserMetadataProvider\");\n }\n return context;\n}\n\n// Convenience hook for getting a specific metadata value\nexport function useUserMetadataValue(key) {\n const $ = _c(3);\n const {\n getMetadata\n } = useUserMetadata();\n let t0;\n if ($[0] !== getMetadata || $[1] !== key) {\n t0 = getMetadata(key);\n $[0] = getMetadata;\n $[1] = key;\n $[2] = t0;\n } else {\n t0 = $[2];\n }\n return t0;\n}\n\n// Convenience hook for setting a specific metadata value\nexport function useSetUserMetadata() {\n const $ = _c(3);\n const {\n setMetadata,\n removeMetadata\n } = useUserMetadata();\n let t0;\n if ($[0] !== removeMetadata || $[1] !== setMetadata) {\n t0 = {\n setMetadata,\n removeMetadata\n };\n $[0] = removeMetadata;\n $[1] = setMetadata;\n $[2] = t0;\n } else {\n t0 = $[2];\n }\n return t0;\n}\n\n// Advanced state-like hook with JSON serialization support\nexport function useUserMetadataState(key, defaultValue, options) {\n const $ = _c(11);\n const {\n metadata,\n setMetadata,\n isLoading\n } = useUserMetadata();\n const serialize = options?.serialize ?? _temp;\n const deserialize = options?.deserialize ?? _temp2;\n let t0;\n bb0: {\n const rawValue = metadata[key];\n if (!rawValue) {\n t0 = defaultValue;\n break bb0;\n }\n ;\n try {\n let t2;\n if ($[0] !== deserialize || $[1] !== rawValue) {\n t2 = deserialize(rawValue);\n $[0] = deserialize;\n $[1] = rawValue;\n $[2] = t2;\n } else {\n t2 = $[2];\n }\n t0 = t2;\n } catch (t1) {\n const error = t1;\n console.warn(`Failed to deserialize metadata for key \"${key}\":`, error);\n t0 = defaultValue;\n }\n }\n const currentValue = t0;\n let t1;\n if ($[3] !== key || $[4] !== serialize || $[5] !== setMetadata) {\n t1 = async value_1 => {\n const serializedValue = serialize(value_1);\n await setMetadata(key, serializedValue);\n };\n $[3] = key;\n $[4] = serialize;\n $[5] = setMetadata;\n $[6] = t1;\n } else {\n t1 = $[6];\n }\n const setValue = t1;\n let t2;\n if ($[7] !== currentValue || $[8] !== isLoading || $[9] !== setValue) {\n t2 = [currentValue, setValue, isLoading];\n $[7] = currentValue;\n $[8] = isLoading;\n $[9] = setValue;\n $[10] = t2;\n } else {\n t2 = $[10];\n }\n return t2;\n}\nfunction _temp2(value_0) {\n return JSON.parse(value_0);\n}\nfunction _temp(value) {\n return JSON.stringify(value);\n}"],"mappings":"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","names":["createContext","useMemo","useRef","jsx","createContext","useRef","useMemo","useCallback","useEffect","useMemo","useRef","useState","jsx","useState","useEffect","useCallback","useRef","useMemo","_c","createContext","useContext","useEffect","useMemo","useState","useCallback","useRef","jsx","createContext","useState","useContext","useRef","useEffect","useCallback","useMemo","_c","t2","t1"]}
@@ -596,6 +596,28 @@ var SQLBuilder = class {
596
596
  params: [id]
597
597
  };
598
598
  }
599
+ /**
600
+ * Build an UPSERT query (INSERT OR REPLACE).
601
+ *
602
+ * @param table - Table name
603
+ * @param data - Record data to upsert
604
+ * @param idColumn - Name of the ID column (defaults to "id")
605
+ * @returns Built query
606
+ */
607
+ buildUpsertQuery(table, data, idColumn = "id") {
608
+ const columns = Object.keys(data).filter((k) => data[k] !== void 0);
609
+ const values = columns.map((k) => data[k]);
610
+ if (columns.length === 0) {
611
+ throw new Error("Cannot upsert empty record");
612
+ }
613
+ const columnList = columns.map((c) => `"${c}"`).join(", ");
614
+ const placeholders = columns.map(() => "?").join(", ");
615
+ const sql = `INSERT OR REPLACE INTO "${table}" (${columnList}) VALUES (${placeholders})`;
616
+ return {
617
+ sql,
618
+ params: values
619
+ };
620
+ }
599
621
  /**
600
622
  * Build a COUNT query.
601
623
  *
@@ -851,6 +873,10 @@ var QueryExecutor = class {
851
873
  resolver;
852
874
  builder;
853
875
  joiner;
876
+ /**
877
+ * Cache for resolved relationships to avoid repeated schema lookups
878
+ */
879
+ relationCache = /* @__PURE__ */ new Map();
854
880
  /**
855
881
  * Execute a query and return results.
856
882
  *
@@ -912,7 +938,7 @@ var QueryExecutor = class {
912
938
  *
913
939
  * @param table - The table to insert into
914
940
  * @param data - The record data
915
- * @returns The inserted record (re-fetched to get defaults)
941
+ * @returns The inserted record
916
942
  */
917
943
  async insert(table, data) {
918
944
  if (__DEV__) {
@@ -947,22 +973,14 @@ var QueryExecutor = class {
947
973
  });
948
974
  }
949
975
  await this.db.execute(query.sql, query.params);
950
- if (__DEV__) {
951
- console.log(`[QueryExecutor] insert SQL executed successfully:`, {
952
- table,
953
- id: data[idColumn]
954
- });
955
- }
956
- const result = await this.executeById(table, data[idColumn]);
957
976
  if (__DEV__) {
958
977
  console.log(`[QueryExecutor] insert completed:`, {
959
978
  table,
960
979
  operation: "insert",
961
- resultId: result?.[idColumn] ?? data[idColumn],
962
- refetchSucceeded: result !== null
980
+ id: data[idColumn]
963
981
  });
964
982
  }
965
- return result ?? data;
983
+ return data;
966
984
  }
967
985
  /**
968
986
  * Update a record.
@@ -991,24 +1009,13 @@ var QueryExecutor = class {
991
1009
  });
992
1010
  }
993
1011
  await this.db.execute(query.sql, query.params);
994
- if (__DEV__) {
995
- console.log(`[QueryExecutor] update SQL executed successfully:`, {
996
- table,
997
- id
998
- });
999
- }
1000
- const result = await this.executeById(table, id);
1001
1012
  if (__DEV__) {
1002
1013
  console.log(`[QueryExecutor] update completed:`, {
1003
1014
  table,
1004
1015
  operation: "update",
1005
- id,
1006
- refetchSucceeded: result !== null
1016
+ id
1007
1017
  });
1008
1018
  }
1009
- if (result) {
1010
- return result;
1011
- }
1012
1019
  return {
1013
1020
  ...data,
1014
1021
  [idColumn]: id
@@ -1048,19 +1055,23 @@ var QueryExecutor = class {
1048
1055
  });
1049
1056
  }
1050
1057
  }
1051
- const existing = await this.executeById(table, id);
1058
+ const query = this.builder.buildUpsertQuery(table, data, idColumn);
1052
1059
  if (__DEV__) {
1053
- console.log(`[QueryExecutor] upsert existence check:`, {
1060
+ console.log(`[QueryExecutor] upsert executing SQL:`, {
1054
1061
  table,
1055
- id,
1056
- exists: existing !== null,
1057
- willPerform: existing ? "update" : "insert"
1062
+ sql: query.sql,
1063
+ paramCount: query.params.length
1058
1064
  });
1059
1065
  }
1060
- if (existing) {
1061
- return this.update(table, id, data);
1066
+ await this.db.execute(query.sql, query.params);
1067
+ if (__DEV__) {
1068
+ console.log(`[QueryExecutor] upsert completed:`, {
1069
+ table,
1070
+ operation: "upsert",
1071
+ id
1072
+ });
1062
1073
  }
1063
- return this.insert(table, data);
1074
+ return data;
1064
1075
  }
1065
1076
  /**
1066
1077
  * Delete a record.
@@ -1082,8 +1093,15 @@ var QueryExecutor = class {
1082
1093
  * @returns Parent records with relations attached
1083
1094
  */
1084
1095
  async queryAndJoinRelations(parentTable, parentRecords, relations) {
1096
+ const idCache = /* @__PURE__ */ new Map();
1097
+ const getIdsForColumn = (column) => {
1098
+ if (!idCache.has(column)) {
1099
+ idCache.set(column, this.joiner.extractUniqueValues(parentRecords, column));
1100
+ }
1101
+ return idCache.get(column);
1102
+ };
1085
1103
  const relationResults = await Promise.all(relations.map(async (relation) => {
1086
- const resolved = this.resolver.resolve(parentTable, relation.name);
1104
+ const resolved = this.resolveRelationCached(parentTable, relation.name);
1087
1105
  if (!resolved) {
1088
1106
  console.warn(`Could not resolve relationship: ${parentTable} -> ${relation.name}`);
1089
1107
  return {
@@ -1092,7 +1110,8 @@ var QueryExecutor = class {
1092
1110
  records: []
1093
1111
  };
1094
1112
  }
1095
- const parentIds = this.getParentIdsForRelation(parentRecords, resolved);
1113
+ const idColumn = resolved.type === "one-to-many" ? resolved.referencedColumn : resolved.foreignKey;
1114
+ const parentIds = getIdsForColumn(idColumn);
1096
1115
  if (parentIds.length === 0) {
1097
1116
  return {
1098
1117
  relation,
@@ -1173,6 +1192,20 @@ var QueryExecutor = class {
1173
1192
  getJoiner() {
1174
1193
  return this.joiner;
1175
1194
  }
1195
+ /**
1196
+ * Resolve a relationship with caching.
1197
+ *
1198
+ * @param fromTable - The source table
1199
+ * @param toTable - The target table/relation name
1200
+ * @returns Resolved relationship or null
1201
+ */
1202
+ resolveRelationCached(fromTable, toTable) {
1203
+ const key = `${fromTable}:${toTable}`;
1204
+ if (!this.relationCache.has(key)) {
1205
+ this.relationCache.set(key, this.resolver.resolve(fromTable, toTable));
1206
+ }
1207
+ return this.relationCache.get(key);
1208
+ }
1176
1209
  };
1177
1210
  function createQueryExecutor(db, schema) {
1178
1211
  return new QueryExecutor(db, schema);
@@ -1195,4 +1228,4 @@ export {
1195
1228
  QueryExecutor,
1196
1229
  createQueryExecutor
1197
1230
  };
1198
- //# sourceMappingURL=chunk-BXSOHOQ2.js.map
1231
+ //# sourceMappingURL=chunk-CNIGRBRE.js.map