@seedprotocol/react 0.4.15 → 0.4.17
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/SeedImage.d.ts.map +1 -1
- package/dist/index.js +566 -555
- package/dist/index.js.map +1 -1
- package/dist/itemProperty.d.ts.map +1 -1
- package/dist/liveQuery.d.ts.map +1 -1
- package/package.json +8 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/client.ts","../src/liveQuery.ts","../src/item.ts","../src/itemProperty.ts","../src/services.ts","../src/db.ts","../src/schema.ts","../src/model.ts","../src/modelProperty.ts","../src/trash.ts","../src/useImageFiles.ts","../src/useFiles.ts","../src/queryClient.ts","../src/SeedProvider.tsx","../src/SeedClientGate.tsx","../src/useOPFSFiles.ts","../src/OPFSFilesManager.tsx","../src/SeedImage.tsx"],"sourcesContent":["import { ClientManagerState, getClient } from '@seedprotocol/sdk'\nimport { useSelector } from \"@xstate/react\"\n\n\nexport const useIsClientReady = () => {\n const client = getClient()\n\n const clientService = client.getService()\n\n const isClientReady = useSelector(clientService, (snapshot) => {\n return snapshot.value === ClientManagerState.IDLE\n })\n\n // GlobalState removed - check ClientManager state directly\n return isClientReady\n}","import { useEffect, useState, useRef, useMemo } from 'react'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { Observable } from 'rxjs'\nimport { useIsClientReady } from './client'\n\n/**\n * Hook to execute a reactive query that emits new results whenever the underlying data changes.\n * \n * Supports two usage patterns:\n * 1. SQL tag function: useLiveQuery((sql) => sql`SELECT * FROM models`)\n * 2. Drizzle query builder: useLiveQuery(db.select().from(models))\n * \n * @param query - SQL query function or Drizzle query builder, or null/undefined to disable the query\n * @returns Array of query results, or undefined if not yet loaded\n * \n * @example\n * ```typescript\n * // Using SQL tag function\n * const models = useLiveQuery<ModelRow>(\n * (sql) => sql`SELECT * FROM models WHERE schema_file_id = ${schemaId}`\n * )\n * \n * // Using Drizzle query builder\n * import { models } from '@seedprotocol/sdk'\n * import { eq } from 'drizzle-orm'\n * \n * const appDb = BaseDb.getAppDb()\n * const models = useLiveQuery<ModelRow>(\n * appDb.select().from(models).where(eq(models.schemaFileId, schemaId))\n * )\n * ```\n */\nexport function useLiveQuery<T>(\n query: ((sql: any) => any) | any | null | undefined\n): T[] | undefined {\n const [data, setData] = useState<T[] | undefined>(undefined)\n const subscriptionRef = useRef<{ unsubscribe: () => void } | null>(null)\n const previousDataRef = useRef<T[] | undefined>(undefined)\n const isClientReady = useIsClientReady()\n\n // Create Observable outside useEffect so it's stable and distinctUntilChanged can work\n // Only recreate when query or isClientReady changes\n const observable = useMemo(() => {\n if (!isClientReady || !query) {\n return null\n }\n try {\n return BaseDb.liveQuery<T>(query)\n } catch (error) {\n console.error('[useLiveQuery] Failed to create live query:', error)\n return null\n }\n }, [query, isClientReady])\n\n useEffect(() => {\n // Cleanup previous subscription if it exists\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n\n // Don't subscribe if observable is null\n if (!observable) {\n return\n }\n\n const subscription = observable.subscribe({\n next: (results) => {\n const prev = previousDataRef.current\n const prevJson = prev ? JSON.stringify(prev) : 'undefined'\n const currJson = results ? JSON.stringify(results) : 'undefined'\n const isSameValue = prevJson === currJson\n\n // Defensive check: don't update state if values are the same\n // This should be handled by distinctUntilChanged, but adding as safety\n // (especially important for Drizzle query builders which may not work with distinctUntilChanged)\n if (isSameValue && prev !== undefined) {\n return\n }\n\n previousDataRef.current = results\n setData(results)\n },\n error: (err) => {\n console.error('[useLiveQuery] Error:', err)\n // Don't set data to undefined on error - keep last known good state\n // This prevents UI flickering on transient errors\n },\n })\n\n subscriptionRef.current = subscription\n\n // Cleanup on unmount or observable change\n return () => {\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n }\n }, [observable]) // Only re-subscribe when observable changes\n\n return data\n}\n\n","import { useCallback, useEffect, useRef, useState, useMemo } from 'react'\nimport { flushSync } from 'react-dom'\nimport { createNewItem, getAddressesForItemsFilter, Item } from '@seedprotocol/sdk'\nimport { orderBy } from 'lodash-es'\nimport debug from 'debug'\nimport type { ModelValues } from '@seedprotocol/sdk'\nimport { Subscription } from 'xstate'\nimport type { IItem } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport { useLiveQuery } from './liveQuery'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { seeds } from '@seedprotocol/sdk'\nimport { and, eq, gt, inArray, isNotNull, isNull, or, sql } from 'drizzle-orm'\nimport { toSnakeCase } from 'drizzle-orm/casing'\nimport type { SeedType } from '@seedprotocol/sdk'\nimport { getVersionData } from '@seedprotocol/sdk'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\n\nconst logger = debug('seedSdk:react:item')\n\ntype UseItemReturn<T extends ModelValues<T>> = {\n item: IItem<T> | undefined\n isLoading: boolean\n error: Error | null\n}\n\ntype UseItemProps = {\n modelName: string\n seedLocalId?: string\n seedUid?: string\n}\n\ntype UseItem = <T extends ModelValues<T>>(props: UseItemProps) => UseItemReturn<T>\n\nexport const useItem: UseItem = <T extends ModelValues<T>>({ modelName, seedLocalId, seedUid }: UseItemProps) => {\n const [item, setItem] = useState<Item<T> | undefined>()\n const [isLoading, setIsLoading] = useState(!!(seedLocalId || seedUid))\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const hasSeenIdleRef = useRef(false)\n\n const isClientReady = useIsClientReady()\n\n const modelNameRef = useRef<string>(modelName)\n const seedLocalIdRef = useRef<string | undefined>(seedLocalId)\n const seedUidRef = useRef<string | undefined>(seedUid)\n\n // Determine if we should be loading based on parameters - use useMemo to stabilize\n // Use refs to check current values to avoid dependency issues\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n return !!(seedLocalIdRef.current || seedUidRef.current)\n }, [isClientReady, seedLocalId, seedUid])\n\n const loadItem = useCallback(async () => {\n // Check shouldLoad inside the function to avoid recreating the callback\n const currentShouldLoad = !!(isClientReady && (seedLocalIdRef.current || seedUidRef.current))\n if (!currentShouldLoad) {\n setItem(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n try {\n // Don't set isLoading here - let the subscription effect handle it\n // This avoids race conditions where isLoading is set to true but then\n // the subscription effect hasn't run yet to set it to false\n setError(null)\n\n const foundItem = await Item.find({\n modelName: modelNameRef.current,\n seedLocalId: seedLocalIdRef.current,\n seedUid: seedUidRef.current,\n }) as Item<T> | undefined\n\n if (!foundItem) {\n logger('[useItem] [loadItem] no item found', modelNameRef.current, seedLocalIdRef.current)\n // Don't clear item if we already have one for the same request (e.g. duplicate loadItem from effect re-run)\n setItem((prev) => {\n if (!prev) return undefined\n const match = (prev.seedLocalId && prev.seedLocalId === seedLocalIdRef.current) ||\n (prev.seedUid && prev.seedUid === seedUidRef.current)\n return match ? prev : undefined\n })\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Item.find() now waits for idle by default, so the item should be ready\n setItem(foundItem)\n setIsLoading(false) // Item is ready since find() waited for idle\n setError(null)\n } catch (error) {\n logger('[useItem] Error loading item:', error)\n setItem(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }, [isClientReady])\n\n useEffect(() => {\n modelNameRef.current = modelName\n seedLocalIdRef.current = seedLocalId\n seedUidRef.current = seedUid\n }, [modelName, seedLocalId, seedUid])\n\n // Fetch/refetch when parameters change or client becomes ready\n useEffect(() => {\n // Only clear item if we don't have parameters to load\n // Don't clear if shouldLoad is false but we have an item - it might just be a timing issue\n if (!shouldLoad) {\n // Only clear if we actually don't have parameters (not just client not ready)\n if (!seedLocalId && !seedUid) {\n setItem(undefined)\n setIsLoading(false)\n setError(null)\n }\n return\n }\n loadItem()\n }, [shouldLoad, loadItem, seedLocalId, seedUid])\n\n // Subscribe to service changes when item is available\n useEffect(() => {\n if (!item) {\n // Clean up subscription if item is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n hasSeenIdleRef.current = false\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n hasSeenIdleRef.current = false\n\n // Subscribe to service changes. Only set isLoading to true after we've seen idle at least\n // once, so we don't overwrite the ready state that loadItem() just set (find() waits for idle).\n const service = item.getService()\n\n const subscription = service.subscribe((snapshot: any) => {\n // Update loading state based on service state changes\n if (snapshot && typeof snapshot === 'object' && 'value' in snapshot) {\n const isIdle = snapshot.value === 'idle'\n if (isIdle) {\n hasSeenIdleRef.current = true\n setIsLoading(false)\n setError(null)\n } else if (snapshot.value === 'error') {\n setError(new Error('Item service error'))\n setIsLoading(false)\n } else {\n // Only show loading if we've already seen idle (real transition to loading)\n if (hasSeenIdleRef.current) {\n setIsLoading(true)\n }\n }\n }\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [item])\n\n return {\n item,\n isLoading,\n error,\n }\n}\n\ntype UseItemsReturn = {\n items: IItem<any>[]\n isLoading: boolean\n error: Error | null\n}\n\ntype UseItemsProps = {\n modelName?: string\n deleted?: boolean\n includeEas?: boolean\n addressFilter?: 'owned' | 'watched' | 'all'\n}\n\ntype UseItems = (props: UseItemsProps) => UseItemsReturn\n\nconst getItemsQueryKey = (\n modelName?: string,\n deleted?: boolean,\n includeEas?: boolean,\n addressFilter?: 'owned' | 'watched' | 'all'\n) => ['seed', 'items', modelName ?? null, deleted ?? false, includeEas ?? false, addressFilter ?? null] as const\n\nexport const useItems: UseItems = ({\n modelName,\n deleted = false,\n includeEas = false,\n addressFilter,\n}) => {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const previousSeedsTableDataRef = useRef<SeedType[] | undefined>(undefined)\n const itemsRef = useRef<IItem<any>[]>([])\n const lastFetchedIdsRef = useRef<Set<string>>(new Set())\n const [addressesForFilter, setAddressesForFilter] = useState<string[] | null>(null)\n\n useEffect(() => {\n if (addressFilter !== 'owned' && addressFilter !== 'watched') {\n setAddressesForFilter(null)\n return\n }\n let cancelled = false\n getAddressesForItemsFilter(addressFilter).then((addrs) => {\n if (!cancelled) setAddressesForFilter(addrs)\n })\n return () => {\n cancelled = true\n }\n }, [addressFilter])\n\n const queryKey = useMemo(\n () => getItemsQueryKey(modelName, deleted, includeEas, addressFilter),\n [modelName, deleted, includeEas, addressFilter],\n )\n\n const {\n data: items = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey,\n queryFn: () => Item.all(modelName, deleted, { waitForReady: true, includeEas, addressFilter }),\n enabled: isClientReady,\n })\n itemsRef.current = items\n\n // Watch the seeds table for changes\n const db = isClientReady ? BaseDb.getAppDb() : null\n const seedsQuery = useMemo(() => {\n if (!db) return null\n if (addressFilter === 'owned' || addressFilter === 'watched') {\n if (addressesForFilter === null) return null\n }\n const conditions: any[] = []\n if (!includeEas) {\n conditions.push(or(isNull(seeds.uid), eq(seeds.uid, '')) as any)\n }\n if (modelName) {\n conditions.push(eq(seeds.type, toSnakeCase(modelName)))\n }\n if (addressFilter === 'owned') {\n if (addressesForFilter && addressesForFilter.length > 0) {\n conditions.push(\n or(\n inArray(seeds.publisher, addressesForFilter),\n isNull(seeds.publisher)\n ) as any\n )\n }\n } else if (addressFilter === 'watched') {\n if (addressesForFilter && addressesForFilter.length > 0) {\n conditions.push(inArray(seeds.publisher, addressesForFilter) as any)\n } else {\n conditions.push(sql`1=0` as any)\n }\n }\n if (deleted) {\n conditions.push(\n or(\n isNotNull(seeds._markedForDeletion),\n eq(seeds._markedForDeletion, 1)\n ) as any\n )\n } else {\n conditions.push(\n or(\n isNull(seeds._markedForDeletion),\n eq(seeds._markedForDeletion, 0)\n ) as any\n )\n conditions.push(\n or(isNull(seeds.revokedAt), eq(seeds.revokedAt, 0)) as any\n )\n }\n const versionData = getVersionData()\n return db\n .with(versionData)\n .select({\n localId: seeds.localId,\n uid: seeds.uid,\n type: seeds.type,\n schemaUid: seeds.schemaUid,\n createdAt: seeds.createdAt,\n attestationCreatedAt: seeds.attestationCreatedAt,\n _markedForDeletion: seeds._markedForDeletion,\n })\n .from(seeds)\n .leftJoin(versionData, eq(seeds.localId, versionData.seedLocalId))\n .where(and(gt(versionData.versionsCount, 0), ...conditions))\n .groupBy(seeds.localId)\n }, [db, isClientReady, modelName, deleted, includeEas, addressFilter, addressesForFilter])\n const seedsTableData = useLiveQuery<SeedType>(seedsQuery)\n\n // Invalidate when table data actually changes so useQuery refetches\n useEffect(() => {\n if (!isClientReady || !seedsTableData) return\n\n const tableDataItemsSet = new Set<string>()\n for (const dbSeed of seedsTableData) {\n const key = dbSeed.localId || dbSeed.uid\n if (key) tableDataItemsSet.add(key)\n }\n\n const currentItemsSet = new Set<string>()\n for (const item of itemsRef.current) {\n const key = item.seedLocalId || item.seedUid\n if (key) currentItemsSet.add(key)\n }\n\n if (tableDataItemsSet.size === 0 && currentItemsSet.size > 0) return\n\n const lastFetched = lastFetchedIdsRef.current\n if (\n lastFetched.size === tableDataItemsSet.size &&\n [...lastFetched].every((id) => tableDataItemsSet.has(id))\n ) {\n return\n }\n\n previousSeedsTableDataRef.current = seedsTableData\n\n const setsAreEqual =\n currentItemsSet.size === tableDataItemsSet.size &&\n [...currentItemsSet].every((id) => tableDataItemsSet.has(id))\n\n if (setsAreEqual) {\n lastFetchedIdsRef.current = new Set(tableDataItemsSet)\n return\n }\n\n lastFetchedIdsRef.current = new Set(tableDataItemsSet)\n queryClient.invalidateQueries({ queryKey })\n }, [isClientReady, seedsTableData, queryClient, queryKey])\n\n return {\n items: orderBy(\n items,\n [\n (item) =>\n item.lastVersionPublishedAt ||\n item.attestationCreatedAt ||\n item.createdAt,\n ],\n ['desc'],\n ),\n isLoading,\n error: queryError as Error | null,\n }\n}\n\nexport type UseCreateItemReturn = {\n createItem: (modelName: string, itemData?: Record<string, any>) => Promise<Item<any> | undefined>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useCreateItem = (): UseCreateItemReturn => {\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const createItem = useCallback(\n async (modelName: string, itemData?: Record<string, any>): Promise<Item<any> | undefined> => {\n if (isLoading) {\n logger('[useCreateItem] [createItem] already creating item, skipping')\n return undefined\n }\n\n setError(null)\n // Flush loading=true synchronously so the UI (and tests) can observe it before async work runs.\n flushSync(() => setIsLoading(true))\n\n try {\n const data = itemData ?? {}\n const { seedLocalId } = await createNewItem({ modelName, ...data })\n const newItem = await Item.find({ modelName, seedLocalId })\n return (newItem ?? undefined) as Item<any> | undefined\n } catch (err) {\n logger('[useCreateItem] Error creating item:', err)\n setError(err instanceof Error ? err : new Error(String(err)))\n return undefined\n } finally {\n // Defer clearing loading so React can commit the loading=true render first.\n // Otherwise the test (or UI) may never observe isLoading true (same continuation batching).\n queueMicrotask(() => setIsLoading(false))\n }\n },\n [isLoading],\n )\n\n return {\n createItem,\n isLoading,\n error,\n resetError,\n }\n}\n\ntype UsePublishItemReturn = {\n publishItem: (item: Item<any> | undefined) => void\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const usePublishItem = (): UsePublishItemReturn => {\n const [publishingItem, setPublishingItem] = useState<Item<any> | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n\n const resetError = useCallback(() => setError(null), [])\n\n const publishItem = useCallback((item: Item<any> | undefined) => {\n if (!item) return\n setPublishingItem(item)\n setError(null)\n item.publish().catch(() => {\n // Error is surfaced via service state subscription; avoid unhandled rejection\n })\n }, [])\n\n useEffect(() => {\n if (!publishingItem) {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n setIsLoading(false)\n return\n }\n\n subscriptionRef.current?.unsubscribe()\n const service = publishingItem.getService()\n const subscription = service.subscribe((snapshot: any) => {\n const value = snapshot?.value\n const ctx = snapshot?.context\n setIsLoading(value === 'publishing')\n const publishError = ctx?._publishError\n setError(publishError ? new Error(publishError.message) : null)\n })\n\n subscriptionRef.current = subscription\n const snap = service.getSnapshot()\n setIsLoading(snap?.value === 'publishing')\n const ctx = snap?.context\n const publishError = ctx?._publishError\n setError(publishError ? new Error(publishError.message) : null)\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [publishingItem])\n\n return {\n publishItem,\n isLoading,\n error,\n resetError,\n }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Subscription, SnapshotFrom } from 'xstate'\nimport debug from 'debug'\nimport { ItemProperty } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport type { IItemProperty } from '@seedprotocol/sdk'\nimport { useLiveQuery } from './liveQuery'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { metadata } from '@seedprotocol/sdk'\nimport { seeds } from '@seedprotocol/sdk'\nimport { and, eq, isNotNull } from 'drizzle-orm'\nimport { getMetadataLatest } from '@seedprotocol/sdk'\nimport { propertyMachine } from '@seedprotocol/sdk'\nimport { debounce, startCase } from 'lodash-es'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\n\nconst logger = debug('seedSdk:react:property')\nconst propertiesLogger = debug('seedSdk:react:itemProperties')\n\ntype ItemPropertySnapshot = SnapshotFrom<typeof propertyMachine>\n\ntype UseItemPropertyReturn = {\n property: IItemProperty | undefined\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook to get a specific ItemProperty instance\n * Can be called in multiple ways:\n * 1. With seedLocalId/seedUid and propertyName: useItemProperty({ seedLocalId, propertyName }) or useItemProperty({ seedUid, propertyName })\n * 2. With itemId and propertyName: useItemProperty(itemId, propertyName) or useItemProperty({ itemId, propertyName })\n * \n * @overload\n * @param props - Object with seedLocalId or seedUid, and propertyName\n * @returns Object with property, isLoading, and error\n * \n * @overload\n * @param props - Object with itemId and propertyName\n * @returns Object with property, isLoading, and error\n * \n * @overload\n * @param itemId - The item ID (seedLocalId or seedUid)\n * @param propertyName - The name of the property\n * @returns Object with property, isLoading, and error\n */\nexport function useItemProperty(props: {\n seedLocalId?: string\n seedUid?: string\n propertyName: string\n}): UseItemPropertyReturn\nexport function useItemProperty(props: {\n itemId?: string\n propertyName: string\n}): UseItemPropertyReturn\nexport function useItemProperty(\n itemId: string,\n propertyName: string\n): UseItemPropertyReturn\nexport function useItemProperty(\n arg1:\n | { seedLocalId?: string; seedUid?: string; propertyName: string }\n | { itemId: string; propertyName: string }\n | string,\n arg2?: string\n) {\n const isClientReady = useIsClientReady()\n const [property, setProperty] = useState<IItemProperty | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [, setVersion] = useState(0) // Version counter to force re-renders\n\n // Extract primitives so useMemo/useCallback deps are stable when caller passes inline objects\n // Support object form with itemId: useItemProperty({ itemId, propertyName })\n const arg1IsObject = typeof arg1 === 'object' && arg1 != null\n const obj = arg1IsObject ? (arg1 as Record<string, unknown>) : null\n const itemIdFromObj = obj != null ? (obj.itemId as string | undefined) : undefined\n const seedLocalId =\n obj != null ? (obj.seedLocalId as string | undefined) : undefined\n const seedUid =\n obj != null ? (obj.seedUid as string | undefined) : undefined\n const propertyNameFromObj =\n obj != null ? (obj.propertyName as string | undefined) : undefined\n const itemId =\n typeof arg1 === 'string' ? arg1 : (itemIdFromObj !== undefined && itemIdFromObj !== '' ? itemIdFromObj : undefined)\n const propertyNameFromArgs = typeof arg1 === 'string' ? arg2 : undefined\n const propertyName = propertyNameFromObj ?? propertyNameFromArgs\n\n // Determine which lookup mode we're in based on arguments (deps are primitives to avoid infinite loop)\n // Unify itemId and identifiers: when itemId is provided (string or object form), use it as seedLocalId so we hit the same code path\n const lookupMode = useMemo(() => {\n const resolvedSeedLocalId = (itemId !== undefined && itemId !== '') ? itemId : seedLocalId\n const resolvedSeedUid = (itemId !== undefined && itemId !== '') ? undefined : seedUid\n if ((resolvedSeedLocalId != null || resolvedSeedUid != null) && propertyName != null && propertyName !== '') {\n return {\n type: 'identifiers' as const,\n seedLocalId: resolvedSeedLocalId ?? undefined,\n seedUid: resolvedSeedUid,\n propertyName,\n }\n }\n return null\n }, [itemId, propertyName, seedLocalId, seedUid])\n\n // Determine initial loading state\n const initialLoadingState = useMemo(() => {\n if (!lookupMode) return false\n return !!(\n (lookupMode.seedLocalId || lookupMode.seedUid) &&\n lookupMode.propertyName\n )\n }, [lookupMode])\n\n // Determine if we should be loading based on parameters\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n if (!lookupMode) return false\n return !!(\n (lookupMode.seedLocalId || lookupMode.seedUid) &&\n lookupMode.propertyName\n )\n }, [isClientReady, lookupMode])\n\n const updateItemProperty = useCallback(async () => {\n if (!isClientReady || !lookupMode) {\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n try {\n setIsLoading(true)\n setError(null)\n\n const seedLocalId = lookupMode.seedLocalId\n const seedUid = lookupMode.seedUid\n\n if (!seedLocalId && !seedUid) {\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n const foundProperty = await ItemProperty.find({\n propertyName: lookupMode.propertyName,\n seedLocalId,\n seedUid,\n })\n\n if (!foundProperty) {\n logger(\n `[useItemProperty] [updateItemProperty] no property found for Item.${seedLocalId || seedUid}.${lookupMode.propertyName}`,\n )\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // ItemProperty.find() now waits for idle by default, so the property should be ready\n setProperty(foundProperty)\n setIsLoading(false) // Property is ready since find() waited for idle\n setError(null)\n } catch (error) {\n logger('[useItemProperty] Error updating item property:', error)\n setProperty(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }, [isClientReady, lookupMode])\n\n // Fetch/refetch when lookup parameters change or client becomes ready.\n // Skip refetch when we already have the property for this lookup (avoids setting loading true\n // again when effect re-runs e.g. from Strict Mode or updateItemProperty identity change).\n // Match by the active identifier only: when looking up by seedLocalId both must match;\n // when looking up by seedUid both must match. Do not use (seedUid === undefined) as a match\n // when seedLocalIds differ, which would incorrectly skip refetch after seedLocalId change.\n useEffect(() => {\n if (!shouldLoad) {\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n const alreadyHavePropertyGuard =\n property &&\n lookupMode &&\n property.propertyName === lookupMode.propertyName &&\n ((lookupMode.seedLocalId != null && property.seedLocalId === lookupMode.seedLocalId) ||\n (lookupMode.seedUid != null && (property as any).seedUid === lookupMode.seedUid))\n if (alreadyHavePropertyGuard) return\n updateItemProperty()\n }, [shouldLoad, updateItemProperty, property, lookupMode])\n\n // Subscribe to service changes when property is available\n useEffect(() => {\n if (!property) {\n // Clean up subscription if property is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n // Subscribe to service changes. Only set isLoading to false when idle; never set to true\n // here so we never overwrite the loaded state when the machine emits any non-idle state\n // (e.g. loading, initializing, resolvingRelatedValue) after the initial fetch.\n let lastVersionAt = 0\n let wasIdle = false\n const THROTTLE_MS = 50\n const subscription = property.getService().subscribe((snapshot: any) => {\n const isIdle = snapshot && typeof snapshot === 'object' && 'value' in snapshot && snapshot.value === 'idle'\n if (isIdle) {\n setIsLoading(false)\n setError(null)\n // Only update when transitioning TO idle (not on every idle snapshot - machine emits many)\n if (!wasIdle) {\n wasIdle = true\n setVersion(prev => prev + 1)\n }\n return\n }\n wasIdle = false\n // Throttle re-renders during transitions: property machine emits many snapshots\n const now = Date.now()\n if (now - lastVersionAt >= THROTTLE_MS) {\n lastVersionAt = now\n setVersion(prev => prev + 1)\n }\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [property])\n\n return {\n property,\n isLoading,\n error,\n }\n}\n\ntype UseDebouncedItemPropertyParams =\n | { seedLocalId?: string; seedUid?: string; propertyName: string }\n | { itemId: string; propertyName: string }\n\ntype UseDebouncedItemPropertyReturn = {\n property: IItemProperty | undefined\n setValue: (value: string) => void\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook for real-time ItemProperty updates with debounced persistence.\n * Updates the display immediately on each change while debouncing writes to the database.\n * Use this for text inputs and other high-frequency updates.\n *\n * @param params - Same as useItemProperty: { seedLocalId, propertyName }, { seedUid, propertyName }, or { itemId, propertyName }\n * @param debounceMs - Debounce delay for persistence (default: 300)\n */\nexport function useDebouncedItemProperty(\n params: UseDebouncedItemPropertyParams,\n debounceMs = 300\n): UseDebouncedItemPropertyReturn {\n const itemId = 'itemId' in params ? params.itemId : undefined\n const seedLocalId = 'seedLocalId' in params ? params.seedLocalId : undefined\n const seedUid = 'seedUid' in params ? params.seedUid : undefined\n const propertyName = params.propertyName\n\n const normalizedParams = useMemo(() => {\n if (itemId) {\n return { seedLocalId: itemId, propertyName }\n }\n return { seedLocalId, seedUid, propertyName }\n }, [itemId, seedLocalId, seedUid, propertyName])\n\n const { property, isLoading, error } = useItemProperty(normalizedParams)\n const latestValueRef = useRef<string>('')\n\n const debouncedPersist = useMemo(\n () =>\n debounce((prop: IItemProperty) => {\n prop.getService().send({\n type: 'save',\n newValue: latestValueRef.current,\n })\n }, debounceMs),\n [debounceMs]\n )\n\n useEffect(() => {\n return () => debouncedPersist.cancel()\n }, [debouncedPersist])\n\n const setValue = useCallback(\n (value: string) => {\n if (!property) return\n latestValueRef.current = value\n property.getService().send({\n type: 'updateContext',\n propertyValue: value,\n renderValue: value,\n })\n debouncedPersist(property)\n },\n [property, debouncedPersist]\n )\n\n return {\n property,\n setValue,\n isLoading,\n error,\n }\n}\n\ntype UseItemPropertiesReturn = {\n properties: IItemProperty[]\n isLoading: boolean\n error: Error | null\n}\n\n/** Fetches item properties list for useQuery (shared with useItemProperties). */\nasync function fetchItemPropertiesList(\n seedLocalId: string | undefined,\n seedUid: string | undefined\n): Promise<IItemProperty[]> {\n if (!seedLocalId && !seedUid) return []\n const db = BaseDb.getAppDb()\n if (!db) return []\n\n const baseList = await ItemProperty.all(\n { seedLocalId: seedLocalId ?? undefined, seedUid: seedUid ?? undefined },\n { waitForReady: true },\n )\n const _itemProperties: IItemProperty[] = [...(baseList as IItemProperty[])]\n\n const propertiesWithMetadata = new Set<string>()\n for (const p of baseList) {\n if (p.propertyName) propertiesWithMetadata.add(p.propertyName)\n }\n\n let modelName: string | undefined\n if (baseList.length > 0) {\n const first = baseList[0]\n modelName = first.modelName ?? (first as any).modelType\n if (modelName && typeof modelName === 'string') modelName = startCase(modelName)\n }\n if (!modelName) {\n const seedRecords = await db\n .select({ type: seeds.type })\n .from(seeds)\n .where(seedUid ? eq(seeds.uid, seedUid) : eq(seeds.localId, seedLocalId!))\n .limit(1)\n if (seedRecords.length > 0 && seedRecords[0].type) {\n modelName = startCase(seedRecords[0].type)\n }\n }\n\n const modelProperties: string[] = []\n if (modelName) {\n try {\n const { Model } = await import('@seedprotocol/sdk')\n const model = await Model.getByNameAsync(modelName)\n if (model?.properties) {\n for (const modelProperty of model.properties) {\n if (modelProperty.name) modelProperties.push(modelProperty.name)\n }\n }\n } catch (error) {\n propertiesLogger(`[useItemProperties] Error getting ModelProperties for ${modelName}:`, error)\n }\n }\n\n if (modelName && modelProperties.length > 0) {\n const resolvedSeedLocalId = baseList.length > 0 ? (baseList[0].seedLocalId ?? seedLocalId) : seedLocalId\n const resolvedSeedUid = baseList.length > 0 ? (baseList[0].seedUid ?? seedUid) : seedUid\n for (const propertyName of modelProperties) {\n if (propertiesWithMetadata.has(propertyName)) continue\n try {\n const itemProperty = ItemProperty.create(\n {\n propertyName,\n modelName,\n seedLocalId: resolvedSeedLocalId || undefined,\n seedUid: resolvedSeedUid || undefined,\n propertyValue: null,\n },\n { waitForReady: false },\n )\n if (itemProperty) _itemProperties.push(itemProperty as any as IItemProperty)\n } catch (error) {\n logger(`[useItemProperties] Error creating ItemProperty for missing property ${propertyName}:`, error)\n }\n }\n }\n\n if (seedLocalId || seedUid) {\n const seedRecords = await db\n .select({ createdAt: seeds.createdAt })\n .from(seeds)\n .where(seedUid ? eq(seeds.uid, seedUid) : eq(seeds.localId, seedLocalId!))\n .limit(1)\n if (seedRecords.length > 0 && seedRecords[0].createdAt) {\n const createdAtPropertyName = 'createdAt'\n const hasCreatedAtProperty = _itemProperties.some((p) => p.propertyName === createdAtPropertyName)\n if (!hasCreatedAtProperty && modelName) {\n try {\n const resolvedSeedLocalId = baseList.length > 0 ? (baseList[0].seedLocalId ?? seedLocalId) : seedLocalId\n const resolvedSeedUid = baseList.length > 0 ? (baseList[0].seedUid ?? seedUid) : seedUid\n const createdAtProperty = ItemProperty.create(\n {\n propertyName: createdAtPropertyName,\n modelName,\n seedLocalId: resolvedSeedLocalId || undefined,\n seedUid: resolvedSeedUid || undefined,\n propertyValue: seedRecords[0].createdAt.toString(),\n },\n { waitForReady: false },\n )\n if (createdAtProperty) _itemProperties.push(createdAtProperty as any as IItemProperty)\n } catch (error) {\n logger(`[useItemProperties] Error creating createdAt ItemProperty:`, error)\n }\n }\n }\n }\n\n return _itemProperties\n}\n\n/**\n * Hook to get all ItemProperty instances for a specific item\n * Can be called in multiple ways:\n * 1. With seedLocalId: useItemProperties({ seedLocalId })\n * 2. With seedUid: useItemProperties({ seedUid })\n * 3. With itemId: useItemProperties(itemId)\n * \n * Uses useLiveQuery to watch for changes in the metadata table and automatically\n * updates the returned ItemProperty instances when changes occur.\n * \n * @overload\n * @param props - Object with seedLocalId or seedUid\n * @returns Object with properties array, isLoading, and error\n * \n * @overload\n * @param itemId - The item ID (seedLocalId or seedUid)\n * @returns Object with properties array, isLoading, and error\n */\nexport function useItemProperties(props: {\n seedLocalId?: string\n seedUid?: string\n}): UseItemPropertiesReturn\nexport function useItemProperties(itemId: string): UseItemPropertiesReturn\nexport function useItemProperties(\n arg1: { seedLocalId?: string; seedUid?: string } | string\n): UseItemPropertiesReturn {\n\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const previousTableDataRef = useRef<string | undefined>(undefined)\n\n // Determine which lookup mode we're in based on arguments\n const lookupMode = useMemo(() => {\n if (typeof arg1 === 'string') {\n // String argument: itemId (assumed to be seedLocalId)\n return { type: 'itemId' as const, itemId: arg1 }\n } else if (typeof arg1 === 'object') {\n // Object argument: { seedLocalId/seedUid }\n return {\n type: 'identifiers' as const,\n seedLocalId: arg1.seedLocalId,\n seedUid: arg1.seedUid,\n }\n } else {\n return null\n }\n }, [arg1])\n\n // Determine seedLocalId and seedUid for query\n const seedLocalId = useMemo(() => {\n if (!lookupMode) return undefined\n if (lookupMode.type === 'itemId') {\n return lookupMode.itemId\n } else {\n return lookupMode.seedLocalId\n }\n }, [lookupMode])\n\n const seedUid = useMemo(() => {\n if (!lookupMode || lookupMode.type === 'itemId') return undefined\n return lookupMode.seedUid\n }, [lookupMode])\n\n const canonicalItemKey = seedLocalId ?? seedUid ?? ''\n const itemPropertiesQueryKey = useMemo(\n () => (['seed', 'itemProperties', canonicalItemKey] as const),\n [canonicalItemKey],\n )\n\n const {\n data: properties = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey: itemPropertiesQueryKey,\n queryFn: () => fetchItemPropertiesList(seedLocalId, seedUid),\n enabled: isClientReady && !!canonicalItemKey,\n })\n\n // Watch the metadata table for changes\n // Query metadata table directly and filter for latest records in JavaScript\n // This is simpler and works better with useLiveQuery than CTEs\n // Get db inside useMemo to avoid recreating query on each render\n // Drizzle query builders are new objects each time, but useMemo will only recreate\n // when dependencies change, which is what we want for reactive queries\n const propertiesQuery = useMemo(() => {\n if (!isClientReady || (!seedLocalId && !seedUid)) {\n propertiesLogger('[useItemProperties] Query: returning null (not ready or no identifiers)')\n return null\n }\n \n const db = BaseDb.getAppDb()\n if (!db) {\n propertiesLogger('[useItemProperties] Query: returning null (no db)')\n return null\n }\n \n propertiesLogger(`[useItemProperties] Query: creating query for seedLocalId=${seedLocalId}, seedUid=${seedUid}`)\n \n // Query metadata table directly - we'll filter for latest records in JavaScript\n const query = seedUid\n ? db\n .select({\n propertyName: metadata.propertyName,\n propertyValue: metadata.propertyValue,\n seedLocalId: metadata.seedLocalId,\n seedUid: metadata.seedUid,\n modelType: metadata.modelType,\n schemaUid: metadata.schemaUid,\n createdAt: metadata.createdAt,\n attestationCreatedAt: metadata.attestationCreatedAt,\n })\n .from(metadata)\n .where(\n and(\n eq(metadata.seedUid, seedUid),\n isNotNull(metadata.propertyName)\n )\n )\n : seedLocalId\n ? db\n .select({\n propertyName: metadata.propertyName,\n propertyValue: metadata.propertyValue,\n seedLocalId: metadata.seedLocalId,\n seedUid: metadata.seedUid,\n modelType: metadata.modelType,\n schemaUid: metadata.schemaUid,\n createdAt: metadata.createdAt,\n attestationCreatedAt: metadata.attestationCreatedAt,\n })\n .from(metadata)\n .where(\n and(\n eq(metadata.seedLocalId, seedLocalId),\n isNotNull(metadata.propertyName)\n )\n )\n : null\n \n propertiesLogger(`[useItemProperties] Query: created query object`, { queryType: seedUid ? 'seedUid' : 'seedLocalId' })\n return query\n }, [isClientReady, seedLocalId, seedUid])\n \n const rawPropertiesTableData = useLiveQuery<{\n propertyName: string | null\n propertyValue: string | null\n seedLocalId: string | null\n seedUid: string | null\n modelType: string | null\n schemaUid: string | null\n createdAt: number | null\n attestationCreatedAt: number | null\n }>(propertiesQuery)\n \n // Filter for latest records (one per propertyName) in JavaScript\n const propertiesTableData = useMemo(() => {\n if (!rawPropertiesTableData || rawPropertiesTableData.length === 0) {\n return []\n }\n\n // Group by propertyName and keep only the latest record for each\n const latestByProperty = new Map<string, typeof rawPropertiesTableData[0]>()\n \n for (const record of rawPropertiesTableData) {\n if (!record.propertyName) continue\n \n const existing = latestByProperty.get(record.propertyName)\n if (!existing) {\n latestByProperty.set(record.propertyName, record)\n } else {\n // Compare timestamps to find the latest\n const existingTime = existing.attestationCreatedAt || existing.createdAt || 0\n const currentTime = record.attestationCreatedAt || record.createdAt || 0\n if (currentTime > existingTime) {\n latestByProperty.set(record.propertyName, record)\n }\n }\n }\n\n return Array.from(latestByProperty.values())\n }, [rawPropertiesTableData])\n\n // Invalidate when metadata table data actually changes so useQuery refetches\n useEffect(() => {\n if (!isClientReady || (!seedLocalId && !seedUid) || propertiesTableData === undefined) return\n\n // Include propertyValue so value-only changes produce a different string and trigger invalidation\n const tableDataString = JSON.stringify(\n propertiesTableData\n .map((p) => ({\n propertyName: p.propertyName,\n propertyValue: p.propertyValue,\n seedLocalId: p.seedLocalId,\n seedUid: p.seedUid,\n }))\n .sort((a, b) => (a.propertyName || '').localeCompare(b.propertyName || ''))\n )\n\n if (previousTableDataRef.current === tableDataString) return\n previousTableDataRef.current = tableDataString\n\n // Invalidate when metadata table data changed (new/updated/removed props or value changes)\n // so useQuery refetches and UI shows latest values.\n if (propertiesTableData.length > 0) {\n queryClient.invalidateQueries({ queryKey: itemPropertiesQueryKey })\n }\n }, [isClientReady, propertiesTableData, properties, seedLocalId, seedUid, queryClient, itemPropertiesQueryKey])\n\n useEffect(() => {\n previousTableDataRef.current = undefined\n }, [seedLocalId, seedUid])\n\n return {\n properties,\n isLoading,\n error: queryError as Error | null,\n }\n}\n\nexport type UseCreateItemPropertyProps = {\n seedLocalId?: string\n seedUid?: string\n propertyName: string\n modelName: string\n propertyValue?: any\n versionLocalId?: string\n versionUid?: string\n [key: string]: any\n}\n\nexport type UseCreateItemPropertyReturn = {\n create: (props: UseCreateItemPropertyProps) => IItemProperty | undefined\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\n/**\n * Hook to create an ItemProperty with loading and error state.\n * create(props) creates a new property instance for an item; provide seedLocalId or seedUid, propertyName, and modelName.\n */\nexport const useCreateItemProperty = (): UseCreateItemPropertyReturn => {\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const create = useCallback((props: UseCreateItemPropertyProps): IItemProperty | undefined => {\n if (!props.propertyName || (!props.seedLocalId && !props.seedUid) || !props.modelName) {\n const err = new Error('seedLocalId or seedUid, propertyName, and modelName are required')\n setError(err)\n return undefined\n }\n\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n\n const instance = ItemProperty.create(props, { waitForReady: false })\n if (!instance) {\n setError(new Error('Failed to create item property'))\n setIsLoading(false)\n return undefined\n }\n\n const subscription = instance.getService().subscribe((snapshot: any) => {\n if (snapshot?.value === 'error') {\n const err = (snapshot.context as any)?._loadingError?.error ?? new Error('Failed to create item property')\n setError(err instanceof Error ? err : new Error(String(err)))\n setIsLoading(false)\n }\n if (snapshot?.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return instance\n }, [])\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [])\n\n return {\n create,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroyItemPropertyReturn = {\n destroy: (itemProperty: IItemProperty) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroyItemProperty = (): UseDestroyItemPropertyReturn => {\n const [currentInstance, setCurrentInstance] = useState<IItemProperty | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot() as unknown as {\n context: { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n }\n const ctx = snap.context\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (itemProperty: IItemProperty) => {\n if (!itemProperty) return\n setCurrentInstance(itemProperty)\n await itemProperty.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}\n","import { useCallback, useEffect, useState } from 'react'\nimport { ActorRef, InspectedEventEvent } from 'xstate'\nimport { orderBy } from 'lodash-es'\nimport { produce } from 'immer'\nimport { eventEmitter } from '@seedprotocol/sdk'\nimport pluralize from 'pluralize'\nimport { useSelector } from '@xstate/react'\nimport debug from 'debug'\nimport { appState } from '@seedprotocol/sdk'\nimport { like } from 'drizzle-orm'\nimport { BaseDb, MachineIds, ClientManagerState, getClient } from '@seedprotocol/sdk'\n\nconst logger = debug('seedSdk:react:services')\n\nconst finalStrings = ['idle', 'ready', 'done', 'success', 'initialized']\n\nexport const getServiceName = (service: ActorRef<any, any>) => {\n let name = 'actor'\n const serviceAny = service as any\n if (service && serviceAny.uniqueKey) {\n name = serviceAny.uniqueKey\n }\n if (service && !serviceAny.uniqueKey && serviceAny.logic && serviceAny.logic.config) {\n name = getServiceUniqueKey(service)\n }\n return name\n}\n\nexport const getServiceValue = (\n service: ActorRef<any, any>,\n): string | undefined => {\n let value\n if (service && service.getSnapshot() && service.getSnapshot().value) {\n value = service.getSnapshot().value\n }\n if (getServiceName(service) === 'global') {\n if (\n value &&\n typeof value === 'object' &&\n Object.keys(value).length > 0 &&\n Object.keys(value)[0] === 'initialized'\n ) {\n value = 'ready'\n }\n }\n if (value && typeof value === 'object') {\n value = JSON.stringify(value)\n }\n return value\n}\n\nexport const getServiceUniqueKey = (service: ActorRef<any, any>) => {\n const serviceAny = service as any\n if (!service || !serviceAny.logic || !serviceAny.logic.config || !serviceAny._snapshot) {\n return\n }\n const config = serviceAny.logic.config\n if (!config.id) {\n return\n }\n let uniqueKey = config.id\n if (config.id.includes('@seedSdk/')) {\n uniqueKey = config.id.match(/^.*@seedSdk\\/(\\w+)[\\.\\w]*/)[1]\n }\n let snapshot\n try {\n snapshot = service.getSnapshot()\n } catch (error) {\n logger('Error:', error)\n return uniqueKey\n }\n if (snapshot) {\n const context = snapshot.context\n if (context && context.dbName) {\n uniqueKey = context.dbName\n }\n if (context && context.modelNamePlural) {\n uniqueKey = context.modelNamePlural\n }\n if (context && context.modelName) {\n uniqueKey = pluralize(context.modelName.toLowerCase())\n }\n }\n return uniqueKey\n}\n\nexport const useService = (service: ActorRef<any, any>) => {\n const [timeElapsed, setTimeElapsed] = useState(0)\n\n const getPercentComplete = (service: ActorRef<any, any>) => {\n let percentComplete = 0\n const serviceAny = service as any\n if (serviceAny.logic?.states) {\n const stateNames: string[] = []\n const startupStates: any[] = []\n\n for (const [stateName, state] of Object.entries(serviceAny.logic.states)) {\n const stateTyped = state as { tags?: string[] }\n if (stateTyped.tags?.includes('loading')) {\n stateNames.push(stateName)\n startupStates.push(state)\n }\n }\n\n const totalStates = startupStates.length\n const value = getServiceValue(service)\n if (value && finalStrings.includes(value)) {\n return 0\n }\n if (value) {\n const stateIndex = stateNames.indexOf(value)\n percentComplete = (stateIndex / totalStates) * 100\n }\n }\n return percentComplete\n }\n\n const updateTime = useCallback(\n (interval: ReturnType<typeof setInterval>) => {\n const context = service.getSnapshot().context\n const status = service.getSnapshot().value\n if (\n status === 'done' ||\n status === 'success' ||\n status === 'idle' ||\n status === 'ready'\n ) {\n clearInterval(interval)\n return\n }\n setTimeElapsed((timeElapsed) => timeElapsed + 1)\n },\n [service],\n )\n\n const startInterval = useCallback(() => {\n const interval = setInterval(() => {\n updateTime(interval)\n }, 1000)\n return interval\n }, [updateTime, service])\n\n useEffect(() => {\n const interval = startInterval()\n return () => clearInterval(interval)\n }, [])\n\n return {\n name: getServiceName(service),\n timeElapsed,\n value: getServiceValue(service),\n percentComplete: getPercentComplete(service),\n uniqueKey: getServiceUniqueKey(service),\n }\n}\n\nexport const useIsDbReady = () => {\n const [isDbReady, setIsDbReady] = useState(false)\n\n const { internalStatus } = useGlobalServiceStatus()\n\n useEffect(() => {\n if (internalStatus === 'ready') {\n setIsDbReady(true)\n }\n }, [internalStatus])\n\n useEffect(() => {\n if (internalStatus === 'ready') {\n setIsDbReady(true)\n }\n }, [])\n \n\n return isDbReady\n}\n\nexport const usePersistedSnapshots = () => {\n const [initialized, setInitialized] = useState(false)\n\n const hasSavedSnapshots = useHasSavedSnapshots()\n\n const { services, percentComplete } = useServices()\n\n // Helper function to save all actor snapshots to the database\n const save = useCallback(async () => {\n for (const actor of services) {\n const uniqueKey = getServiceUniqueKey(actor)\n logger(\n `would save to db with snapshot__${uniqueKey}:`,\n JSON.stringify(actor.getPersistedSnapshot()),\n )\n // await writeAppState(\n // `snapshot__${uniqueKey}`,\n // JSON.stringify(actor.getPersistedSnapshot()),\n // )\n }\n }, [services])\n\n // Helper function to load persisted snapshots from the database\n const load = useCallback(async () => {\n const appDb = BaseDb.getAppDb()\n\n if (!appDb) {\n return []\n }\n\n const persistedSnapshots = await appDb\n .select()\n .from(appState)\n .where(like(appState.key, 'snapshot__%'))\n return persistedSnapshots\n }, [])\n\n useEffect(() => {\n if (!hasSavedSnapshots || initialized) {\n return\n }\n const initialize = async () => {\n const persistedSnapshots = await load()\n logger('persistedSnapshots:', persistedSnapshots)\n setInitialized(true)\n }\n\n initialize()\n\n return () => {\n save() // Save snapshots on unmount\n }\n }, [hasSavedSnapshots, initialized])\n}\n\nexport const useHasSavedSnapshots = () => {\n const [hasSavedSnapshots, setHasSavedSnapshots] = useState(false)\n\n const isDbReady = useIsDbReady()\n\n useEffect(() => {\n if (isDbReady) {\n const _checkForSnapshots = async (): Promise<void> => {\n const appDb = BaseDb.getAppDb()\n\n const rows = await appDb\n .select()\n .from(appState)\n .where(like(appState.key, 'snapshot__%'))\n\n if (rows && rows.length > 0) {\n setHasSavedSnapshots(true)\n }\n }\n\n _checkForSnapshots()\n }\n }, [isDbReady])\n\n return hasSavedSnapshots\n}\n\nexport const useServices = () => {\n const [actors, setActors] = useState<ActorRef<any, any>[]>([])\n const [percentComplete, setPercentComplete] = useState(5)\n\n // Global service removed - now track ClientManager directly\n useEffect(() => {\n const clientManager = getClient()\n const clientService = clientManager.getService()\n \n // Add ClientManager to actors list\n const clientActor = clientService as any\n clientActor.uniqueKey = 'clientManager'\n \n setActors([clientActor])\n \n // Calculate percent complete based on ClientManager state\n const subscription = clientService.subscribe((snapshot) => {\n const state = snapshot.value\n // Calculate completion based on state progression\n let percent = 0\n if (state === ClientManagerState.IDLE) {\n percent = 100\n } else if (state === ClientManagerState.ADD_MODELS_TO_DB) {\n percent = 90\n } else if (state === ClientManagerState.ADD_MODELS_TO_STORE) {\n percent = 80\n } else if (state === ClientManagerState.PROCESS_SCHEMA_FILES) {\n percent = 70\n } else if (state === ClientManagerState.SAVE_CONFIG) {\n percent = 60\n } else if (state === ClientManagerState.DB_INIT) {\n percent = 50\n } else if (state === ClientManagerState.FILE_SYSTEM_INIT) {\n percent = 30\n } else if (state === ClientManagerState.PLATFORM_CLASSES_INIT) {\n percent = 10\n }\n setPercentComplete(percent)\n })\n \n return () => {\n subscription.unsubscribe()\n }\n }, [])\n\n return {\n services: actors,\n percentComplete,\n }\n}\n\nexport const useGlobalServiceStatus = () => {\n const clientManager = getClient()\n const clientService = clientManager.getService()\n\n const status = useSelector(clientService, (snapshot) => {\n return snapshot.value\n })\n\n // Internal service functionality is now part of ClientManager\n // DB is ready when ClientManager reaches DB_INIT or later states\n const internalStatus = useSelector(clientService, (snapshot) => {\n const state = snapshot.value\n if (state === ClientManagerState.DB_INIT || \n state === ClientManagerState.SAVE_CONFIG ||\n state === ClientManagerState.PROCESS_SCHEMA_FILES ||\n state === ClientManagerState.ADD_MODELS_TO_STORE ||\n state === ClientManagerState.ADD_MODELS_TO_DB ||\n state === ClientManagerState.IDLE) {\n return 'ready'\n }\n return state\n })\n\n return {\n status,\n internalStatus,\n }\n}\n","import { useCallback, useEffect, useState } from 'react'\nimport { Subscription } from 'xstate'\nimport { getClient, ClientManagerState } from '@seedprotocol/sdk'\nimport debug from 'debug'\n\nconst logger = debug('seedSdk:react:db')\n\nexport const useDbsAreReady = () => {\n const [dbsAreReady, setDbsAreReady] = useState(false)\n\n const update = useCallback(() => {\n if (dbsAreReady) {\n return\n }\n setDbsAreReady(true)\n }, [])\n\n useEffect(() => {\n let subscription: Subscription | undefined\n\n const _waitForDbs = async (): Promise<void> => {\n const clientManager = getClient()\n const clientService = clientManager.getService()\n \n const currentState = clientService.getSnapshot().value\n // DB is ready when ClientManager reaches DB_INIT state or later\n if (currentState === ClientManagerState.DB_INIT || \n currentState === ClientManagerState.SAVE_CONFIG ||\n currentState === ClientManagerState.PROCESS_SCHEMA_FILES ||\n currentState === ClientManagerState.ADD_MODELS_TO_STORE ||\n currentState === ClientManagerState.ADD_MODELS_TO_DB ||\n currentState === ClientManagerState.IDLE) {\n update()\n return\n }\n \n subscription = clientService.subscribe((snapshot) => {\n const state = snapshot.value\n if (state === ClientManagerState.DB_INIT || \n state === ClientManagerState.SAVE_CONFIG ||\n state === ClientManagerState.PROCESS_SCHEMA_FILES ||\n state === ClientManagerState.ADD_MODELS_TO_STORE ||\n state === ClientManagerState.ADD_MODELS_TO_DB ||\n state === ClientManagerState.IDLE) {\n update()\n subscription?.unsubscribe()\n }\n })\n }\n\n _waitForDbs()\n\n return () => {\n if (subscription) {\n subscription.unsubscribe()\n }\n }\n }, [])\n\n return {\n dbsAreReady,\n }\n}\n","import { loadAllSchemasFromDb } from '@seedprotocol/sdk'\nimport { useCallback, useEffect, useRef, useState, useMemo } from \"react\"\nimport { flushSync } from \"react-dom\"\nimport debug from \"debug\"\nimport { useIsClientReady } from \"./client\"\nimport { Schema } from '@seedprotocol/sdk'\nimport { SnapshotFrom, Subscription } from \"xstate\"\nimport { schemaMachine, SEED_PROTOCOL_SCHEMA_NAME } from '@seedprotocol/sdk'\nimport { useLiveQuery } from \"./liveQuery\"\nimport { BaseDb, schemas as schemasTable } from '@seedprotocol/sdk'\nimport { desc } from \"drizzle-orm\"\nimport type { SchemaType as DbSchemaType } from '@seedprotocol/sdk'\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\"\n\nconst logger = debug('seedSdk:react:schema')\n\n/**\n * Hook to get a Schema class instance (with setters) that is reactive\n * This allows you to edit schema properties directly like: schema.name = 'New name'\n * The schema instance uses a Proxy to ensure React re-renders when properties change\n * @param schemaIdentifier - The name of the schema or the schema file ID\n * - If a name is provided, retrieves the latest version with that name\n * - If an ID is provided, retrieves the specific schema by ID\n * @returns Object with schema instance\n */\nexport const useSchema = (schemaIdentifier: string | null | undefined) => {\n const [schema, setSchema] = useState<Schema | null>(null)\n const [isLoading, setIsLoading] = useState(schemaIdentifier ? true : false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | null>(null)\n\n const isClientReady = useIsClientReady()\n\n const loadSchema = useCallback((identifier: string) => {\n setIsLoading(true)\n setError(null)\n try {\n const schemaInstance = Schema.create(identifier, {\n waitForReady: false,\n }) as Schema\n setSchema(schemaInstance)\n\n const service = schemaInstance.getService()\n const initialSnapshot = service.getSnapshot()\n\n // Set initial loading state based on whether status is 'idle'\n const isIdle = initialSnapshot.value === 'idle'\n if (isIdle) {\n flushSync(() => setIsLoading(false))\n setError(null)\n } else {\n setIsLoading(true)\n }\n\n // Subscribe to all status changes and update isLoading based on whether status is 'idle'\n subscriptionRef.current = service.subscribe((snapshot: SchemaSnapshot) => {\n const isIdle = snapshot.value === 'idle'\n if (isIdle) {\n flushSync(() => setIsLoading(false))\n setError(null)\n } else {\n setIsLoading(true)\n }\n })\n\n } catch (error) {\n logger('[useSchema] Error creating schema:', error)\n setError(error as Error)\n setSchema(null)\n setIsLoading(false)\n return null\n }\n }, [])\n\n useEffect(() => {\n // Clean up previous subscription before starting a new load\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n \n if (!isClientReady) {\n setSchema(null)\n setError(null)\n setIsLoading(false)\n return\n }\n if (!schemaIdentifier) {\n setSchema(null)\n setError(null)\n setIsLoading(false)\n return\n }\n\n loadSchema(schemaIdentifier)\n \n // Cleanup function to unsubscribe when effect re-runs or component unmounts\n return () => {\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n }\n }, [schemaIdentifier, isClientReady, loadSchema])\n \n return {\n schema,\n isLoading,\n error,\n }\n\n}\n\nconst SEED_SCHEMAS_QUERY_KEY = ['seed', 'schemas'] as const\n\nexport const useSchemas = () => {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const previousSchemasTableDataRef = useRef<DbSchemaType[] | undefined>(undefined)\n const schemasRef = useRef<Schema[]>([])\n\n const {\n data: schemas = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey: SEED_SCHEMAS_QUERY_KEY,\n queryFn: () => Schema.all({ waitForReady: true }),\n enabled: isClientReady,\n })\n schemasRef.current = schemas\n\n // Watch the schemas table for changes and invalidate so useQuery refetches\n const db = isClientReady ? BaseDb.getAppDb() : null\n const schemasQuery = useMemo(() => {\n if (!db) return null\n return db.select().from(schemasTable).orderBy(schemasTable.name, desc(schemasTable.version))\n }, [db, isClientReady])\n const schemasTableData = useLiveQuery<DbSchemaType>(schemasQuery)\n\n // When a schema is created, addSchemaToDb posts to this channel; live query often doesn't re-run when schemas table is inserted.\n useEffect(() => {\n if (typeof BroadcastChannel === 'undefined') return\n const ch = new BroadcastChannel('seed-schemas-invalidate')\n const onMessage = () => {\n queryClient.invalidateQueries({ queryKey: SEED_SCHEMAS_QUERY_KEY })\n }\n ch.addEventListener('message', onMessage)\n return () => {\n ch.removeEventListener('message', onMessage)\n ch.close()\n }\n }, [queryClient])\n\n useEffect(() => {\n if (!isClientReady || !schemasTableData) {\n return\n }\n\n const prevData = previousSchemasTableDataRef.current\n const prevDataJson = prevData ? JSON.stringify(prevData) : 'undefined'\n const currDataJson = schemasTableData ? JSON.stringify(schemasTableData) : 'undefined'\n\n if (prevDataJson === currDataJson && prevData !== undefined) {\n return\n }\n\n previousSchemasTableDataRef.current = schemasTableData\n\n const currentSchemasSet = new Set<string>()\n for (const schema of schemasRef.current) {\n const schemaFileId = schema.id || schema.schemaFileId\n if (schemaFileId) {\n currentSchemasSet.add(schemaFileId)\n } else {\n const name = schema.metadata?.name\n const version = schema.version\n if (name && version !== undefined) {\n currentSchemasSet.add(`${name}:${version}`)\n }\n }\n }\n\n const tableDataSchemasSet = new Set<string>()\n for (const dbSchema of schemasTableData) {\n if (dbSchema.name === 'Seed Protocol') continue\n if (dbSchema.schemaFileId) {\n tableDataSchemasSet.add(dbSchema.schemaFileId)\n } else if (dbSchema.name != null && dbSchema.version !== undefined) {\n tableDataSchemasSet.add(`${dbSchema.name}:${dbSchema.version}`)\n }\n }\n\n const setsAreEqual =\n currentSchemasSet.size === tableDataSchemasSet.size &&\n [...currentSchemasSet].every((id) => tableDataSchemasSet.has(id))\n\n // Only invalidate when we have data and the table has rows we might be missing (live query saw new data).\n // Skip during initial load (currentSchemasSet empty) to avoid disrupting loading state.\n // Do NOT invalidate when we have more than the table: the live query may not have updated\n // yet, and refetching could overwrite cache with stale/empty data.\n const tableHasNewRows =\n currentSchemasSet.size > 0 &&\n tableDataSchemasSet.size > 0 &&\n [...tableDataSchemasSet].some((id) => !currentSchemasSet.has(id))\n\n if (!setsAreEqual && tableHasNewRows) {\n queryClient.invalidateQueries({ queryKey: SEED_SCHEMAS_QUERY_KEY })\n }\n }, [isClientReady, schemasTableData, queryClient])\n\n return {\n schemas,\n isLoading,\n error: queryError as Error | null,\n }\n}\n\nexport const useCreateSchema = () => {\n const subscriptionRef = useRef<{ unsubscribe: () => void } | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const createSchema = useCallback((schemaName: string) => {\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = null\n const schema = Schema.create(schemaName, {\n waitForReady: false,\n }) as Schema\n const subscription = schema.getService().subscribe((snapshot: SchemaSnapshot) => {\n if (snapshot.value === 'error') {\n const err = snapshot.context._loadingError?.error\n setError(err instanceof Error ? err : new Error('Failed to create schema'))\n setIsLoading(false)\n }\n if (snapshot.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return schema\n }, [])\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = null\n }\n }, [])\n\n return {\n createSchema,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroySchemaReturn = {\n destroy: (schema: Schema) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroySchema = (): UseDestroySchemaReturn => {\n const [currentInstance, setCurrentInstance] = useState<Schema | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (schema: Schema) => {\n if (!schema) return\n setCurrentInstance(schema)\n await schema.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}\n\nexport const useAllSchemaVersions = () => {\n const [schemaInstances, setSchemaInstances] = useState<Schema[] | undefined | null>()\n const schemaInstancesRef = useRef<Map<string, Schema>>(new Map())\n const isClientReady = useIsClientReady()\n\n const fetchSchemas = useCallback(async () => {\n if (!isClientReady) {\n return\n }\n\n try {\n // Use DB-first approach: load all schemas from database\n // This will also import any missing schemas from files\n const allSchemasData = await loadAllSchemasFromDb()\n\n // Extract unique schema names\n const schemaNames = new Set<string>()\n for (const schemaData of allSchemasData) {\n const schemaName = schemaData.schema.metadata?.name\n if (schemaName) {\n schemaNames.add(schemaName)\n }\n }\n\n // Create/update Schema instances\n const currentInstances = new Map<string, Schema>()\n \n for (const schemaName of schemaNames) {\n // Reuse existing instance if it exists\n if (schemaInstancesRef.current.has(schemaName)) {\n const existingInstance = schemaInstancesRef.current.get(schemaName)!\n currentInstances.set(schemaName, existingInstance)\n } else {\n // Create new instance\n const schema = Schema.create(schemaName, {\n waitForReady: false,\n }) as Schema\n currentInstances.set(schemaName, schema)\n }\n }\n\n // Cleanup instances that are no longer needed\n for (const [name, instance] of schemaInstancesRef.current.entries()) {\n if (!schemaNames.has(name)) {\n instance.unload()\n }\n }\n\n // Update ref and state\n schemaInstancesRef.current = currentInstances\n setSchemaInstances(Array.from(currentInstances.values()))\n } catch (error) {\n logger('Error fetching all schema versions from database:', error)\n setSchemaInstances(null)\n }\n }, [isClientReady])\n\n useEffect(() => {\n if (!isClientReady) {\n return\n }\n fetchSchemas()\n }, [isClientReady, fetchSchemas])\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n schemaInstancesRef.current.forEach((instance) => {\n instance.unload()\n })\n schemaInstancesRef.current.clear()\n }\n }, [])\n\n return schemaInstances\n}\n\ntype SchemaSnapshot = SnapshotFrom<typeof schemaMachine>\n\n\n/**\n * Hook to get the internal Seed Protocol schema (SDK-only schema)\n * This schema is managed by the SDK and should not be edited by app developers\n * @returns Object with schema instance and schemaData (version, metadata, etc.)\n */\nexport const useSeedProtocolSchema = () => {\n return useSchema(SEED_PROTOCOL_SCHEMA_NAME)\n}","import { useMemo, useState, useEffect, useCallback, useRef } from 'react'\nimport { Model } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport { useLiveQuery } from './liveQuery'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { models as modelsTable, modelSchemas, schemas as schemasTable } from '@seedprotocol/sdk'\nimport { eq, or } from 'drizzle-orm'\nimport { Subscription } from 'xstate'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\n\ntype UseModelsResult = {\n models: Model[]\n isLoading: boolean\n error: Error | null\n}\n\ntype UseModelsParams = string | null | undefined\n\ntype UseModels = (schemaId: UseModelsParams) => UseModelsResult\n\n/**\n * Hook to get all Model instances for a specific schema\n * Uses useLiveQuery to watch for changes in the models table and automatically\n * updates the returned Model instances when changes occur.\n * @param schemaId - The schema ID (schema file ID) or schema name to get models from\n * @returns Array of Model instances belonging to the schema\n */\nconst getModelsQueryKey = (schemaId: UseModelsParams) => ['seed', 'models', schemaId] as const\n\n// Last-known-good models per schemaId so we never flash [] after remount or refetch race (survives component unmount).\nconst lastModelsBySchemaId = new Map<string, Model[]>()\n\nexport const useModels: UseModels = (schemaId) => {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const modelsRef = useRef<Model[]>([])\n\n const queryKey = useMemo(() => getModelsQueryKey(schemaId), [schemaId])\n\n const {\n data: models = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey,\n queryFn: async () => {\n // Capture previous data before any async work so we don't overwrite good cache with [].\n const prev = queryClient.getQueryData<Model[]>(queryKey)\n // Use waitForReady: false so we return models as soon as they exist; waitForReady: true\n // filters to only idle models and can return [] while a model is in creatingProperties.\n const next = await Model.all(schemaId!, { waitForReady: false })\n // getModelsData can intermittently return [] after returning data; keep prev to avoid overwrite.\n if (Array.isArray(prev) && prev.length > 0 && Array.isArray(next) && next.length === 0) {\n return [...prev]\n }\n // If this refetch returned [], avoid overwriting non-empty cache (e.g. race where another refetch already wrote data).\n if (Array.isArray(next) && next.length === 0) {\n const current = queryClient.getQueryData<Model[]>(queryKey)\n if (Array.isArray(current) && current.length > 0) {\n return [...current]\n }\n }\n return next\n },\n enabled: isClientReady && !!schemaId,\n })\n // Never expose [] when we previously had models (avoids flash from refetch races, remounts, or intermittent getModelsData returning []).\n // When schemaId is null/undefined, always show [] — do not use fallback from a previous schema.\n const schemaIdKey = schemaId && typeof schemaId === 'string' ? schemaId : ''\n if (models.length > 0) {\n lastModelsBySchemaId.set(schemaIdKey, models)\n }\n const fallback = modelsRef.current.length > 0 ? modelsRef.current : lastModelsBySchemaId.get(schemaIdKey)\n const displayModels =\n !schemaId\n ? models\n : models.length > 0\n ? models\n : fallback?.length\n ? fallback\n : models\n modelsRef.current = displayModels\n\n // When a model is created, writeModelToDb posts to this channel; live query over join often doesn't re-run\n useEffect(() => {\n if (!schemaId || typeof BroadcastChannel === 'undefined') return\n const ch = new BroadcastChannel('seed-models-invalidate')\n const onMessage = (event: MessageEvent<{ schemaName?: string; schemaFileId?: string }>) => {\n const { schemaName, schemaFileId } = event.data || {}\n if (schemaId === schemaName || schemaId === schemaFileId) {\n queryClient.invalidateQueries({ queryKey })\n queryClient.refetchQueries({ queryKey })\n }\n }\n ch.addEventListener('message', onMessage)\n return () => {\n ch.removeEventListener('message', onMessage)\n ch.close()\n }\n }, [schemaId, queryClient, queryKey])\n\n // Stabilize query reference: only recreate when (schemaId, isClientReady) change, not when db reference changes.\n // This keeps the same liveQuery observable/subscription alive so effects can deliver updates when a new model is added.\n const stableModelsQueryKeyRef = useRef<{ schemaId: string; ready: boolean } | null>(null)\n const stableModelsQueryRef = useRef<ReturnType<typeof buildModelsQuery> | null>(null)\n function buildModelsQuery() {\n const currentDb = BaseDb.getAppDb()\n if (!currentDb || !schemaId) return null\n return currentDb\n .select({\n modelFileId: modelsTable.schemaFileId,\n modelName: modelsTable.name,\n })\n .from(schemasTable)\n .innerJoin(modelSchemas, eq(schemasTable.id, modelSchemas.schemaId))\n .innerJoin(modelsTable, eq(modelSchemas.modelId, modelsTable.id))\n .where(\n or(\n eq(schemasTable.schemaFileId, schemaId),\n eq(schemasTable.name, schemaId)\n )\n )\n }\n const modelsQuery = useMemo(() => {\n if (!schemaId || !isClientReady) return null\n const key = { schemaId, ready: isClientReady }\n const prevKey = stableModelsQueryKeyRef.current\n if (\n prevKey &&\n prevKey.schemaId === key.schemaId &&\n prevKey.ready === key.ready &&\n stableModelsQueryRef.current !== null\n ) {\n return stableModelsQueryRef.current\n }\n const q = buildModelsQuery()\n if (!q) return null\n stableModelsQueryKeyRef.current = key\n stableModelsQueryRef.current = q\n return q\n }, [schemaId, isClientReady])\n\n const modelsTableData = useLiveQuery<{ modelFileId: string | null; modelName: string }>(modelsQuery)\n\n useEffect(() => {\n if (!isClientReady || !modelsTableData || !schemaId) return\n\n const currentModelsSet = new Set<string>()\n for (const model of modelsRef.current) {\n const modelFileId = model.id || (model as any).modelFileId\n if (modelFileId) currentModelsSet.add(modelFileId)\n else if (model.modelName) currentModelsSet.add(model.modelName)\n }\n\n const tableDataModelsSet = new Set<string>()\n for (const dbModel of modelsTableData) {\n if (dbModel.modelFileId) tableDataModelsSet.add(dbModel.modelFileId)\n else if (dbModel.modelName) tableDataModelsSet.add(dbModel.modelName)\n }\n\n const setsAreEqual =\n currentModelsSet.size === tableDataModelsSet.size &&\n [...currentModelsSet].every((id) => tableDataModelsSet.has(id))\n\n // Only invalidate when the table has rows we might be missing (live query saw new data).\n // Do NOT invalidate when we have more than the table: the live query may not have updated\n // yet (e.g. join over model_schemas), and refetching would overwrite cache with [].\n const tableHasNewRows =\n tableDataModelsSet.size > 0 &&\n [...tableDataModelsSet].some((id) => !currentModelsSet.has(id))\n\n if (!setsAreEqual && tableHasNewRows) {\n queryClient.invalidateQueries({ queryKey })\n }\n }, [isClientReady, modelsTableData, schemaId, queryClient, queryKey])\n\n return {\n models: displayModels,\n isLoading,\n error: queryError as Error | null,\n }\n}\n\ntype UseModelResult = {\n model: Model | undefined\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook to get a specific Model instance\n * Can be called in two ways:\n * 1. With schemaId and modelName: useModel(schemaId, modelName)\n * 2. With modelId: useModel(modelId)\n * \n * @param schemaIdOrModelId - The schema ID (schema file ID) OR the model ID (modelFileId)\n * @param modelName - The name of the model to retrieve (required if first param is schemaId)\n * @returns Object with model, isLoading, and error\n */\nexport const useModel = (\n schemaIdOrModelId: string | null | undefined,\n modelName?: string | null | undefined\n): UseModelResult => {\n const isClientReady = useIsClientReady()\n const [model, setModel] = useState<Model | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [, setVersion] = useState(0) // Version counter to force re-renders\n\n // If modelName is provided, treat first param as schemaId\n // Otherwise, treat first param as modelId\n const isModelIdLookup = modelName === undefined || modelName === null\n\n // Determine initial loading state\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n if (isModelIdLookup) {\n return !!schemaIdOrModelId\n } else {\n return !!(schemaIdOrModelId && modelName)\n }\n }, [isClientReady, isModelIdLookup, schemaIdOrModelId, modelName])\n\n // Lookup model by ID if needed\n useEffect(() => {\n if (!isClientReady || !isModelIdLookup || !schemaIdOrModelId) {\n setModel(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n const lookupModelById = async () => {\n try {\n setIsLoading(true)\n setError(null)\n // Use Model.createById which handles cache + DB lookup\n const foundModel = await Model.createById(schemaIdOrModelId)\n setModel(foundModel || undefined)\n setIsLoading(false)\n setError(null)\n } catch (error) {\n console.error('[useModel] Error looking up model by ID:', error)\n setModel(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }\n\n lookupModelById()\n }, [isClientReady, isModelIdLookup, schemaIdOrModelId])\n\n // Subscribe to service changes when model is available (for modelId lookup)\n useEffect(() => {\n if (!isModelIdLookup || !model) {\n // Clean up subscription if model is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n // Subscribe to service changes\n const subscription = model.getService().subscribe((snapshot) => {\n // Force re-render by incrementing version counter\n setVersion(prev => prev + 1)\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [isModelIdLookup, model])\n\n // If doing modelId lookup, return the model directly\n if (isModelIdLookup) {\n return {\n model,\n isLoading,\n error,\n }\n }\n\n // Otherwise, use schemaId + modelName lookup via useModels\n const { models: modelsList, isLoading: modelsLoading, error: modelsError } = useModels(schemaIdOrModelId)\n const foundModel = useMemo(() => {\n if (!modelName) {\n return undefined\n }\n // Try both modelName property and name getter for compatibility\n return modelsList.find((m: Model) => {\n const mName = m.modelName ?? (m as any).name\n return mName === modelName\n })\n }, [modelsList, modelName])\n\n // Subscribe to service changes when model is available (for schemaId + modelName lookup)\n useEffect(() => {\n if (isModelIdLookup || !foundModel) {\n // Clean up subscription if model is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n // Subscribe to service changes\n const subscription = foundModel.getService().subscribe((snapshot) => {\n // Force re-render by incrementing version counter\n setVersion(prev => prev + 1)\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [isModelIdLookup, foundModel])\n\n // For schemaId + modelName lookup, derive loading/error from useModels\n return {\n model: foundModel,\n isLoading: modelsLoading,\n error: modelsError,\n }\n}\n\nexport type UseCreateModelOptions = {\n modelFileId?: string\n properties?: { [propertyName: string]: any }\n registerWithSchema?: boolean\n}\n\nexport type UseCreateModelReturn = {\n create: (\n schemaName: string,\n modelName: string,\n options?: UseCreateModelOptions\n ) => Model\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useCreateModel = (): UseCreateModelReturn => {\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const create = useCallback(\n (schemaName: string, modelName: string, options?: UseCreateModelOptions): Model => {\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n const model = Model.create(modelName, schemaName, {\n ...options,\n waitForReady: false,\n }) as Model\n const subscription = model.getService().subscribe((snapshot) => {\n if (snapshot.value === 'error') {\n setError(\n (snapshot.context as any)._loadingError?.error ??\n new Error('Failed to create model')\n )\n setIsLoading(false)\n }\n if (snapshot.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return model\n },\n []\n )\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [])\n\n return {\n create,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroyModelReturn = {\n destroy: (model: Model) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroyModel = (): UseDestroyModelReturn => {\n const [currentInstance, setCurrentInstance] = useState<Model | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (model: Model) => {\n if (!model) return\n setCurrentInstance(model)\n await model.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}","import { useModel } from \"./model\"\nimport { useCallback, useEffect, useRef, useState, useMemo } from \"react\"\nimport { flushSync } from \"react-dom\"\nimport { debounce } from \"lodash-es\"\nimport { getPropertySchema, ModelProperty } from '@seedprotocol/sdk'\nimport { useIsClientReady } from \"./client\"\nimport { Subscription } from \"xstate\"\nimport debug from \"debug\"\nimport { useLiveQuery } from \"./liveQuery\"\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { properties as propertiesTable, models as modelsTable } from '@seedprotocol/sdk'\nimport { eq } from \"drizzle-orm\"\nimport { Model } from '@seedprotocol/sdk'\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\"\nimport { getSchemaNameFromId } from '@seedprotocol/sdk'\n\nconst logger = debug('seedSdk:browser:react:modelProperty')\n\ntype UseModelPropertiesResult = {\n modelProperties: ModelProperty[]\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook to get all ModelProperty instances for a specific model\n * Can be called in two ways:\n * 1. With schemaId and modelName: useModelProperties(schemaId, modelName)\n * 2. With modelId: useModelProperties(modelId)\n * \n * Uses useLiveQuery to watch for changes in the properties table and automatically\n * updates the returned ModelProperty instances when changes occur.\n * \n * @param schemaIdOrModelId - The schema ID (schema file ID) OR the model ID (modelFileId)\n * @param modelName - The name of the model to get properties from (required if first param is schemaId)\n * @returns Object with modelProperties array, isLoading, and error\n */\nexport const useModelProperties = (\n schemaIdOrModelId: string | null | undefined,\n modelName?: string | null | undefined\n): UseModelPropertiesResult => {\n // Use useModel to handle both lookup patterns (by ID or by schemaId + modelName)\n const { model } = useModel(schemaIdOrModelId, modelName)\n \n // Determine the modelName for use in getPropertySchema\n const modelNameForProperty = useMemo(() => {\n if (!model) return undefined\n try {\n return model.modelName ?? (model as any).name\n } catch {\n return undefined\n }\n }, [model])\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n\n // Get _dbId (database ID) from model context\n const dbModelId = useMemo(() => {\n if (!model) return null\n try {\n const context = (model as any)._getSnapshotContext()\n return context._dbId as number | undefined\n } catch {\n return null\n }\n }, [model])\n\n const modelId = model?.id\n const modelPropertiesQueryKey = useMemo(\n () => ['seed', 'modelProperties', modelId ?? ''] as const,\n [modelId],\n )\n\n const {\n data: modelProperties = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey: modelPropertiesQueryKey,\n queryFn: () => ModelProperty.all(modelId!, { waitForReady: true }),\n enabled: isClientReady && !!modelId,\n })\n\n const db = isClientReady ? BaseDb.getAppDb() : null\n const propertiesQuery = useMemo(() => {\n if (!db || !dbModelId) return null\n return db\n .select({\n id: propertiesTable.id,\n name: propertiesTable.name,\n dataType: propertiesTable.dataType,\n schemaFileId: propertiesTable.schemaFileId,\n })\n .from(propertiesTable)\n .where(eq(propertiesTable.modelId, dbModelId))\n }, [db, isClientReady, dbModelId])\n const propertiesTableData = useLiveQuery<{ id: number; name: string; dataType: string; schemaFileId: string | null }>(propertiesQuery)\n\n const modelPropertiesRef = useRef<ModelProperty[]>([])\n modelPropertiesRef.current = modelProperties\n\n // Fallback: when we have modelId but query returned [] (e.g. properties not in DB yet or\n // propertiesTableData is undefined because model._dbId isn't set yet), schedule refetches\n // so we pick up properties after they're written.\n useEffect(() => {\n if (!modelId || modelProperties.length > 0 || !queryClient || !modelPropertiesQueryKey) return\n const delays = [400, 1200, 2500]\n const timers = delays.map((ms) =>\n setTimeout(() => {\n queryClient.invalidateQueries({ queryKey: modelPropertiesQueryKey })\n }, ms)\n )\n return () => timers.forEach((t) => clearTimeout(t))\n }, [modelId, modelProperties.length, queryClient, modelPropertiesQueryKey])\n\n useEffect(() => {\n if (!isClientReady || !model?.id || !propertiesTableData || !modelPropertiesQueryKey) return\n\n const currentPropertiesSet = new Set<string>()\n for (const prop of modelPropertiesRef.current) {\n const context = (prop as any)._getSnapshotContext()\n const propertyFileId = context?.id\n if (propertyFileId) currentPropertiesSet.add(propertyFileId)\n else if (prop.name) currentPropertiesSet.add(prop.name)\n }\n\n const tableDataPropertiesSet = new Set<string>()\n for (const dbProperty of propertiesTableData) {\n if (dbProperty.schemaFileId) tableDataPropertiesSet.add(dbProperty.schemaFileId)\n else if (dbProperty.name) tableDataPropertiesSet.add(dbProperty.name)\n }\n\n const setsAreEqual =\n currentPropertiesSet.size === tableDataPropertiesSet.size &&\n (currentPropertiesSet.size === 0 ||\n [...currentPropertiesSet].every((id) => tableDataPropertiesSet.has(id)))\n\n // Invalidate when cached list is out of sync with the table: either we have stale cached data\n // (currentPropertiesSet.size > 0) or the table has new rows we don't have yet (tableDataPropertiesSet.size > 0).\n // The latter handles the case where the initial query returned [] before properties were written.\n const shouldInvalidate =\n !setsAreEqual && (currentPropertiesSet.size > 0 || tableDataPropertiesSet.size > 0)\n\n if (shouldInvalidate) {\n queryClient.invalidateQueries({ queryKey: modelPropertiesQueryKey })\n }\n }, [isClientReady, propertiesTableData, model?.id, queryClient, modelPropertiesQueryKey])\n\n // When we have cached modelProperties, do not report isLoading: true even if the query\n // is refetching (e.g. after useModels refetch causes modelId to change briefly). UX expects\n // isLoading false once we have shown data.\n const effectiveIsLoading = isLoading && modelProperties.length === 0\n\n return {\n modelProperties,\n isLoading: effectiveIsLoading,\n error: queryError as Error | null,\n }\n}\n\n/**\n * Helper function to get property schema by modelFileId and propertyName\n */\nconst getPropertySchemaByModelFileId = async (\n modelFileId: string,\n propertyName: string\n): Promise<ReturnType<typeof getPropertySchema>> => {\n // Get model by modelFileId\n const model = await Model.createById(modelFileId)\n if (!model) {\n return undefined\n }\n\n // Get modelName from model\n const modelName = model.modelName ?? (model as any).name\n if (!modelName) {\n return undefined\n }\n\n // Use existing getPropertySchema function\n return getPropertySchema(modelName, propertyName)\n}\n\n/**\n * Hook to get a specific ModelProperty instance\n * Can be called in three ways:\n * 1. With propertyFileId: useModelProperty(propertyFileId)\n * 2. With modelFileId and propertyName: useModelProperty(modelFileId, propertyName)\n * 3. With schemaId, modelName, and propertyName: useModelProperty(schemaId, modelName, propertyName)\n * \n * @overload\n * @param propertyFileId - The property file ID (schemaFileId)\n * @returns Object with modelProperty, isLoading, and error\n * \n * @overload\n * @param modelFileId - The model file ID (modelFileId)\n * @param propertyName - The name of the property\n * @returns Object with modelProperty, isLoading, and error\n * \n * @overload\n * @param schemaId - The schema ID (schema file ID)\n * @param modelName - The name of the model\n * @param propertyName - The name of the property\n * @returns Object with modelProperty, isLoading, and error\n */\nexport function useModelProperty(propertyFileId: string): {\n modelProperty: ModelProperty | undefined\n isLoading: boolean\n error: Error | null\n}\nexport function useModelProperty(\n modelFileId: string,\n propertyName: string\n): {\n modelProperty: ModelProperty | undefined\n isLoading: boolean\n error: Error | null\n}\nexport function useModelProperty(\n schemaId: string,\n modelName: string,\n propertyName: string\n): {\n modelProperty: ModelProperty | undefined\n isLoading: boolean\n error: Error | null\n}\nexport function useModelProperty(\n arg1: string | null | undefined,\n arg2?: string | null | undefined,\n arg3?: string | null | undefined\n) {\n // Determine initial loading state - start loading if we have valid parameters\n const initialLoadingState = useMemo(() => {\n if (arg3 !== undefined && arg3 !== null) {\n // Three arguments: schemaId, modelName, propertyName\n return !!(arg1 && arg2 && arg3)\n } else if (arg2 !== undefined && arg2 !== null) {\n // Two arguments: modelFileId, propertyName\n return !!(arg1 && arg2)\n } else {\n // One argument: propertyFileId\n return !!arg1\n }\n }, [arg1, arg2, arg3])\n\n const [modelProperty, setModelProperty] = useState<ModelProperty | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(initialLoadingState)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n\n const isClientReady = useIsClientReady()\n\n // Determine which lookup mode we're in based on arguments\n const lookupMode = useMemo(() => {\n if (arg3 !== undefined && arg3 !== null) {\n // Three arguments: schemaId, modelName, propertyName\n return { type: 'schemaId' as const, schemaId: arg1, modelName: arg2, propertyName: arg3 }\n } else if (arg2 !== undefined && arg2 !== null) {\n // Two arguments: modelFileId, propertyName\n return { type: 'modelFileId' as const, modelFileId: arg1, propertyName: arg2 }\n } else {\n // One argument: propertyFileId\n return { type: 'propertyFileId' as const, propertyFileId: arg1 }\n }\n }, [arg1, arg2, arg3])\n\n // Determine if we should be loading based on parameters\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n if (lookupMode.type === 'propertyFileId') {\n return !!lookupMode.propertyFileId\n } else if (lookupMode.type === 'modelFileId') {\n return !!(lookupMode.modelFileId && lookupMode.propertyName)\n } else {\n return !!(lookupMode.schemaId && lookupMode.modelName && lookupMode.propertyName)\n }\n }, [isClientReady, lookupMode])\n\n const updateModelProperty = useCallback(async () => {\n if (!isClientReady) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n let propertyData: Awaited<ReturnType<typeof getPropertySchema>> | undefined\n let resolvedModelName: string | undefined\n\n try {\n setIsLoading(true)\n setError(null)\n\n if (lookupMode.type === 'propertyFileId') {\n if (!lookupMode.propertyFileId) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Use ModelProperty.createById for propertyFileId lookup\n const foundProperty = await ModelProperty.createById(lookupMode.propertyFileId)\n if (foundProperty) {\n setModelProperty(foundProperty)\n setIsLoading(false)\n setError(null)\n } else {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n }\n return\n } else if (lookupMode.type === 'modelFileId') {\n if (!lookupMode.modelFileId || !lookupMode.propertyName) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Get property schema by modelFileId and propertyName\n // This function already gets the model and resolves modelName\n propertyData = await getPropertySchemaByModelFileId(lookupMode.modelFileId, lookupMode.propertyName)\n \n // Get modelName from model (needed for ModelProperty.create)\n const model = await Model.createById(lookupMode.modelFileId)\n resolvedModelName = model?.modelName ?? (model as any)?.name\n } else {\n // lookupMode.type === 'schemaId'\n if (!lookupMode.schemaId || !lookupMode.modelName || !lookupMode.propertyName) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Use existing getPropertySchema for schemaId + modelName + propertyName\n propertyData = await getPropertySchema(lookupMode.modelName, lookupMode.propertyName)\n resolvedModelName = lookupMode.modelName\n }\n\n if (propertyData && resolvedModelName) {\n const createdProperty = ModelProperty.create(\n { ...propertyData, modelName: resolvedModelName },\n { waitForReady: false }\n )\n const resolvedProperty = createdProperty instanceof Promise ? await createdProperty : createdProperty\n flushSync(() => {\n setModelProperty(resolvedProperty)\n setIsLoading(false)\n setError(null)\n })\n } else {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n }\n } catch (error) {\n console.error('[useModelProperty] Error updating model property:', error)\n setModelProperty(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }, [isClientReady, lookupMode.type, lookupMode.propertyFileId, lookupMode.modelFileId, lookupMode.propertyName, lookupMode.schemaId, lookupMode.modelName])\n\n // Fetch/refetch when lookup parameters change or client becomes ready\n useEffect(() => {\n if (!shouldLoad) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n updateModelProperty()\n }, [shouldLoad, updateModelProperty])\n\n // Subscribe to service changes when modelProperty is available.\n // Skip subscription for schemaId/modelFileId lookups where we created the instance locally—\n // refetching on every snapshot would set loading and can race with the initial render.\n // Debounce to reduce refetch frequency and avoid updateContext/refetch loops.\n const shouldSubscribe = lookupMode.type === 'propertyFileId'\n useEffect(() => {\n if (!modelProperty || !shouldSubscribe) {\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n const debouncedUpdate = debounce(updateModelProperty, 100)\n\n // Subscribe to service changes\n const subscription = modelProperty.getService().subscribe(() => {\n debouncedUpdate()\n })\n\n subscriptionRef.current = subscription\n\n return () => {\n debouncedUpdate.cancel()\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [modelProperty, updateModelProperty, shouldSubscribe])\n\n return {\n modelProperty,\n isLoading,\n error,\n }\n}\n\nexport type UseCreateModelPropertyOptions = {\n name: string\n dataType: string\n [key: string]: any\n}\n\nexport type UseCreateModelPropertyReturn = {\n create: (\n schemaId: string,\n modelName: string,\n property: UseCreateModelPropertyOptions\n ) => ModelProperty\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\n/**\n * Hook to create a ModelProperty with loading and error state.\n * create(schemaId, modelName, property) creates a new property on the model.\n */\nexport const useCreateModelProperty = (): UseCreateModelPropertyReturn => {\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const create = useCallback(\n (\n schemaId: string,\n modelName: string,\n property: UseCreateModelPropertyOptions\n ): ModelProperty => {\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n\n if (!modelName || !property.name || !property.dataType) {\n const err = new Error('modelName, property name and dataType are required')\n setError(err)\n setIsLoading(false)\n throw err\n }\n\n // Resolve schema name: schemaId may be \"Blog-1\" (schemaName-version) or just \"Blog\"\n const schemaName = getSchemaNameFromId(schemaId) ?? schemaId\n\n const created = ModelProperty.create(\n { ...property, modelName } as Parameters<typeof ModelProperty.create>[0],\n { waitForReady: false, schemaName }\n ) as ModelProperty\n const subscription = created.getService().subscribe((snapshot) => {\n if ((snapshot as { value?: string }).value === 'error') {\n const err = (snapshot.context as any)._loadingError?.error ?? new Error('Failed to create model property')\n setError(err instanceof Error ? err : new Error(String(err)))\n setIsLoading(false)\n }\n if (snapshot.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return created\n },\n []\n )\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [])\n\n return {\n create,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroyModelPropertyReturn = {\n destroy: (modelProperty: ModelProperty) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroyModelProperty = (): UseDestroyModelPropertyReturn => {\n const [currentInstance, setCurrentInstance] = useState<ModelProperty | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (modelProperty: ModelProperty) => {\n if (!modelProperty) return\n setCurrentInstance(modelProperty)\n await modelProperty.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}","import { useCallback, useEffect, useState } from 'react'\nimport { Item } from '@seedprotocol/sdk'\n\nexport type UseDeleteItemReturn = {\n deleteItem: (item: Item<any>) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDeleteItem = (): UseDeleteItemReturn => {\n const [currentInstance, setCurrentInstance] = useState<Item<any> | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (item: Item<any>) => {\n if (!item) return\n setCurrentInstance(item)\n await item.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n deleteItem: destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}\n","import { useEffect } from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { BaseFileManager } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport { eventEmitter } from '@seedprotocol/sdk'\n\nconst IMAGE_FILES_QUERY_KEY = ['seed', 'imageFiles'] as const\n\n/**\n * Returns an up-to-date list of image filenames stored in the file system (OPFS in browser).\n * Automatically refetches when images are saved (file-saved) or after bulk downloads (fs.downloadAll.success).\n *\n * Must be used within SeedProvider and after client.init().\n *\n * @example\n * ```tsx\n * const { imageFiles, isLoading, error, refetch } = useImageFiles()\n * // imageFiles: ['photo.jpg', 'cover.png']\n * ```\n */\nexport function useImageFiles() {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n\n const {\n data: imageFiles = [],\n isLoading,\n error,\n refetch,\n } = useQuery({\n queryKey: IMAGE_FILES_QUERY_KEY,\n queryFn: () => BaseFileManager.listImageFiles(),\n enabled: isClientReady,\n })\n\n useEffect(() => {\n const fileSavedHandler = (filePath: string) => {\n if (filePath.includes('/images/')) {\n queryClient.invalidateQueries({ queryKey: IMAGE_FILES_QUERY_KEY })\n }\n }\n const downloadSuccessHandler = () => {\n queryClient.invalidateQueries({ queryKey: IMAGE_FILES_QUERY_KEY })\n }\n eventEmitter.on('file-saved', fileSavedHandler)\n eventEmitter.on('fs.downloadAll.success', downloadSuccessHandler)\n return () => {\n eventEmitter.off('file-saved', fileSavedHandler)\n eventEmitter.off('fs.downloadAll.success', downloadSuccessHandler)\n }\n }, [queryClient])\n\n return {\n imageFiles,\n isLoading,\n error: error instanceof Error ? error : null,\n refetch,\n }\n}\n","import { useEffect, useMemo } from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { BaseFileManager, eventEmitter } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\n\nexport const FILES_QUERY_KEY_PREFIX = ['seed', 'files'] as const\n\n/**\n * Returns an up-to-date list of filenames stored in the given directory.\n * Automatically refetches when files are saved (file-saved) or after bulk downloads (fs.downloadAll.success).\n *\n * Must be used within SeedProvider and after client.init().\n *\n * @param dir - Directory name under the files root (e.g. 'files', 'images'). Default: 'files'.\n *\n * @example\n * ```tsx\n * const { files, isLoading, error, refetch } = useFiles('files')\n * // files: ['document.pdf', 'contract.docx']\n * ```\n */\nexport function useFiles(dir: string = 'files') {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n\n const queryKey = useMemo(() => [...FILES_QUERY_KEY_PREFIX, dir] as const, [dir])\n\n const {\n data: files = [],\n isLoading,\n error,\n refetch,\n } = useQuery({\n queryKey,\n queryFn: () => BaseFileManager.listFiles(dir),\n enabled: isClientReady,\n })\n\n useEffect(() => {\n const fileSavedHandler = (filePath: string) => {\n if (filePath.includes(`/${dir}/`)) {\n queryClient.invalidateQueries({ queryKey })\n }\n }\n const downloadSuccessHandler = () => {\n queryClient.invalidateQueries({ queryKey })\n }\n eventEmitter.on('file-saved', fileSavedHandler)\n eventEmitter.on('fs.downloadAll.success', downloadSuccessHandler)\n return () => {\n eventEmitter.off('file-saved', fileSavedHandler)\n eventEmitter.off('fs.downloadAll.success', downloadSuccessHandler)\n }\n }, [queryClient, dir, queryKey])\n\n return {\n files,\n isLoading,\n error: error instanceof Error ? error : null,\n refetch,\n }\n}\n","import {\n type QueryClient,\n type DefaultOptions,\n QueryClient as ReactQueryClient,\n type QueryClientConfig,\n NetworkMode,\n} from '@tanstack/react-query'\n\nconst SEED_QUERY_DEFAULT_OPTIONS: DefaultOptions = {\n queries: {\n networkMode: 'offlineFirst' as NetworkMode,\n gcTime: 1000 * 60 * 60 * 24, // 24 hours\n staleTime: 1000 * 60, // 1 minute - list data can be slightly stale\n },\n}\n\n/**\n * Returns the default options used by Seed for list-query caching.\n * Use this when building your own QueryClient so Seed hooks get consistent behavior.\n */\nexport function getSeedQueryDefaultOptions(): DefaultOptions {\n return { ...SEED_QUERY_DEFAULT_OPTIONS }\n}\n\n/**\n * Merges Seed's default query options with your existing default options.\n * Your options take precedence over Seed's. Use when constructing your own QueryClient:\n *\n * @example\n * ```ts\n * const client = new QueryClient({\n * defaultOptions: mergeSeedQueryDefaults({\n * queries: { gcTime: 1000 * 60 * 60 },\n * }),\n * })\n * ```\n */\nexport function mergeSeedQueryDefaults(\n userOptions?: Partial<DefaultOptions> | null\n): DefaultOptions {\n const seed = getSeedQueryDefaultOptions()\n if (!userOptions) return seed\n return {\n queries: {\n ...seed.queries,\n ...(userOptions.queries ?? {}),\n },\n mutations: {\n ...(seed.mutations ?? {}),\n ...(userOptions.mutations ?? {}),\n },\n }\n}\n\n/**\n * Creates a QueryClient configured with Seed's default options.\n * Use this when you want to provide your own QueryClientProvider but still use Seed's defaults.\n *\n * @param overrides - Optional config to merge with Seed defaults (e.g. defaultOptions, logger).\n */\nexport function createSeedQueryClient(overrides?: Partial<QueryClientConfig>): QueryClient {\n const defaults = getSeedQueryDefaultOptions()\n const { defaultOptions: userDefaultOptions, ...restOverrides } = overrides ?? {}\n return new ReactQueryClient({\n ...restOverrides,\n defaultOptions: userDefaultOptions\n ? mergeSeedQueryDefaults(userDefaultOptions as DefaultOptions)\n : defaults,\n })\n}\n","import React, { type ReactNode, useMemo, useEffect } from 'react'\nimport { QueryClientProvider } from '@tanstack/react-query'\nimport type { QueryClient } from '@tanstack/react-query'\nimport { createSeedQueryClient } from './queryClient'\nimport { eventEmitter } from '@seedprotocol/sdk'\n\nexport type SeedProviderProps = {\n children: ReactNode\n /** Optional: use your own QueryClient. If not provided, a default client with Seed options is created. */\n queryClient?: QueryClient\n /** Optional: ref to receive the QueryClient instance (e.g. for tests). */\n queryClientRef?: React.MutableRefObject<QueryClient | null>\n}\n\ndeclare global {\n interface Window {\n __SEED_INVALIDATE_ITEM_PROPERTIES__?: ((canonicalId: string) => void) | null\n }\n}\n\n/** Module-level ref so invalidateItemPropertiesForItem works when test and app share the same bundle but not the same window (e.g. iframe). */\nlet invalidateItemPropertiesRef: ((canonicalId: string) => void | Promise<void>) | null = null\n\n/**\n * Invalidates and refetches the item-properties query for an item.\n * Call this after updating an ItemProperty (e.g. after save()) so useItemProperties\n * refetches and the UI updates. Returns a Promise that resolves when the refetch has completed (if available).\n */\nexport function invalidateItemPropertiesForItem(canonicalId: string): Promise<void> {\n const p1 = invalidateItemPropertiesRef?.(canonicalId)\n if (typeof window !== 'undefined' && window.__SEED_INVALIDATE_ITEM_PROPERTIES__) {\n window.__SEED_INVALIDATE_ITEM_PROPERTIES__(canonicalId)\n }\n return Promise.resolve(p1).then(() => {})\n}\n\nfunction SeedProviderEventSubscriber({ queryClient }: { queryClient: QueryClient }) {\n useEffect(() => {\n const invalidate = (canonicalId: string) => {\n const key: readonly [string, string, string] = ['seed', 'itemProperties', canonicalId]\n queryClient.invalidateQueries({ queryKey: key })\n return queryClient.refetchQueries({ queryKey: key })\n }\n invalidateItemPropertiesRef = invalidate\n if (typeof window !== 'undefined') {\n window.__SEED_INVALIDATE_ITEM_PROPERTIES__ = invalidate\n }\n const handler = (payload: { seedLocalId?: string; seedUid?: string }) => {\n const canonicalId = payload?.seedLocalId ?? payload?.seedUid\n if (canonicalId) {\n invalidate(canonicalId)\n }\n }\n eventEmitter.on('itemProperty.saved', handler)\n return () => {\n eventEmitter.off('itemProperty.saved', handler)\n invalidateItemPropertiesRef = null\n if (typeof window !== 'undefined') {\n window.__SEED_INVALIDATE_ITEM_PROPERTIES__ = null\n }\n }\n }, [queryClient])\n return null\n}\n\n/**\n * Provider that supplies a React Query client to Seed list hooks (useSchemas, useItems, useModels, etc.)\n * so results are cached and shared across components. Wrap your app (or the subtree that uses Seed hooks)\n * after calling client.init().\n *\n * - No props: uses an internal QueryClient with Seed defaults.\n * - queryClient prop: use your own client (e.g. merge getSeedQueryDefaultOptions when creating it).\n */\nexport function SeedProvider({ children, queryClient: queryClientProp, queryClientRef }: SeedProviderProps) {\n const queryClient = useMemo(\n () => queryClientProp ?? createSeedQueryClient(),\n [queryClientProp]\n )\n if (queryClientRef) {\n queryClientRef.current = queryClient\n if (typeof window !== 'undefined') {\n const w = window as { __TEST_SEED_QUERY_CLIENT__?: QueryClient }\n w.__TEST_SEED_QUERY_CLIENT__ = queryClient\n try {\n if (window.parent && window.parent !== window) (window.parent as { __TEST_SEED_QUERY_CLIENT__?: QueryClient }).__TEST_SEED_QUERY_CLIENT__ = queryClient\n } catch {\n // cross-origin frame, ignore\n }\n }\n }\n return (\n <QueryClientProvider client={queryClient}>\n <SeedProviderEventSubscriber queryClient={queryClient} />\n {children}\n </QueryClientProvider>\n )\n}\n","import React, { useEffect, type ReactNode } from 'react'\nimport { client } from '@seedprotocol/sdk'\nimport type { SeedConstructorOptions, SeedConfig, SchemaFileFormat } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\n\n/** Schema input: path string or SchemaFileFormat object. Merged into config.schema at init. */\ntype SchemaInput = string | SchemaFileFormat\n\nfunction DefaultLoading() {\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n width: '100%',\n }}\n >\n Loading...\n </div>\n )\n}\n\nexport type SeedClientGateProps = {\n /** Seed client init options (config + addresses). Required. */\n initConfig: SeedConstructorOptions\n /** Optional canonical schema. When provided, merged into config.schema and loaded at init (no separate import). */\n schema?: SchemaInput\n /** Custom loading UI. Default: simple centered \"Loading...\" text. */\n loadingComponent?: ReactNode\n /** @deprecated Schema is now loaded at init via config.schema; no separate import. Kept for backward compatibility. */\n onSchemaImportError?: (err: unknown) => void\n /** Class for the root wrapper. e.g. \"relative flex h-screen w-screen\" */\n wrapperClassName?: string\n /** Class for the loading overlay. e.g. \"absolute inset-0 z-50 flex items-center justify-center bg-zinc-950\" */\n loadingClassName?: string\n children: ReactNode\n}\n\n/**\n * Gates children until the Seed client is initialized and optionally imports a schema.\n * Mounted inside RouterProvider so we never swap the router—only the route content.\n * This avoids removeChild DOM errors and ensures QueryClientProvider stays stable.\n * Both overlay and content stay in DOM; we only toggle visibility via classes.\n */\nexport function SeedClientGate({\n initConfig,\n schema,\n loadingComponent,\n wrapperClassName,\n loadingClassName,\n children,\n}: SeedClientGateProps) {\n const isClientReady = useIsClientReady()\n\n useEffect(() => {\n const effectiveConfig: SeedConstructorOptions = schema\n ? {\n ...initConfig,\n config: {\n ...initConfig.config,\n schema,\n } as SeedConfig,\n }\n : initConfig\n client.init(effectiveConfig)\n }, [initConfig, schema])\n\n const loadingContent = loadingComponent ?? <DefaultLoading />\n\n const wrapperStyle = !wrapperClassName\n ? { position: 'relative' as const, display: 'flex' as const, height: '100vh', width: '100vw' }\n : undefined\n\n const overlayStyle: React.CSSProperties = {\n display: isClientReady ? 'none' : 'flex',\n ...(!loadingClassName && {\n position: 'absolute',\n inset: 0,\n zIndex: 50,\n alignItems: 'center',\n justifyContent: 'center',\n }),\n }\n\n const contentStyle: React.CSSProperties = {\n flex: 1,\n display: isClientReady ? 'flex' : 'none',\n flexDirection: 'column',\n }\n\n return (\n <div className={wrapperClassName} style={wrapperStyle}>\n <div\n className={loadingClassName}\n style={overlayStyle}\n aria-hidden={isClientReady}\n >\n {loadingContent}\n </div>\n <div style={contentStyle}>\n {children}\n </div>\n </div>\n )\n}\n","import { useState, useCallback, useEffect } from 'react'\n\nexport interface OPFSFile {\n name: string\n path: string\n size: number\n type: string\n lastModified: number\n}\n\nasync function scanDirectory(\n dirHandle: FileSystemDirectoryHandle,\n basePath: string = ''\n): Promise<OPFSFile[]> {\n const foundFiles: OPFSFile[] = []\n\n try {\n for await (const [name, handle] of dirHandle.entries()) {\n const currentPath = basePath ? `${basePath}/${name}` : name\n\n if (handle.kind === 'file') {\n try {\n const file = await (handle as FileSystemFileHandle).getFile()\n foundFiles.push({\n name,\n path: currentPath,\n size: file.size,\n type: file.type || 'application/octet-stream',\n lastModified: file.lastModified,\n })\n } catch (err) {\n console.warn(`Failed to read file ${currentPath}:`, err)\n }\n } else if (handle.kind === 'directory') {\n const subFiles = await scanDirectory(handle as FileSystemDirectoryHandle, currentPath)\n foundFiles.push(...subFiles)\n }\n }\n } catch (err) {\n console.warn(`Failed to scan directory ${basePath}:`, err)\n }\n\n return foundFiles\n}\n\nexport interface UseOPFSFilesOptions {\n /** Optional subdirectory to scan (e.g. 'app-files'). Default: root. */\n rootPath?: string\n}\n\n/**\n * Hook to scan and list all files in OPFS (Origin Private File System).\n * Uses navigator.storage.getDirectory() - works in browsers that support OPFS.\n *\n * @example\n * ```tsx\n * const { files, isLoading, error, refetch } = useOPFSFiles()\n * ```\n */\nexport function useOPFSFiles(options: UseOPFSFilesOptions = {}) {\n const { rootPath } = options\n const [files, setFiles] = useState<OPFSFile[]>([])\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n\n const load = useCallback(async () => {\n setIsLoading(true)\n setError(null)\n\n try {\n const root = await navigator.storage.getDirectory()\n let dirHandle: FileSystemDirectoryHandle = root\n\n if (rootPath) {\n const parts = rootPath.split('/').filter(Boolean)\n for (const part of parts) {\n dirHandle = await dirHandle.getDirectoryHandle(part)\n }\n }\n\n const allFiles = await scanDirectory(dirHandle, rootPath || '')\n setFiles(allFiles.sort((a, b) => a.path.localeCompare(b.path)))\n } catch (err) {\n setError(\n 'Failed to access OPFS: ' + (err instanceof Error ? err.message : String(err))\n )\n console.error('OPFS access error:', err)\n } finally {\n setIsLoading(false)\n }\n }, [rootPath])\n\n useEffect(() => {\n load()\n }, [load])\n\n return { files, isLoading, error, refetch: load }\n}\n","import React, { useState, useRef, useEffect } from 'react'\nimport { useOPFSFiles, type OPFSFile } from './useOPFSFiles'\n\n// Inline SVG icons to avoid external dependencies\nconst DownloadIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 20, height: 20 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3\" />\n </svg>\n)\nconst FolderIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 48, height: 48 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 12.75V12a2.25 2.25 0 012.25-2.25h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z\" />\n </svg>\n)\nconst DocumentIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 20, height: 20 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z\" />\n </svg>\n)\nconst TrashIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 20, height: 20 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0\" />\n </svg>\n)\nconst SpinnerIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{ width: 32, height: 32 }}\n aria-hidden\n >\n <circle\n style={{ opacity: 0.25 }}\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n style={{ opacity: 0.75 }}\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n)\n\nfunction formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 Bytes'\n const k = 1024\n const sizes = ['Bytes', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i]\n}\n\nfunction formatDate(timestamp: number): string {\n return new Date(timestamp).toLocaleString()\n}\n\nasync function getFileBlob(file: OPFSFile, root: FileSystemDirectoryHandle): Promise<Blob> {\n const pathParts = file.path.split('/').filter(Boolean)\n if (pathParts.length === 0) throw new Error('Invalid file path')\n\n let currentHandle: FileSystemDirectoryHandle = root\n for (let i = 0; i < pathParts.length - 1; i++) {\n currentHandle = await currentHandle.getDirectoryHandle(pathParts[i])\n }\n const fileName = pathParts[pathParts.length - 1]\n const fileHandle = await currentHandle.getFileHandle(fileName)\n const opfsFile = await fileHandle.getFile()\n return opfsFile\n}\n\nasync function deleteFileAtPath(\n path: string,\n root: FileSystemDirectoryHandle\n): Promise<void> {\n const pathParts = path.split('/').filter(Boolean)\n if (pathParts.length === 0) throw new Error('Invalid file path')\n\n let currentHandle: FileSystemDirectoryHandle = root\n for (let i = 0; i < pathParts.length - 1; i++) {\n currentHandle = await currentHandle.getDirectoryHandle(pathParts[i])\n }\n const fileName = pathParts[pathParts.length - 1]\n await currentHandle.removeEntry(fileName)\n}\n\nexport type OPFSFilesManagerTheme = 'light' | 'dark'\n\nexport interface OPFSFilesManagerProps {\n /** Optional subdirectory to scan (e.g. 'app-files'). Default: root. */\n rootPath?: string\n /** Filter which files to include. */\n filter?: (file: OPFSFile) => boolean\n /** Called when a file is about to be deleted. Return false to cancel. */\n onBeforeDelete?: (file: OPFSFile) => boolean | Promise<boolean>\n /** Called after a file or files are deleted. Use for clearing app state (e.g. Seed DB). */\n onAfterDelete?: (paths: string[]) => void | Promise<void>\n /** Custom download handler (e.g. Electron). If not provided, uses browser blob download. */\n onDownload?: (file: OPFSFile, blob: Blob) => void | Promise<void>\n /** Title for the page. Default: \"Files\" */\n title?: string\n /** Description text. Default: OPFS description. */\n description?: string\n /** Visual theme. Default: \"dark\" */\n theme?: OPFSFilesManagerTheme\n /** Class for the container. */\n className?: string\n}\n\nconst themeClasses = {\n light: {\n title: 'text-gray-900',\n description: 'text-gray-500',\n batchBar: 'bg-gray-100 border-gray-200',\n batchText: 'text-gray-900',\n clearButton: 'text-gray-500 hover:text-gray-900',\n loadingText: 'text-gray-500',\n errorBox: 'bg-red-50 border-red-200',\n errorTitle: 'text-red-800',\n errorText: 'text-red-700',\n emptyIcon: 'text-gray-400',\n emptyTitle: 'text-gray-900',\n emptyText: 'text-gray-500',\n tableHeader: 'bg-gray-100 text-gray-900',\n tableRow: 'bg-white',\n tableBorder: 'border-gray-200 divide-gray-200',\n tableCell: 'text-gray-900',\n tableCellMuted: 'text-gray-500',\n codeBlock: 'bg-gray-100 border-gray-200 text-gray-800',\n actionButton: 'text-gray-500 hover:text-gray-700',\n deleteButton: 'text-gray-500 hover:text-red-600',\n },\n dark: {\n title: 'text-white',\n description: 'text-gray-400',\n batchBar: 'bg-gray-800 border-gray-700',\n batchText: 'text-white',\n clearButton: 'text-gray-400 hover:text-white',\n loadingText: 'text-gray-400',\n errorBox: 'bg-red-900/50 border-red-800',\n errorTitle: 'text-red-200',\n errorText: 'text-red-300',\n emptyIcon: 'text-gray-500',\n emptyTitle: 'text-white',\n emptyText: 'text-gray-400',\n tableHeader: 'bg-gray-900 text-white',\n tableRow: 'bg-gray-900',\n tableBorder: 'border-gray-800 divide-gray-800',\n tableCell: 'text-white',\n tableCellMuted: 'text-gray-400',\n codeBlock: 'bg-gray-800 border-gray-700 text-gray-300',\n actionButton: 'text-gray-400 hover:text-indigo-400',\n deleteButton: 'text-gray-400 hover:text-red-500',\n },\n} as const\n\nconst layoutStyles = {\n container: { padding: '2rem 0' } as React.CSSProperties,\n header: {\n display: 'flex',\n flexWrap: 'wrap' as const,\n alignItems: 'center',\n gap: '1rem',\n marginBottom: '1rem',\n },\n title: { fontSize: '1.5rem', fontWeight: 600, margin: 0 },\n description: { fontSize: '0.875rem', margin: '0.5rem 0 0 0' },\n button:\n 'rounded-md px-3 py-2 text-sm font-semibold border-0 cursor-pointer bg-indigo-600 text-white hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600',\n buttonDanger:\n 'rounded-md px-3 py-2 text-sm font-semibold border-0 cursor-pointer bg-red-600 text-white hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600',\n table: 'min-w-full divide-y',\n tableHeader: 'py-3.5 pl-4 pr-3 text-left text-sm font-semibold sm:pl-6',\n tableCell: 'whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6',\n errorBox: 'rounded-md border p-4 mt-4',\n emptyState: 'text-center py-12',\n}\n\n/**\n * A React component to browse, download, and delete files stored in OPFS.\n * Useful for debugging and managing Origin Private File System storage.\n *\n * @example\n * ```tsx\n * <OPFSFilesManager\n * onAfterDelete={(paths) => {\n * if (paths.some(isSeedDbPath)) {\n * clearSeedDependentData()\n * window.location.reload()\n * }\n * }}\n * onDownload={async (file, blob) => {\n * if (window.electron?.downloadFile) {\n * await window.electron.downloadFile({ data: await blob.arrayBuffer(), filename: file.name })\n * }\n * }}\n * />\n * ```\n */\nexport function OPFSFilesManager({\n rootPath,\n filter,\n onBeforeDelete,\n onAfterDelete,\n onDownload,\n title = 'Files',\n description = 'Browse and download all files stored in the Origin Private File System (OPFS).',\n theme = 'dark',\n className,\n}: OPFSFilesManagerProps) {\n const t = themeClasses[theme]\n const { files: rawFiles, isLoading, error, refetch } = useOPFSFiles({ rootPath })\n const files = filter ? rawFiles.filter(filter) : rawFiles\n const [selectedFiles, setSelectedFiles] = useState<Set<string>>(new Set())\n const selectAllCheckboxRef = useRef<HTMLInputElement>(null)\n\n const allSelected = files.length > 0 && selectedFiles.size === files.length\n const someSelected = selectedFiles.size > 0 && selectedFiles.size < files.length\n\n const toggleFileSelection = (filePath: string) => {\n setSelectedFiles((prev) => {\n const next = new Set(prev)\n if (next.has(filePath)) next.delete(filePath)\n else next.add(filePath)\n return next\n })\n }\n\n const toggleSelectAll = () => {\n setSelectedFiles(\n selectedFiles.size === files.length ? new Set() : new Set(files.map((f) => f.path))\n )\n }\n\n useEffect(() => {\n setSelectedFiles(new Set())\n }, [files.length])\n\n useEffect(() => {\n if (selectAllCheckboxRef.current) {\n selectAllCheckboxRef.current.indeterminate = someSelected\n }\n }, [someSelected])\n\n const downloadFile = async (file: OPFSFile, suppressAlert = false) => {\n try {\n const root = await navigator.storage.getDirectory()\n const blob = await getFileBlob(file, root)\n\n if (onDownload) {\n await onDownload(file, blob)\n } else {\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = file.name\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n }\n } catch (err) {\n const msg = 'Failed to download file: ' + (err instanceof Error ? err.message : String(err))\n if (!suppressAlert) alert(msg)\n throw err\n }\n }\n\n const deleteFile = async (file: OPFSFile) => {\n if (onBeforeDelete) {\n const ok = await onBeforeDelete(file)\n if (!ok) return\n }\n if (!confirm(`Are you sure you want to delete \"${file.name}\"? This action cannot be undone.`)) {\n return\n }\n\n try {\n const root = await navigator.storage.getDirectory()\n await deleteFileAtPath(file.path, root)\n await refetch()\n await onAfterDelete?.([file.path])\n } catch (err) {\n alert('Failed to delete file: ' + (err instanceof Error ? err.message : String(err)))\n }\n }\n\n const downloadAllSelected = async () => {\n if (selectedFiles.size === 0) return\n const selected = files.filter((f) => selectedFiles.has(f.path))\n const errors: string[] = []\n for (const file of selected) {\n try {\n await downloadFile(file, true)\n await new Promise((r) => setTimeout(r, 100))\n } catch (err) {\n errors.push(`${file.name}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n if (errors.length > 0) {\n alert(`Some downloads failed:\\n${errors.join('\\n')}`)\n }\n }\n\n const deleteAllSelected = async () => {\n if (selectedFiles.size === 0) return\n const selected = files.filter((f) => selectedFiles.has(f.path))\n const names = selected.map((f) => f.name).join(', ')\n if (\n !confirm(\n `Are you sure you want to delete ${selectedFiles.size} file(s)?\\n\\nFiles: ${names}\\n\\nThis action cannot be undone.`\n )\n ) {\n return\n }\n\n const root = await navigator.storage.getDirectory()\n const deletedPaths: string[] = []\n const errors: string[] = []\n\n for (const file of selected) {\n if (onBeforeDelete) {\n const ok = await onBeforeDelete(file)\n if (!ok) continue\n }\n try {\n await deleteFileAtPath(file.path, root)\n deletedPaths.push(file.path)\n } catch (err) {\n errors.push(`${file.name}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n setSelectedFiles(new Set())\n await refetch()\n if (deletedPaths.length > 0) await onAfterDelete?.(deletedPaths)\n if (errors.length > 0) {\n alert(`Some deletions failed:\\n${errors.join('\\n')}`)\n }\n }\n\n return (\n <div className={className} style={layoutStyles.container}>\n <style>{`@keyframes opfs-spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}`}</style>\n <div style={layoutStyles.header}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <h1 style={layoutStyles.title} className={t.title}>\n {title}\n </h1>\n <p style={layoutStyles.description} className={t.description}>\n {description}\n </p>\n </div>\n <button type=\"button\" onClick={refetch} className={layoutStyles.button}>\n Refresh\n </button>\n </div>\n\n {selectedFiles.size > 0 && (\n <div\n className={`mt-4 flex items-center justify-between rounded-lg border px-4 py-3 ${t.batchBar}`}\n >\n <span className={`text-sm font-medium ${t.batchText}`}>\n {selectedFiles.size} file{selectedFiles.size === 1 ? '' : 's'} selected\n </span>\n <div className=\"flex items-center gap-3\">\n <button onClick={downloadAllSelected} className={layoutStyles.button}>\n <span className=\"inline-flex items-center gap-2\">\n <DownloadIcon /> Download All\n </span>\n </button>\n <button onClick={deleteAllSelected} className={layoutStyles.buttonDanger}>\n <span className=\"inline-flex items-center gap-2\">\n <TrashIcon /> Delete All\n </span>\n </button>\n <button\n onClick={() => setSelectedFiles(new Set())}\n className={`text-sm cursor-pointer bg-transparent border-0 ${t.clearButton}`}\n >\n Clear selection\n </button>\n </div>\n </div>\n )}\n\n <div className=\"mt-8\">\n {isLoading ? (\n <div className=\"flex justify-center items-center py-12 gap-3\">\n <span style={{ animation: 'opfs-spin 1s linear infinite' }}>\n <SpinnerIcon />\n </span>\n <span className={t.loadingText}>Loading files...</span>\n </div>\n ) : error ? (\n <div className={`${layoutStyles.errorBox} ${t.errorBox}`}>\n <h3 className={`m-0 text-sm font-medium ${t.errorTitle}`}>Error</h3>\n <div className={`mt-2 text-sm ${t.errorText}`}>{error}</div>\n </div>\n ) : files.length === 0 ? (\n <div className={layoutStyles.emptyState}>\n <span className={t.emptyIcon}>\n <FolderIcon />\n </span>\n <h3 className={`mt-2 text-sm font-semibold ${t.emptyTitle}`}>No files</h3>\n <p className={`mt-1 text-sm ${t.emptyText}`}>No files found in OPFS.</p>\n </div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className={layoutStyles.table}>\n <thead>\n <tr className={t.tableBorder}>\n <th className={`${layoutStyles.tableHeader} w-10 ${t.tableHeader}`}>\n <input\n ref={selectAllCheckboxRef}\n type=\"checkbox\"\n checked={allSelected}\n onChange={toggleSelectAll}\n aria-label=\"Select all\"\n />\n </th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Name</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Path</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Size</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Type</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Modified</th>\n <th\n className={`${layoutStyles.tableHeader} w-24 ${t.tableHeader}`}\n aria-label=\"Actions\"\n />\n </tr>\n </thead>\n <tbody className={`divide-y ${t.tableBorder}`}>\n {files.map((file) => (\n <tr key={file.path} className={t.tableRow}>\n <td className={`${layoutStyles.tableCell} ${t.tableCell}`}>\n <input\n type=\"checkbox\"\n checked={selectedFiles.has(file.path)}\n onChange={() => toggleFileSelection(file.path)}\n aria-label={`Select ${file.name}`}\n />\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCell}`}>\n <span className=\"flex items-center gap-2\">\n <DocumentIcon />\n {file.name}\n </span>\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n <code className={`text-xs px-2 py-1 rounded border ${t.codeBlock}`}>\n {file.path}\n </code>\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n {formatFileSize(file.size)}\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n {file.type}\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n {formatDate(file.lastModified)}\n </td>\n <td className={layoutStyles.tableCell}>\n <div className=\"flex gap-2 justify-end\">\n <button\n type=\"button\"\n onClick={() => downloadFile(file)}\n title=\"Download\"\n className={`p-1.5 rounded cursor-pointer bg-transparent border-0 transition-colors ${t.actionButton}`}\n >\n <DownloadIcon />\n </button>\n <button\n type=\"button\"\n onClick={() => deleteFile(file)}\n title=\"Delete\"\n className={`p-1.5 rounded cursor-pointer bg-transparent border-0 transition-colors ${t.deleteButton}`}\n >\n <TrashIcon />\n </button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </div>\n </div>\n )\n}\n","import React, { useState, useEffect, DetailedHTMLProps, ImgHTMLAttributes } from 'react'\nimport debug from 'debug'\nimport { BaseFileManager } from '@seedprotocol/sdk'\nimport { useItemProperty } from \"./itemProperty\"\nimport { ItemProperty } from '@seedprotocol/sdk'\n\nconst logger = debug('seedSdk:react:SeedImage')\n\n// Cache for content URLs\nconst contentUrlCache = new Map<string, string>()\n\nconst getFileNameWithoutExtension = (filePath: string): string => {\n // This regex has 3 parts:\n // 1. (.*[\\/\\\\]) - Captures the directory path (if any) ending with / or \\\n // 2. ([^\\/\\\\]+) - Captures the filename (anything that's not a / or \\)\n // 3. (\\.[^.\\/\\\\]*)?$ - Captures the last extension (if any)\n const regex = /^(.*[\\/\\\\])?([^\\/\\\\]+?)(\\.[^.\\/\\\\]*)?$/;\n \n const match = filePath.match(regex);\n \n if (match && match[2]) {\n return match[2];\n }\n \n return filePath; // Return original if no match (unlikely)\n}\n\n// Helper function to escape special regex characters\nfunction escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n}\n\nfunction matchFileNameWithoutExtension(fileName: string, targetName: string): boolean {\n // Create a regex pattern that matches the targetName\n // ^ - start of string\n // targetName is escaped to handle special regex characters\n // $ - end of string\n const regex = new RegExp(`^${escapeRegExp(targetName)}$`);\n \n // First get the filename without extension\n const nameWithoutExt = getFileNameWithoutExtension(fileName);\n \n // Then check if it matches the target name\n return regex.test(nameWithoutExt);\n}\n\ntype SeedImageProps = DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement> & {\n imageProperty: ItemProperty<any>\n alt?: string\n width?: number\n height?: number\n /** Optional filename override when property hasn't resolved yet (e.g. in tests) */\n filename?: string\n}\n\nconst SeedImageInner = ({ imageProperty, width, filename: filenameOverride, ...props }: SeedImageProps): React.ReactNode => {\n const [sizedContentUrl, setSizedContentUrl] = useState<string | undefined>()\n const [originalContentUrl, setOriginalContentUrl] = useState<string | undefined>()\n\n const { property: propertyFromHook } = useItemProperty({\n propertyName: imageProperty.propertyName,\n seedLocalId: imageProperty.seedLocalId,\n seedUid: imageProperty.seedUid\n })\n\n // Use passed imageProperty when parent provides it (e.g. direct pass from Item.properties); else use hook for reactive lookup\n const property = imageProperty ?? propertyFromHook\n\n // Resolved filename: explicit override, or from property\n const resolvedFilename = filenameOverride ?? (property?.refResolvedValue ?? property?.value) as string | undefined\n\n // Get display URL: value (blob URL or filename from ItemProperty.value getter), or resolvedFilename\n const rawValue = property?.value\n const srcUrl = (typeof rawValue === 'string' ? rawValue : resolvedFilename) as string | undefined\n const isFileOrBlob = rawValue != null && (rawValue instanceof File || rawValue instanceof Blob)\n const [blobPreviewUrl, setBlobPreviewUrl] = useState<string | null>(null)\n const blobPreviewRef = React.useRef<string | null>(null)\n useEffect(() => {\n if (isFileOrBlob && (rawValue instanceof File || rawValue instanceof Blob)) {\n if (!blobPreviewRef.current) {\n blobPreviewRef.current = URL.createObjectURL(rawValue)\n setBlobPreviewUrl(blobPreviewRef.current)\n }\n return () => {\n if (blobPreviewRef.current) {\n URL.revokeObjectURL(blobPreviewRef.current)\n blobPreviewRef.current = null\n }\n setBlobPreviewUrl(null)\n }\n }\n blobPreviewRef.current = null\n setBlobPreviewUrl(null)\n }, [isFileOrBlob, rawValue])\n\n // Fallback: when we have filename but no blob URL (e.g. after reload, or sized versions missing), load original file\n useEffect(() => {\n if (!resolvedFilename) return\n const isBlob = (s: unknown) => typeof s === 'string' && s.startsWith('blob:')\n if (rawValue && isBlob(rawValue)) return // Already have blob URL\n if (blobPreviewUrl) return // Have blob preview\n\n const _getOriginalContentUrl = async () => {\n try {\n const filePath = property?.localStoragePath\n ? property.localStoragePath\n : `${BaseFileManager.getFilesPath('images')}/${resolvedFilename}`\n const exists = await BaseFileManager.pathExists(filePath)\n if (exists) {\n const url = await BaseFileManager.getContentUrlFromPath(filePath)\n if (url) setOriginalContentUrl(url)\n }\n } catch (err) {\n logger('_getOriginalContentUrl error', err)\n }\n }\n _getOriginalContentUrl()\n return () => setOriginalContentUrl(undefined)\n }, [resolvedFilename, rawValue, blobPreviewUrl, property?.localStoragePath])\n\n useEffect(() => {\n if (!width || !resolvedFilename) {\n return\n }\n\n const _getSizedContentUrl = async () => {\n try {\n const fs = await BaseFileManager.getFs()\n const baseDir = property?.localStoragePath\n ? property.localStoragePath.split('/').slice(0, -1).join('/')\n : BaseFileManager.getFilesPath('images')\n const itemsInDir = fs.readdirSync(baseDir, {withFileTypes: true})\n const widthDirs = itemsInDir.filter((item: { isDirectory: () => boolean }) => item.isDirectory())\n const availableWidths = widthDirs.map((dir: { name: string }) => parseInt(dir.name))\n const closestWidth = availableWidths.reduce((prev: number, curr: number) => {\n return (Math.abs(curr - width) < Math.abs(prev - width) ? curr : prev)\n }, availableWidths[0])\n const filenameWithoutExtension = getFileNameWithoutExtension(resolvedFilename)\n\n // Check cache first\n const cacheKey = `${filenameWithoutExtension}-${closestWidth}`\n if (contentUrlCache.has(cacheKey)) {\n try {\n const contentUrl = contentUrlCache.get(cacheKey)\n if (contentUrl) {\n const response = await fetch(contentUrl)\n if (response.ok) {\n setSizedContentUrl(contentUrl)\n return\n }\n }\n } catch (error) {\n logger('error', error)\n contentUrlCache.delete(cacheKey)\n }\n }\n\n const itemsInSizedDir = fs.readdirSync(`${baseDir}/${closestWidth}`, {withFileTypes: true})\n\n const matchingFile = itemsInSizedDir.find((item: { name?: string }) => {\n if (!item.name) {\n return false\n }\n return matchFileNameWithoutExtension(item.name, filenameWithoutExtension)\n })\n if (!matchingFile) {\n return\n }\n const newPath = `${baseDir}/${closestWidth}/${matchingFile?.name}`\n const exists = await BaseFileManager.pathExists(newPath)\n if (exists) {\n const contentUrl = await BaseFileManager.getContentUrlFromPath(newPath)\n if (contentUrl) {\n contentUrlCache.set(cacheKey, contentUrl)\n setSizedContentUrl(contentUrl)\n }\n }\n } catch (err) {\n logger('_getSizedContentUrl error', err)\n }\n }\n\n _getSizedContentUrl()\n }, [property, width, srcUrl, resolvedFilename])\n\n // Render img when we have a content URL, or when we have filename (show placeholder while loading)\n const isBlobUrl = (s: unknown) => typeof s === 'string' && s.startsWith('blob:')\n const hasContentUrl = !!sizedContentUrl || !!originalContentUrl || !!blobPreviewUrl || (!!srcUrl && isBlobUrl(srcUrl))\n if (!hasContentUrl && !resolvedFilename) {\n return null\n }\n\n // Placeholder 1x1 transparent GIF while loading (ensures img exists for a11y and tests)\n const imgSrc = sizedContentUrl || originalContentUrl || blobPreviewUrl || (isBlobUrl(srcUrl) ? srcUrl : undefined) || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'\n\n return (\n <img src={imgSrc} alt={props.alt || imageProperty.propertyName || 'Image'} {...props} />\n )\n}\n\nexport const SeedImage = React.memo(SeedImageInner, (prev, next) =>\n prev.imageProperty === next.imageProperty &&\n prev.width === next.width &&\n prev.filename === next.filename\n)"],"names":["useIsClientReady","clientService","getClient","useSelector","snapshot","ClientManagerState","useLiveQuery","query","data","setData","useState","subscriptionRef","useRef","previousDataRef","isClientReady","observable","useMemo","BaseDb","error","useEffect","subscription","results","prev","prevJson","currJson","err","logger","debug","useItem","modelName","seedLocalId","seedUid","item","setItem","isLoading","setIsLoading","setError","hasSeenIdleRef","modelNameRef","seedLocalIdRef","seedUidRef","shouldLoad","loadItem","useCallback","foundItem","Item","getItemsQueryKey","deleted","includeEas","addressFilter","useItems","queryClient","useQueryClient","previousSeedsTableDataRef","itemsRef","lastFetchedIdsRef","addressesForFilter","setAddressesForFilter","cancelled","getAddressesForItemsFilter","addrs","queryKey","items","queryError","useQuery","db","seedsQuery","conditions","or","isNull","seeds","eq","toSnakeCase","inArray","sql","isNotNull","versionData","getVersionData","and","gt","seedsTableData","tableDataItemsSet","dbSeed","key","currentItemsSet","lastFetched","id","orderBy","useCreateItem","resetError","itemData","flushSync","createNewItem","usePublishItem","publishingItem","setPublishingItem","publishItem","service","value","ctx","publishError","snap","propertiesLogger","useItemProperty","arg1","arg2","property","setProperty","setVersion","obj","itemIdFromObj","propertyNameFromObj","itemId","propertyName","lookupMode","resolvedSeedLocalId","resolvedSeedUid","updateItemProperty","foundProperty","ItemProperty","lastVersionAt","wasIdle","THROTTLE_MS","now","useDebouncedItemProperty","params","debounceMs","normalizedParams","latestValueRef","debouncedPersist","debounce","prop","setValue","fetchItemPropertiesList","baseList","_itemProperties","propertiesWithMetadata","p","first","startCase","seedRecords","modelProperties","Model","model","modelProperty","itemProperty","createdAtPropertyName","createdAtProperty","useItemProperties","previousTableDataRef","canonicalItemKey","itemPropertiesQueryKey","properties","propertiesQuery","metadata","rawPropertiesTableData","propertiesTableData","latestByProperty","record","existing","existingTime","tableDataString","a","b","useCreateItemProperty","create","props","instance","useDestroyItemProperty","currentInstance","setCurrentInstance","destroyState","setDestroyState","update","sub","destroy","finalStrings","getServiceName","name","serviceAny","getServiceUniqueKey","getServiceValue","config","uniqueKey","context","pluralize","useService","timeElapsed","setTimeElapsed","getPercentComplete","percentComplete","stateNames","startupStates","stateName","state","totalStates","updateTime","interval","status","startInterval","useIsDbReady","isDbReady","setIsDbReady","internalStatus","useGlobalServiceStatus","usePersistedSnapshots","initialized","setInitialized","hasSavedSnapshots","useHasSavedSnapshots","services","useServices","save","actor","load","appDb","appState","like","persistedSnapshots","setHasSavedSnapshots","rows","actors","setActors","setPercentComplete","clientActor","percent","useDbsAreReady","dbsAreReady","setDbsAreReady","currentState","useSchema","schemaIdentifier","schema","setSchema","loadSchema","identifier","schemaInstance","Schema","SEED_SCHEMAS_QUERY_KEY","useSchemas","previousSchemasTableDataRef","schemasRef","schemas","schemasQuery","schemasTable","desc","schemasTableData","ch","onMessage","prevData","prevDataJson","currDataJson","currentSchemasSet","schemaFileId","version","tableDataSchemasSet","dbSchema","setsAreEqual","tableHasNewRows","useCreateSchema","createSchema","schemaName","useDestroySchema","useAllSchemaVersions","schemaInstances","setSchemaInstances","schemaInstancesRef","fetchSchemas","allSchemasData","loadAllSchemasFromDb","schemaNames","schemaData","currentInstances","existingInstance","useSeedProtocolSchema","SEED_PROTOCOL_SCHEMA_NAME","getModelsQueryKey","schemaId","lastModelsBySchemaId","useModels","modelsRef","models","next","current","schemaIdKey","fallback","displayModels","event","stableModelsQueryKeyRef","stableModelsQueryRef","buildModelsQuery","currentDb","modelsTable","modelSchemas","modelsQuery","prevKey","q","modelsTableData","currentModelsSet","modelFileId","tableDataModelsSet","dbModel","useModel","schemaIdOrModelId","setModel","isModelIdLookup","foundModel","modelsList","modelsLoading","modelsError","m","useCreateModel","options","useDestroyModel","useModelProperties","dbModelId","modelId","modelPropertiesQueryKey","ModelProperty","propertiesTable","modelPropertiesRef","timers","ms","t","currentPropertiesSet","propertyFileId","tableDataPropertiesSet","dbProperty","effectiveIsLoading","getPropertySchemaByModelFileId","getPropertySchema","useModelProperty","arg3","initialLoadingState","setModelProperty","updateModelProperty","propertyData","resolvedModelName","createdProperty","resolvedProperty","shouldSubscribe","debouncedUpdate","useCreateModelProperty","getSchemaNameFromId","created","useDestroyModelProperty","useDeleteItem","IMAGE_FILES_QUERY_KEY","useImageFiles","imageFiles","refetch","BaseFileManager","fileSavedHandler","filePath","downloadSuccessHandler","eventEmitter","FILES_QUERY_KEY_PREFIX","useFiles","dir","files","SEED_QUERY_DEFAULT_OPTIONS","getSeedQueryDefaultOptions","mergeSeedQueryDefaults","userOptions","seed","createSeedQueryClient","overrides","defaults","userDefaultOptions","restOverrides","ReactQueryClient","invalidateItemPropertiesRef","invalidateItemPropertiesForItem","canonicalId","p1","SeedProviderEventSubscriber","invalidate","handler","payload","SeedProvider","children","queryClientProp","queryClientRef","w","jsxs","QueryClientProvider","jsx","DefaultLoading","SeedClientGate","initConfig","loadingComponent","wrapperClassName","loadingClassName","effectiveConfig","client","loadingContent","wrapperStyle","overlayStyle","scanDirectory","dirHandle","basePath","foundFiles","handle","currentPath","file","subFiles","useOPFSFiles","rootPath","setFiles","parts","part","allFiles","DownloadIcon","FolderIcon","DocumentIcon","TrashIcon","SpinnerIcon","formatFileSize","bytes","k","sizes","i","formatDate","timestamp","getFileBlob","root","pathParts","currentHandle","fileName","deleteFileAtPath","path","themeClasses","layoutStyles","OPFSFilesManager","filter","onBeforeDelete","onAfterDelete","onDownload","title","description","theme","className","rawFiles","selectedFiles","setSelectedFiles","selectAllCheckboxRef","allSelected","someSelected","toggleFileSelection","toggleSelectAll","f","downloadFile","suppressAlert","blob","url","msg","deleteFile","downloadAllSelected","selected","errors","r","deleteAllSelected","names","deletedPaths","contentUrlCache","getFileNameWithoutExtension","regex","match","escapeRegExp","string","matchFileNameWithoutExtension","targetName","nameWithoutExt","SeedImageInner","imageProperty","width","filenameOverride","sizedContentUrl","setSizedContentUrl","originalContentUrl","setOriginalContentUrl","propertyFromHook","resolvedFilename","rawValue","srcUrl","isFileOrBlob","blobPreviewUrl","setBlobPreviewUrl","blobPreviewRef","React","s","fs","baseDir","availableWidths","closestWidth","curr","filenameWithoutExtension","cacheKey","contentUrl","matchingFile","newPath","isBlobUrl","imgSrc","SeedImage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/client.ts","../src/liveQuery.ts","../src/item.ts","../src/itemProperty.ts","../src/services.ts","../src/db.ts","../src/schema.ts","../src/model.ts","../src/modelProperty.ts","../src/trash.ts","../src/useImageFiles.ts","../src/useFiles.ts","../src/queryClient.ts","../src/SeedProvider.tsx","../src/SeedClientGate.tsx","../src/useOPFSFiles.ts","../src/OPFSFilesManager.tsx","../src/SeedImage.tsx"],"sourcesContent":["import { ClientManagerState, getClient } from '@seedprotocol/sdk'\nimport { useSelector } from \"@xstate/react\"\n\n\nexport const useIsClientReady = () => {\n const client = getClient()\n\n const clientService = client.getService()\n\n const isClientReady = useSelector(clientService, (snapshot) => {\n return snapshot.value === ClientManagerState.IDLE\n })\n\n // GlobalState removed - check ClientManager state directly\n return isClientReady\n}","import { useEffect, useState, useRef, useMemo } from 'react'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { Observable } from 'rxjs'\nimport { useIsClientReady } from './client'\n\n/**\n * Hook to execute a reactive query that emits new results whenever the underlying data changes.\n * \n * Supports two usage patterns:\n * 1. SQL tag function: useLiveQuery((sql) => sql`SELECT * FROM models`)\n * 2. Drizzle query builder: useLiveQuery(db.select().from(models))\n * \n * @param query - SQL query function or Drizzle query builder, or null/undefined to disable the query\n * @returns Array of query results, or undefined if not yet loaded\n * \n * @example\n * ```typescript\n * // Using SQL tag function\n * const models = useLiveQuery<ModelRow>(\n * (sql) => sql`SELECT * FROM models WHERE schema_file_id = ${schemaId}`\n * )\n * \n * // Using Drizzle query builder\n * import { models } from '@seedprotocol/sdk'\n * import { eq } from 'drizzle-orm'\n * \n * const appDb = BaseDb.getAppDb()\n * const models = useLiveQuery<ModelRow>(\n * appDb.select().from(models).where(eq(models.schemaFileId, schemaId))\n * )\n * ```\n */\nexport function useLiveQuery<T>(\n query: ((sql: any) => any) | any | null | undefined\n): T[] | undefined {\n const [data, setData] = useState<T[] | undefined>(undefined)\n const subscriptionRef = useRef<{ unsubscribe: () => void } | null>(null)\n const isClientReady = useIsClientReady()\n\n // Create Observable outside useEffect so it's stable and distinctUntilChanged can work\n // Only recreate when query or isClientReady changes\n const observable = useMemo(() => {\n if (!isClientReady || !query) {\n return null\n }\n try {\n return BaseDb.liveQuery<T>(query)\n } catch (error) {\n console.error('[useLiveQuery] Failed to create live query:', error)\n return null\n }\n }, [query, isClientReady])\n\n useEffect(() => {\n // Cleanup previous subscription if it exists\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n\n // Don't subscribe if observable is null\n if (!observable) {\n return\n }\n\n const subscription = observable.subscribe({\n next: (results) => {\n // New array reference so React re-renders when SQLocal mutates row objects in place\n // on the same backing array (Object.is would otherwise bail out of useState).\n setData(results !== undefined ? [...results] : undefined)\n },\n error: (err) => {\n console.error('[useLiveQuery] Error:', err)\n // Don't set data to undefined on error - keep last known good state\n // This prevents UI flickering on transient errors\n },\n })\n\n subscriptionRef.current = subscription\n\n // Cleanup on unmount or observable change\n return () => {\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n }\n }, [observable]) // Only re-subscribe when observable changes\n\n return data\n}\n\n","import { useCallback, useEffect, useRef, useState, useMemo } from 'react'\nimport { flushSync } from 'react-dom'\nimport { createNewItem, getAddressesForItemsFilter, Item } from '@seedprotocol/sdk'\nimport { orderBy } from 'lodash-es'\nimport debug from 'debug'\nimport type { ModelValues } from '@seedprotocol/sdk'\nimport { Subscription } from 'xstate'\nimport type { IItem } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport { useLiveQuery } from './liveQuery'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { seeds } from '@seedprotocol/sdk'\nimport { and, eq, gt, inArray, isNotNull, isNull, or, sql } from 'drizzle-orm'\nimport { toSnakeCase } from 'drizzle-orm/casing'\nimport type { SeedType } from '@seedprotocol/sdk'\nimport { getVersionData } from '@seedprotocol/sdk'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\n\nconst logger = debug('seedSdk:react:item')\n\ntype UseItemReturn<T extends ModelValues<T>> = {\n item: IItem<T> | undefined\n isLoading: boolean\n error: Error | null\n}\n\ntype UseItemProps = {\n modelName: string\n seedLocalId?: string\n seedUid?: string\n}\n\ntype UseItem = <T extends ModelValues<T>>(props: UseItemProps) => UseItemReturn<T>\n\nexport const useItem: UseItem = <T extends ModelValues<T>>({ modelName, seedLocalId, seedUid }: UseItemProps) => {\n const [item, setItem] = useState<Item<T> | undefined>()\n const [isLoading, setIsLoading] = useState(!!(seedLocalId || seedUid))\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const hasSeenIdleRef = useRef(false)\n\n const isClientReady = useIsClientReady()\n\n const modelNameRef = useRef<string>(modelName)\n const seedLocalIdRef = useRef<string | undefined>(seedLocalId)\n const seedUidRef = useRef<string | undefined>(seedUid)\n\n // Determine if we should be loading based on parameters - use useMemo to stabilize\n // Use refs to check current values to avoid dependency issues\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n return !!(seedLocalIdRef.current || seedUidRef.current)\n }, [isClientReady, seedLocalId, seedUid])\n\n const loadItem = useCallback(async () => {\n // Check shouldLoad inside the function to avoid recreating the callback\n const currentShouldLoad = !!(isClientReady && (seedLocalIdRef.current || seedUidRef.current))\n if (!currentShouldLoad) {\n setItem(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n try {\n // Don't set isLoading here - let the subscription effect handle it\n // This avoids race conditions where isLoading is set to true but then\n // the subscription effect hasn't run yet to set it to false\n setError(null)\n\n const foundItem = await Item.find({\n modelName: modelNameRef.current,\n seedLocalId: seedLocalIdRef.current,\n seedUid: seedUidRef.current,\n }) as Item<T> | undefined\n\n if (!foundItem) {\n logger('[useItem] [loadItem] no item found', modelNameRef.current, seedLocalIdRef.current)\n // Don't clear item if we already have one for the same request (e.g. duplicate loadItem from effect re-run)\n setItem((prev) => {\n if (!prev) return undefined\n const match = (prev.seedLocalId && prev.seedLocalId === seedLocalIdRef.current) ||\n (prev.seedUid && prev.seedUid === seedUidRef.current)\n return match ? prev : undefined\n })\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Item.find() now waits for idle by default, so the item should be ready\n setItem(foundItem)\n setIsLoading(false) // Item is ready since find() waited for idle\n setError(null)\n } catch (error) {\n logger('[useItem] Error loading item:', error)\n setItem(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }, [isClientReady])\n\n useEffect(() => {\n modelNameRef.current = modelName\n seedLocalIdRef.current = seedLocalId\n seedUidRef.current = seedUid\n }, [modelName, seedLocalId, seedUid])\n\n // Fetch/refetch when parameters change or client becomes ready\n useEffect(() => {\n // Only clear item if we don't have parameters to load\n // Don't clear if shouldLoad is false but we have an item - it might just be a timing issue\n if (!shouldLoad) {\n // Only clear if we actually don't have parameters (not just client not ready)\n if (!seedLocalId && !seedUid) {\n setItem(undefined)\n setIsLoading(false)\n setError(null)\n }\n return\n }\n loadItem()\n }, [shouldLoad, loadItem, seedLocalId, seedUid])\n\n // Subscribe to service changes when item is available\n useEffect(() => {\n if (!item) {\n // Clean up subscription if item is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n hasSeenIdleRef.current = false\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n hasSeenIdleRef.current = false\n\n // Subscribe to service changes. Only set isLoading to true after we've seen idle at least\n // once, so we don't overwrite the ready state that loadItem() just set (find() waits for idle).\n const service = item.getService()\n\n const subscription = service.subscribe((snapshot: any) => {\n // Update loading state based on service state changes\n if (snapshot && typeof snapshot === 'object' && 'value' in snapshot) {\n const isIdle = snapshot.value === 'idle'\n if (isIdle) {\n hasSeenIdleRef.current = true\n setIsLoading(false)\n setError(null)\n } else if (snapshot.value === 'error') {\n setError(new Error('Item service error'))\n setIsLoading(false)\n } else {\n // Only show loading if we've already seen idle (real transition to loading)\n if (hasSeenIdleRef.current) {\n setIsLoading(true)\n }\n }\n }\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [item])\n\n return {\n item,\n isLoading,\n error,\n }\n}\n\ntype UseItemsReturn = {\n items: IItem<any>[]\n isLoading: boolean\n error: Error | null\n}\n\ntype UseItemsProps = {\n modelName?: string\n deleted?: boolean\n includeEas?: boolean\n addressFilter?: 'owned' | 'watched' | 'all'\n}\n\ntype UseItems = (props: UseItemsProps) => UseItemsReturn\n\nconst getItemsQueryKey = (\n modelName?: string,\n deleted?: boolean,\n includeEas?: boolean,\n addressFilter?: 'owned' | 'watched' | 'all'\n) => ['seed', 'items', modelName ?? null, deleted ?? false, includeEas ?? false, addressFilter ?? null] as const\n\nexport const useItems: UseItems = ({\n modelName,\n deleted = false,\n includeEas = false,\n addressFilter,\n}) => {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const previousSeedsTableDataRef = useRef<SeedType[] | undefined>(undefined)\n const itemsRef = useRef<IItem<any>[]>([])\n const lastFetchedIdsRef = useRef<Set<string>>(new Set())\n const [addressesForFilter, setAddressesForFilter] = useState<string[] | null>(null)\n\n useEffect(() => {\n if (addressFilter !== 'owned' && addressFilter !== 'watched') {\n setAddressesForFilter(null)\n return\n }\n let cancelled = false\n getAddressesForItemsFilter(addressFilter).then((addrs) => {\n if (!cancelled) setAddressesForFilter(addrs)\n })\n return () => {\n cancelled = true\n }\n }, [addressFilter])\n\n const queryKey = useMemo(\n () => getItemsQueryKey(modelName, deleted, includeEas, addressFilter),\n [modelName, deleted, includeEas, addressFilter],\n )\n\n const {\n data: items = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey,\n queryFn: () => Item.all(modelName, deleted, { waitForReady: true, includeEas, addressFilter }),\n enabled: isClientReady,\n })\n itemsRef.current = items\n\n // Watch the seeds table for changes\n const db = isClientReady ? BaseDb.getAppDb() : null\n const seedsQuery = useMemo(() => {\n if (!db) return null\n if (addressFilter === 'owned' || addressFilter === 'watched') {\n if (addressesForFilter === null) return null\n }\n const conditions: any[] = []\n if (!includeEas) {\n conditions.push(or(isNull(seeds.uid), eq(seeds.uid, '')) as any)\n }\n if (modelName) {\n conditions.push(eq(seeds.type, toSnakeCase(modelName)))\n }\n if (addressFilter === 'owned') {\n if (addressesForFilter && addressesForFilter.length > 0) {\n conditions.push(\n or(\n inArray(seeds.publisher, addressesForFilter),\n isNull(seeds.publisher)\n ) as any\n )\n }\n } else if (addressFilter === 'watched') {\n if (addressesForFilter && addressesForFilter.length > 0) {\n conditions.push(inArray(seeds.publisher, addressesForFilter) as any)\n } else {\n conditions.push(sql`1=0` as any)\n }\n }\n if (deleted) {\n conditions.push(\n or(\n isNotNull(seeds._markedForDeletion),\n eq(seeds._markedForDeletion, 1)\n ) as any\n )\n } else {\n conditions.push(\n or(\n isNull(seeds._markedForDeletion),\n eq(seeds._markedForDeletion, 0)\n ) as any\n )\n conditions.push(\n or(isNull(seeds.revokedAt), eq(seeds.revokedAt, 0)) as any\n )\n }\n const versionData = getVersionData()\n return db\n .with(versionData)\n .select({\n localId: seeds.localId,\n uid: seeds.uid,\n type: seeds.type,\n schemaUid: seeds.schemaUid,\n createdAt: seeds.createdAt,\n attestationCreatedAt: seeds.attestationCreatedAt,\n _markedForDeletion: seeds._markedForDeletion,\n })\n .from(seeds)\n .leftJoin(versionData, eq(seeds.localId, versionData.seedLocalId))\n .where(and(gt(versionData.versionsCount, 0), ...conditions))\n .groupBy(seeds.localId)\n }, [db, isClientReady, modelName, deleted, includeEas, addressFilter, addressesForFilter])\n const seedsTableData = useLiveQuery<SeedType>(seedsQuery)\n\n // Invalidate when table data actually changes so useQuery refetches\n useEffect(() => {\n if (!isClientReady || !seedsTableData) return\n\n const tableDataItemsSet = new Set<string>()\n for (const dbSeed of seedsTableData) {\n const key = dbSeed.localId || dbSeed.uid\n if (key) tableDataItemsSet.add(key)\n }\n\n const currentItemsSet = new Set<string>()\n for (const item of itemsRef.current) {\n const key = item.seedLocalId || item.seedUid\n if (key) currentItemsSet.add(key)\n }\n\n if (tableDataItemsSet.size === 0 && currentItemsSet.size > 0) return\n\n const lastFetched = lastFetchedIdsRef.current\n if (\n lastFetched.size === tableDataItemsSet.size &&\n [...lastFetched].every((id) => tableDataItemsSet.has(id))\n ) {\n return\n }\n\n previousSeedsTableDataRef.current = seedsTableData\n\n const setsAreEqual =\n currentItemsSet.size === tableDataItemsSet.size &&\n [...currentItemsSet].every((id) => tableDataItemsSet.has(id))\n\n if (setsAreEqual) {\n lastFetchedIdsRef.current = new Set(tableDataItemsSet)\n return\n }\n\n lastFetchedIdsRef.current = new Set(tableDataItemsSet)\n queryClient.invalidateQueries({ queryKey })\n }, [isClientReady, seedsTableData, queryClient, queryKey])\n\n return {\n items: orderBy(\n items,\n [\n (item) =>\n item.lastVersionPublishedAt ||\n item.attestationCreatedAt ||\n item.createdAt,\n ],\n ['desc'],\n ),\n isLoading,\n error: queryError as Error | null,\n }\n}\n\nexport type UseCreateItemReturn = {\n createItem: (modelName: string, itemData?: Record<string, any>) => Promise<Item<any> | undefined>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useCreateItem = (): UseCreateItemReturn => {\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const createItem = useCallback(\n async (modelName: string, itemData?: Record<string, any>): Promise<Item<any> | undefined> => {\n if (isLoading) {\n logger('[useCreateItem] [createItem] already creating item, skipping')\n return undefined\n }\n\n setError(null)\n // Flush loading=true synchronously so the UI (and tests) can observe it before async work runs.\n flushSync(() => setIsLoading(true))\n\n try {\n const data = itemData ?? {}\n const { seedLocalId } = await createNewItem({ modelName, ...data })\n const newItem = await Item.find({ modelName, seedLocalId })\n return (newItem ?? undefined) as Item<any> | undefined\n } catch (err) {\n logger('[useCreateItem] Error creating item:', err)\n setError(err instanceof Error ? err : new Error(String(err)))\n return undefined\n } finally {\n // Defer clearing loading so React can commit the loading=true render first.\n // Otherwise the test (or UI) may never observe isLoading true (same continuation batching).\n queueMicrotask(() => setIsLoading(false))\n }\n },\n [isLoading],\n )\n\n return {\n createItem,\n isLoading,\n error,\n resetError,\n }\n}\n\ntype UsePublishItemReturn = {\n publishItem: (item: Item<any> | undefined) => void\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const usePublishItem = (): UsePublishItemReturn => {\n const [publishingItem, setPublishingItem] = useState<Item<any> | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n\n const resetError = useCallback(() => setError(null), [])\n\n const publishItem = useCallback((item: Item<any> | undefined) => {\n if (!item) return\n setPublishingItem(item)\n setError(null)\n item.publish().catch(() => {\n // Error is surfaced via service state subscription; avoid unhandled rejection\n })\n }, [])\n\n useEffect(() => {\n if (!publishingItem) {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n setIsLoading(false)\n return\n }\n\n subscriptionRef.current?.unsubscribe()\n const service = publishingItem.getService()\n const subscription = service.subscribe((snapshot: any) => {\n const value = snapshot?.value\n const ctx = snapshot?.context\n setIsLoading(value === 'publishing')\n const publishError = ctx?._publishError\n setError(publishError ? new Error(publishError.message) : null)\n })\n\n subscriptionRef.current = subscription\n const snap = service.getSnapshot()\n setIsLoading(snap?.value === 'publishing')\n const ctx = snap?.context\n const publishError = ctx?._publishError\n setError(publishError ? new Error(publishError.message) : null)\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [publishingItem])\n\n return {\n publishItem,\n isLoading,\n error,\n resetError,\n }\n}\n","import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { Subscription, SnapshotFrom } from 'xstate'\nimport debug from 'debug'\nimport { ItemProperty } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport type { IItemProperty } from '@seedprotocol/sdk'\nimport { useLiveQuery } from './liveQuery'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { metadata } from '@seedprotocol/sdk'\nimport { seeds } from '@seedprotocol/sdk'\nimport { and, eq, isNotNull } from 'drizzle-orm'\nimport { getMetadataLatest } from '@seedprotocol/sdk'\nimport { propertyMachine } from '@seedprotocol/sdk'\nimport { debounce, startCase } from 'lodash-es'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\n\nconst logger = debug('seedSdk:react:property')\nconst propertiesLogger = debug('seedSdk:react:itemProperties')\n\ntype ItemPropertySnapshot = SnapshotFrom<typeof propertyMachine>\n\ntype UseItemPropertyReturn = {\n property: IItemProperty | undefined\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook to get a specific ItemProperty instance\n * Can be called in multiple ways:\n * 1. With seedLocalId/seedUid and propertyName: useItemProperty({ seedLocalId, propertyName }) or useItemProperty({ seedUid, propertyName })\n * 2. With itemId and propertyName: useItemProperty(itemId, propertyName) or useItemProperty({ itemId, propertyName })\n * \n * @overload\n * @param props - Object with seedLocalId or seedUid, and propertyName\n * @returns Object with property, isLoading, and error\n * \n * @overload\n * @param props - Object with itemId and propertyName\n * @returns Object with property, isLoading, and error\n * \n * @overload\n * @param itemId - The item ID (seedLocalId or seedUid)\n * @param propertyName - The name of the property\n * @returns Object with property, isLoading, and error\n */\nexport function useItemProperty(props: {\n seedLocalId?: string\n seedUid?: string\n propertyName: string\n}): UseItemPropertyReturn\nexport function useItemProperty(props: {\n itemId?: string\n propertyName: string\n}): UseItemPropertyReturn\nexport function useItemProperty(\n itemId: string,\n propertyName: string\n): UseItemPropertyReturn\nexport function useItemProperty(\n arg1:\n | { seedLocalId?: string; seedUid?: string; propertyName: string }\n | { itemId: string; propertyName: string }\n | string,\n arg2?: string\n) {\n const isClientReady = useIsClientReady()\n const [property, setProperty] = useState<IItemProperty | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [, setVersion] = useState(0) // Version counter to force re-renders\n\n // Extract primitives so useMemo/useCallback deps are stable when caller passes inline objects\n // Support object form with itemId: useItemProperty({ itemId, propertyName })\n const arg1IsObject = typeof arg1 === 'object' && arg1 != null\n const obj = arg1IsObject ? (arg1 as Record<string, unknown>) : null\n const itemIdFromObj = obj != null ? (obj.itemId as string | undefined) : undefined\n const seedLocalId =\n obj != null ? (obj.seedLocalId as string | undefined) : undefined\n const seedUid =\n obj != null ? (obj.seedUid as string | undefined) : undefined\n const propertyNameFromObj =\n obj != null ? (obj.propertyName as string | undefined) : undefined\n const itemId =\n typeof arg1 === 'string' ? arg1 : (itemIdFromObj !== undefined && itemIdFromObj !== '' ? itemIdFromObj : undefined)\n const propertyNameFromArgs = typeof arg1 === 'string' ? arg2 : undefined\n const propertyName = propertyNameFromObj ?? propertyNameFromArgs\n\n // Determine which lookup mode we're in based on arguments (deps are primitives to avoid infinite loop)\n // Unify itemId and identifiers: when itemId is provided (string or object form), use it as seedLocalId so we hit the same code path\n const lookupMode = useMemo(() => {\n const resolvedSeedLocalId = (itemId !== undefined && itemId !== '') ? itemId : seedLocalId\n const resolvedSeedUid = (itemId !== undefined && itemId !== '') ? undefined : seedUid\n if ((resolvedSeedLocalId != null || resolvedSeedUid != null) && propertyName != null && propertyName !== '') {\n return {\n type: 'identifiers' as const,\n seedLocalId: resolvedSeedLocalId ?? undefined,\n seedUid: resolvedSeedUid,\n propertyName,\n }\n }\n return null\n }, [itemId, propertyName, seedLocalId, seedUid])\n\n // Determine initial loading state\n const initialLoadingState = useMemo(() => {\n if (!lookupMode) return false\n return !!(\n (lookupMode.seedLocalId || lookupMode.seedUid) &&\n lookupMode.propertyName\n )\n }, [lookupMode])\n\n // Determine if we should be loading based on parameters\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n if (!lookupMode) return false\n return !!(\n (lookupMode.seedLocalId || lookupMode.seedUid) &&\n lookupMode.propertyName\n )\n }, [isClientReady, lookupMode])\n\n // Avoid one frame where isLoading is false while a fetch is about to start (default useState(false)).\n useLayoutEffect(() => {\n if (shouldLoad) {\n setIsLoading(true)\n }\n }, [shouldLoad])\n\n const updateItemProperty = useCallback(async () => {\n if (!isClientReady || !lookupMode) {\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n try {\n setIsLoading(true)\n setError(null)\n\n const seedLocalId = lookupMode.seedLocalId\n const seedUid = lookupMode.seedUid\n\n if (!seedLocalId && !seedUid) {\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n const foundProperty = await ItemProperty.find({\n propertyName: lookupMode.propertyName,\n seedLocalId,\n seedUid,\n })\n\n if (!foundProperty) {\n logger(\n `[useItemProperty] [updateItemProperty] no property found for Item.${seedLocalId || seedUid}.${lookupMode.propertyName}`,\n )\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // ItemProperty.find() now waits for idle by default, so the property should be ready\n setProperty(foundProperty)\n setIsLoading(false) // Property is ready since find() waited for idle\n setError(null)\n } catch (error) {\n logger('[useItemProperty] Error updating item property:', error)\n setProperty(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }, [isClientReady, lookupMode])\n\n // Fetch/refetch when lookup parameters change or client becomes ready.\n // Skip refetch when we already have the property for this lookup (avoids setting loading true\n // again when effect re-runs e.g. from Strict Mode or updateItemProperty identity change).\n // Match by the active identifier only: when looking up by seedLocalId both must match;\n // when looking up by seedUid both must match. Do not use (seedUid === undefined) as a match\n // when seedLocalIds differ, which would incorrectly skip refetch after seedLocalId change.\n useEffect(() => {\n if (!shouldLoad) {\n setProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n const alreadyHavePropertyGuard =\n property &&\n lookupMode &&\n property.propertyName === lookupMode.propertyName &&\n ((lookupMode.seedLocalId != null && property.seedLocalId === lookupMode.seedLocalId) ||\n (lookupMode.seedUid != null && (property as any).seedUid === lookupMode.seedUid))\n if (alreadyHavePropertyGuard) return\n updateItemProperty()\n }, [shouldLoad, updateItemProperty, property, lookupMode])\n\n // Subscribe to service changes when property is available\n useEffect(() => {\n if (!property) {\n // Clean up subscription if property is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n // Subscribe to service changes. Only set isLoading to false when idle; never set to true\n // here so we never overwrite the loaded state when the machine emits any non-idle state\n // (e.g. loading, initializing, resolvingRelatedValue) after the initial fetch.\n let lastVersionAt = 0\n let wasIdle = false\n /** Idle snapshots repeat often; only re-render when context values actually change (e.g. liveQuery/updateContext after idle). */\n let lastIdleValueSig: string | undefined\n const THROTTLE_MS = 50\n const subscription = property.getService().subscribe((snapshot: any) => {\n const isIdle = snapshot && typeof snapshot === 'object' && 'value' in snapshot && snapshot.value === 'idle'\n if (isIdle) {\n setIsLoading(false)\n setError(null)\n const ctx = snapshot.context\n const sig = JSON.stringify([ctx.renderValue, ctx.propertyValue])\n const shouldBump = !wasIdle || sig !== lastIdleValueSig\n if (shouldBump) {\n wasIdle = true\n lastIdleValueSig = sig\n setVersion((prev) => prev + 1)\n }\n return\n }\n wasIdle = false\n lastIdleValueSig = undefined\n // Throttle re-renders during transitions: property machine emits many snapshots\n const now = Date.now()\n if (now - lastVersionAt >= THROTTLE_MS) {\n lastVersionAt = now\n setVersion(prev => prev + 1)\n }\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [property])\n\n return {\n property,\n isLoading,\n error,\n }\n}\n\ntype UseDebouncedItemPropertyParams =\n | { seedLocalId?: string; seedUid?: string; propertyName: string }\n | { itemId: string; propertyName: string }\n\ntype UseDebouncedItemPropertyReturn = {\n property: IItemProperty | undefined\n setValue: (value: string) => void\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook for real-time ItemProperty updates with debounced persistence.\n * Updates the display immediately on each change while debouncing writes to the database.\n * Use this for text inputs and other high-frequency updates.\n *\n * @param params - Same as useItemProperty: { seedLocalId, propertyName }, { seedUid, propertyName }, or { itemId, propertyName }\n * @param debounceMs - Debounce delay for persistence (default: 300)\n */\nexport function useDebouncedItemProperty(\n params: UseDebouncedItemPropertyParams,\n debounceMs = 300\n): UseDebouncedItemPropertyReturn {\n const itemId = 'itemId' in params ? params.itemId : undefined\n const seedLocalId = 'seedLocalId' in params ? params.seedLocalId : undefined\n const seedUid = 'seedUid' in params ? params.seedUid : undefined\n const propertyName = params.propertyName\n\n const normalizedParams = useMemo(() => {\n if (itemId) {\n return { seedLocalId: itemId, propertyName }\n }\n return { seedLocalId, seedUid, propertyName }\n }, [itemId, seedLocalId, seedUid, propertyName])\n\n const { property, isLoading, error } = useItemProperty(normalizedParams)\n const latestValueRef = useRef<string>('')\n\n const debouncedPersist = useMemo(\n () =>\n debounce((prop: IItemProperty) => {\n prop.getService().send({\n type: 'save',\n newValue: latestValueRef.current,\n })\n }, debounceMs),\n [debounceMs]\n )\n\n useEffect(() => {\n return () => debouncedPersist.cancel()\n }, [debouncedPersist])\n\n const setValue = useCallback(\n (value: string) => {\n if (!property) return\n latestValueRef.current = value\n property.getService().send({\n type: 'updateContext',\n propertyValue: value,\n renderValue: value,\n })\n debouncedPersist(property)\n },\n [property, debouncedPersist]\n )\n\n return {\n property,\n setValue,\n isLoading,\n error,\n }\n}\n\ntype UseItemPropertiesReturn = {\n properties: IItemProperty[]\n isLoading: boolean\n error: Error | null\n}\n\n/** Fetches item properties list for useQuery (shared with useItemProperties). */\nasync function fetchItemPropertiesList(\n seedLocalId: string | undefined,\n seedUid: string | undefined\n): Promise<IItemProperty[]> {\n if (!seedLocalId && !seedUid) return []\n const db = BaseDb.getAppDb()\n if (!db) return []\n\n const baseList = await ItemProperty.all(\n { seedLocalId: seedLocalId ?? undefined, seedUid: seedUid ?? undefined },\n { waitForReady: true },\n )\n const _itemProperties: IItemProperty[] = [...(baseList as IItemProperty[])]\n\n const propertiesWithMetadata = new Set<string>()\n for (const p of baseList) {\n if (p.propertyName) propertiesWithMetadata.add(p.propertyName)\n }\n\n let modelName: string | undefined\n if (baseList.length > 0) {\n const first = baseList[0]\n modelName = first.modelName ?? (first as any).modelType\n if (modelName && typeof modelName === 'string') modelName = startCase(modelName)\n }\n if (!modelName) {\n const seedRecords = await db\n .select({ type: seeds.type })\n .from(seeds)\n .where(seedUid ? eq(seeds.uid, seedUid) : eq(seeds.localId, seedLocalId!))\n .limit(1)\n if (seedRecords.length > 0 && seedRecords[0].type) {\n modelName = startCase(seedRecords[0].type)\n }\n }\n\n const modelProperties: string[] = []\n if (modelName) {\n try {\n const { Model } = await import('@seedprotocol/sdk')\n const model = await Model.getByNameAsync(modelName)\n if (model?.properties) {\n for (const modelProperty of model.properties) {\n if (modelProperty.name) modelProperties.push(modelProperty.name)\n }\n }\n } catch (error) {\n propertiesLogger(`[useItemProperties] Error getting ModelProperties for ${modelName}:`, error)\n }\n }\n\n if (modelName && modelProperties.length > 0) {\n const resolvedSeedLocalId = baseList.length > 0 ? (baseList[0].seedLocalId ?? seedLocalId) : seedLocalId\n const resolvedSeedUid = baseList.length > 0 ? (baseList[0].seedUid ?? seedUid) : seedUid\n for (const propertyName of modelProperties) {\n if (propertiesWithMetadata.has(propertyName)) continue\n try {\n const itemProperty = ItemProperty.create(\n {\n propertyName,\n modelName,\n seedLocalId: resolvedSeedLocalId || undefined,\n seedUid: resolvedSeedUid || undefined,\n propertyValue: null,\n },\n { waitForReady: false },\n )\n if (itemProperty) _itemProperties.push(itemProperty as any as IItemProperty)\n } catch (error) {\n logger(`[useItemProperties] Error creating ItemProperty for missing property ${propertyName}:`, error)\n }\n }\n }\n\n if (seedLocalId || seedUid) {\n const seedRecords = await db\n .select({ createdAt: seeds.createdAt })\n .from(seeds)\n .where(seedUid ? eq(seeds.uid, seedUid) : eq(seeds.localId, seedLocalId!))\n .limit(1)\n if (seedRecords.length > 0 && seedRecords[0].createdAt) {\n const createdAtPropertyName = 'createdAt'\n const hasCreatedAtProperty = _itemProperties.some((p) => p.propertyName === createdAtPropertyName)\n if (!hasCreatedAtProperty && modelName) {\n try {\n const resolvedSeedLocalId = baseList.length > 0 ? (baseList[0].seedLocalId ?? seedLocalId) : seedLocalId\n const resolvedSeedUid = baseList.length > 0 ? (baseList[0].seedUid ?? seedUid) : seedUid\n const createdAtProperty = ItemProperty.create(\n {\n propertyName: createdAtPropertyName,\n modelName,\n seedLocalId: resolvedSeedLocalId || undefined,\n seedUid: resolvedSeedUid || undefined,\n propertyValue: seedRecords[0].createdAt.toString(),\n },\n { waitForReady: false },\n )\n if (createdAtProperty) _itemProperties.push(createdAtProperty as any as IItemProperty)\n } catch (error) {\n logger(`[useItemProperties] Error creating createdAt ItemProperty:`, error)\n }\n }\n }\n }\n\n return _itemProperties\n}\n\n/**\n * Hook to get all ItemProperty instances for a specific item\n * Can be called in multiple ways:\n * 1. With seedLocalId: useItemProperties({ seedLocalId })\n * 2. With seedUid: useItemProperties({ seedUid })\n * 3. With itemId: useItemProperties(itemId)\n * \n * Uses useLiveQuery to watch for changes in the metadata table and automatically\n * updates the returned ItemProperty instances when changes occur.\n * \n * @overload\n * @param props - Object with seedLocalId or seedUid\n * @returns Object with properties array, isLoading, and error\n * \n * @overload\n * @param itemId - The item ID (seedLocalId or seedUid)\n * @returns Object with properties array, isLoading, and error\n */\nexport function useItemProperties(props: {\n seedLocalId?: string\n seedUid?: string\n}): UseItemPropertiesReturn\nexport function useItemProperties(itemId: string): UseItemPropertiesReturn\nexport function useItemProperties(\n arg1: { seedLocalId?: string; seedUid?: string } | string\n): UseItemPropertiesReturn {\n\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const previousTableDataRef = useRef<string | undefined>(undefined)\n\n // Determine which lookup mode we're in based on arguments\n const lookupMode = useMemo(() => {\n if (typeof arg1 === 'string') {\n // String argument: itemId (assumed to be seedLocalId)\n return { type: 'itemId' as const, itemId: arg1 }\n } else if (typeof arg1 === 'object') {\n // Object argument: { seedLocalId/seedUid }\n return {\n type: 'identifiers' as const,\n seedLocalId: arg1.seedLocalId,\n seedUid: arg1.seedUid,\n }\n } else {\n return null\n }\n }, [arg1])\n\n // Determine seedLocalId and seedUid for query\n const seedLocalId = useMemo(() => {\n if (!lookupMode) return undefined\n if (lookupMode.type === 'itemId') {\n return lookupMode.itemId\n } else {\n return lookupMode.seedLocalId\n }\n }, [lookupMode])\n\n const seedUid = useMemo(() => {\n if (!lookupMode || lookupMode.type === 'itemId') return undefined\n return lookupMode.seedUid\n }, [lookupMode])\n\n const canonicalItemKey = seedLocalId ?? seedUid ?? ''\n const itemPropertiesQueryKey = useMemo(\n () => (['seed', 'itemProperties', canonicalItemKey] as const),\n [canonicalItemKey],\n )\n\n const {\n data: properties = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey: itemPropertiesQueryKey,\n queryFn: () => fetchItemPropertiesList(seedLocalId, seedUid),\n enabled: isClientReady && !!canonicalItemKey,\n })\n\n // Watch the metadata table for changes\n // Query metadata table directly and filter for latest records in JavaScript\n // This is simpler and works better with useLiveQuery than CTEs\n // Get db inside useMemo to avoid recreating query on each render\n // Drizzle query builders are new objects each time, but useMemo will only recreate\n // when dependencies change, which is what we want for reactive queries\n const propertiesQuery = useMemo(() => {\n if (!isClientReady || (!seedLocalId && !seedUid)) {\n propertiesLogger('[useItemProperties] Query: returning null (not ready or no identifiers)')\n return null\n }\n \n const db = BaseDb.getAppDb()\n if (!db) {\n propertiesLogger('[useItemProperties] Query: returning null (no db)')\n return null\n }\n \n propertiesLogger(`[useItemProperties] Query: creating query for seedLocalId=${seedLocalId}, seedUid=${seedUid}`)\n \n // Query metadata table directly - we'll filter for latest records in JavaScript\n const query = seedUid\n ? db\n .select({\n propertyName: metadata.propertyName,\n propertyValue: metadata.propertyValue,\n seedLocalId: metadata.seedLocalId,\n seedUid: metadata.seedUid,\n modelType: metadata.modelType,\n schemaUid: metadata.schemaUid,\n createdAt: metadata.createdAt,\n attestationCreatedAt: metadata.attestationCreatedAt,\n })\n .from(metadata)\n .where(\n and(\n eq(metadata.seedUid, seedUid),\n isNotNull(metadata.propertyName)\n )\n )\n : seedLocalId\n ? db\n .select({\n propertyName: metadata.propertyName,\n propertyValue: metadata.propertyValue,\n seedLocalId: metadata.seedLocalId,\n seedUid: metadata.seedUid,\n modelType: metadata.modelType,\n schemaUid: metadata.schemaUid,\n createdAt: metadata.createdAt,\n attestationCreatedAt: metadata.attestationCreatedAt,\n })\n .from(metadata)\n .where(\n and(\n eq(metadata.seedLocalId, seedLocalId),\n isNotNull(metadata.propertyName)\n )\n )\n : null\n \n propertiesLogger(`[useItemProperties] Query: created query object`, { queryType: seedUid ? 'seedUid' : 'seedLocalId' })\n return query\n }, [isClientReady, seedLocalId, seedUid])\n \n const rawPropertiesTableData = useLiveQuery<{\n propertyName: string | null\n propertyValue: string | null\n seedLocalId: string | null\n seedUid: string | null\n modelType: string | null\n schemaUid: string | null\n createdAt: number | null\n attestationCreatedAt: number | null\n }>(propertiesQuery)\n \n // Filter for latest records (one per propertyName) in JavaScript\n const propertiesTableData = useMemo(() => {\n if (!rawPropertiesTableData || rawPropertiesTableData.length === 0) {\n return []\n }\n\n // Group by propertyName and keep only the latest record for each\n const latestByProperty = new Map<string, typeof rawPropertiesTableData[0]>()\n \n for (const record of rawPropertiesTableData) {\n if (!record.propertyName) continue\n \n const existing = latestByProperty.get(record.propertyName)\n if (!existing) {\n latestByProperty.set(record.propertyName, record)\n } else {\n // Compare timestamps to find the latest\n const existingTime = existing.attestationCreatedAt || existing.createdAt || 0\n const currentTime = record.attestationCreatedAt || record.createdAt || 0\n if (currentTime > existingTime) {\n latestByProperty.set(record.propertyName, record)\n }\n }\n }\n\n return Array.from(latestByProperty.values())\n }, [rawPropertiesTableData])\n\n // Invalidate when metadata table data actually changes so useQuery refetches\n useEffect(() => {\n if (!isClientReady || (!seedLocalId && !seedUid) || propertiesTableData === undefined) return\n\n // Include propertyValue so value-only changes produce a different string and trigger invalidation\n const tableDataString = JSON.stringify(\n propertiesTableData\n .map((p) => ({\n propertyName: p.propertyName,\n propertyValue: p.propertyValue,\n seedLocalId: p.seedLocalId,\n seedUid: p.seedUid,\n }))\n .sort((a, b) => (a.propertyName || '').localeCompare(b.propertyName || ''))\n )\n\n if (previousTableDataRef.current === tableDataString) return\n previousTableDataRef.current = tableDataString\n\n // Invalidate when metadata table data changed (new/updated/removed props or value changes)\n // so useQuery refetches and UI shows latest values.\n if (propertiesTableData.length > 0) {\n queryClient.invalidateQueries({ queryKey: itemPropertiesQueryKey })\n }\n }, [isClientReady, propertiesTableData, properties, seedLocalId, seedUid, queryClient, itemPropertiesQueryKey])\n\n useEffect(() => {\n previousTableDataRef.current = undefined\n }, [seedLocalId, seedUid])\n\n return {\n properties,\n isLoading,\n error: queryError as Error | null,\n }\n}\n\nexport type UseCreateItemPropertyProps = {\n seedLocalId?: string\n seedUid?: string\n propertyName: string\n modelName: string\n propertyValue?: any\n versionLocalId?: string\n versionUid?: string\n [key: string]: any\n}\n\nexport type UseCreateItemPropertyReturn = {\n create: (props: UseCreateItemPropertyProps) => IItemProperty | undefined\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\n/**\n * Hook to create an ItemProperty with loading and error state.\n * create(props) creates a new property instance for an item; provide seedLocalId or seedUid, propertyName, and modelName.\n */\nexport const useCreateItemProperty = (): UseCreateItemPropertyReturn => {\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const create = useCallback((props: UseCreateItemPropertyProps): IItemProperty | undefined => {\n if (!props.propertyName || (!props.seedLocalId && !props.seedUid) || !props.modelName) {\n const err = new Error('seedLocalId or seedUid, propertyName, and modelName are required')\n setError(err)\n return undefined\n }\n\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n\n const instance = ItemProperty.create(props, { waitForReady: false })\n if (!instance) {\n setError(new Error('Failed to create item property'))\n setIsLoading(false)\n return undefined\n }\n\n const subscription = instance.getService().subscribe((snapshot: any) => {\n if (snapshot?.value === 'error') {\n const err = (snapshot.context as any)?._loadingError?.error ?? new Error('Failed to create item property')\n setError(err instanceof Error ? err : new Error(String(err)))\n setIsLoading(false)\n }\n if (snapshot?.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return instance\n }, [])\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [])\n\n return {\n create,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroyItemPropertyReturn = {\n destroy: (itemProperty: IItemProperty) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroyItemProperty = (): UseDestroyItemPropertyReturn => {\n const [currentInstance, setCurrentInstance] = useState<IItemProperty | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot() as unknown as {\n context: { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n }\n const ctx = snap.context\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (itemProperty: IItemProperty) => {\n if (!itemProperty) return\n setCurrentInstance(itemProperty)\n await itemProperty.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}\n","import { useCallback, useEffect, useState } from 'react'\nimport { ActorRef, InspectedEventEvent } from 'xstate'\nimport { orderBy } from 'lodash-es'\nimport { produce } from 'immer'\nimport { eventEmitter } from '@seedprotocol/sdk'\nimport pluralize from 'pluralize'\nimport { useSelector } from '@xstate/react'\nimport debug from 'debug'\nimport { appState } from '@seedprotocol/sdk'\nimport { like } from 'drizzle-orm'\nimport { BaseDb, MachineIds, ClientManagerState, getClient } from '@seedprotocol/sdk'\n\nconst logger = debug('seedSdk:react:services')\n\nconst finalStrings = ['idle', 'ready', 'done', 'success', 'initialized']\n\nexport const getServiceName = (service: ActorRef<any, any>) => {\n let name = 'actor'\n const serviceAny = service as any\n if (service && serviceAny.uniqueKey) {\n name = serviceAny.uniqueKey\n }\n if (service && !serviceAny.uniqueKey && serviceAny.logic && serviceAny.logic.config) {\n name = getServiceUniqueKey(service)\n }\n return name\n}\n\nexport const getServiceValue = (\n service: ActorRef<any, any>,\n): string | undefined => {\n let value\n if (service && service.getSnapshot() && service.getSnapshot().value) {\n value = service.getSnapshot().value\n }\n if (getServiceName(service) === 'global') {\n if (\n value &&\n typeof value === 'object' &&\n Object.keys(value).length > 0 &&\n Object.keys(value)[0] === 'initialized'\n ) {\n value = 'ready'\n }\n }\n if (value && typeof value === 'object') {\n value = JSON.stringify(value)\n }\n return value\n}\n\nexport const getServiceUniqueKey = (service: ActorRef<any, any>) => {\n const serviceAny = service as any\n if (!service || !serviceAny.logic || !serviceAny.logic.config || !serviceAny._snapshot) {\n return\n }\n const config = serviceAny.logic.config\n if (!config.id) {\n return\n }\n let uniqueKey = config.id\n if (config.id.includes('@seedSdk/')) {\n uniqueKey = config.id.match(/^.*@seedSdk\\/(\\w+)[\\.\\w]*/)[1]\n }\n let snapshot\n try {\n snapshot = service.getSnapshot()\n } catch (error) {\n logger('Error:', error)\n return uniqueKey\n }\n if (snapshot) {\n const context = snapshot.context\n if (context && context.dbName) {\n uniqueKey = context.dbName\n }\n if (context && context.modelNamePlural) {\n uniqueKey = context.modelNamePlural\n }\n if (context && context.modelName) {\n uniqueKey = pluralize(context.modelName.toLowerCase())\n }\n }\n return uniqueKey\n}\n\nexport const useService = (service: ActorRef<any, any>) => {\n const [timeElapsed, setTimeElapsed] = useState(0)\n\n const getPercentComplete = (service: ActorRef<any, any>) => {\n let percentComplete = 0\n const serviceAny = service as any\n if (serviceAny.logic?.states) {\n const stateNames: string[] = []\n const startupStates: any[] = []\n\n for (const [stateName, state] of Object.entries(serviceAny.logic.states)) {\n const stateTyped = state as { tags?: string[] }\n if (stateTyped.tags?.includes('loading')) {\n stateNames.push(stateName)\n startupStates.push(state)\n }\n }\n\n const totalStates = startupStates.length\n const value = getServiceValue(service)\n if (value && finalStrings.includes(value)) {\n return 0\n }\n if (value) {\n const stateIndex = stateNames.indexOf(value)\n percentComplete = (stateIndex / totalStates) * 100\n }\n }\n return percentComplete\n }\n\n const updateTime = useCallback(\n (interval: ReturnType<typeof setInterval>) => {\n const context = service.getSnapshot().context\n const status = service.getSnapshot().value\n if (\n status === 'done' ||\n status === 'success' ||\n status === 'idle' ||\n status === 'ready'\n ) {\n clearInterval(interval)\n return\n }\n setTimeElapsed((timeElapsed) => timeElapsed + 1)\n },\n [service],\n )\n\n const startInterval = useCallback(() => {\n const interval = setInterval(() => {\n updateTime(interval)\n }, 1000)\n return interval\n }, [updateTime, service])\n\n useEffect(() => {\n const interval = startInterval()\n return () => clearInterval(interval)\n }, [])\n\n return {\n name: getServiceName(service),\n timeElapsed,\n value: getServiceValue(service),\n percentComplete: getPercentComplete(service),\n uniqueKey: getServiceUniqueKey(service),\n }\n}\n\nexport const useIsDbReady = () => {\n const [isDbReady, setIsDbReady] = useState(false)\n\n const { internalStatus } = useGlobalServiceStatus()\n\n useEffect(() => {\n if (internalStatus === 'ready') {\n setIsDbReady(true)\n }\n }, [internalStatus])\n\n useEffect(() => {\n if (internalStatus === 'ready') {\n setIsDbReady(true)\n }\n }, [])\n \n\n return isDbReady\n}\n\nexport const usePersistedSnapshots = () => {\n const [initialized, setInitialized] = useState(false)\n\n const hasSavedSnapshots = useHasSavedSnapshots()\n\n const { services, percentComplete } = useServices()\n\n // Helper function to save all actor snapshots to the database\n const save = useCallback(async () => {\n for (const actor of services) {\n const uniqueKey = getServiceUniqueKey(actor)\n logger(\n `would save to db with snapshot__${uniqueKey}:`,\n JSON.stringify(actor.getPersistedSnapshot()),\n )\n // await writeAppState(\n // `snapshot__${uniqueKey}`,\n // JSON.stringify(actor.getPersistedSnapshot()),\n // )\n }\n }, [services])\n\n // Helper function to load persisted snapshots from the database\n const load = useCallback(async () => {\n const appDb = BaseDb.getAppDb()\n\n if (!appDb) {\n return []\n }\n\n const persistedSnapshots = await appDb\n .select()\n .from(appState)\n .where(like(appState.key, 'snapshot__%'))\n return persistedSnapshots\n }, [])\n\n useEffect(() => {\n if (!hasSavedSnapshots || initialized) {\n return\n }\n const initialize = async () => {\n const persistedSnapshots = await load()\n logger('persistedSnapshots:', persistedSnapshots)\n setInitialized(true)\n }\n\n initialize()\n\n return () => {\n save() // Save snapshots on unmount\n }\n }, [hasSavedSnapshots, initialized])\n}\n\nexport const useHasSavedSnapshots = () => {\n const [hasSavedSnapshots, setHasSavedSnapshots] = useState(false)\n\n const isDbReady = useIsDbReady()\n\n useEffect(() => {\n if (isDbReady) {\n const _checkForSnapshots = async (): Promise<void> => {\n const appDb = BaseDb.getAppDb()\n\n const rows = await appDb\n .select()\n .from(appState)\n .where(like(appState.key, 'snapshot__%'))\n\n if (rows && rows.length > 0) {\n setHasSavedSnapshots(true)\n }\n }\n\n _checkForSnapshots()\n }\n }, [isDbReady])\n\n return hasSavedSnapshots\n}\n\nexport const useServices = () => {\n const [actors, setActors] = useState<ActorRef<any, any>[]>([])\n const [percentComplete, setPercentComplete] = useState(5)\n\n // Global service removed - now track ClientManager directly\n useEffect(() => {\n const clientManager = getClient()\n const clientService = clientManager.getService()\n \n // Add ClientManager to actors list\n const clientActor = clientService as any\n clientActor.uniqueKey = 'clientManager'\n \n setActors([clientActor])\n \n // Calculate percent complete based on ClientManager state\n const subscription = clientService.subscribe((snapshot) => {\n const state = snapshot.value\n // Calculate completion based on state progression\n let percent = 0\n if (state === ClientManagerState.IDLE) {\n percent = 100\n } else if (state === ClientManagerState.ADD_MODELS_TO_DB) {\n percent = 90\n } else if (state === ClientManagerState.ADD_MODELS_TO_STORE) {\n percent = 80\n } else if (state === ClientManagerState.PROCESS_SCHEMA_FILES) {\n percent = 70\n } else if (state === ClientManagerState.SAVE_CONFIG) {\n percent = 60\n } else if (state === ClientManagerState.DB_INIT) {\n percent = 50\n } else if (state === ClientManagerState.FILE_SYSTEM_INIT) {\n percent = 30\n } else if (state === ClientManagerState.PLATFORM_CLASSES_INIT) {\n percent = 10\n }\n setPercentComplete(percent)\n })\n \n return () => {\n subscription.unsubscribe()\n }\n }, [])\n\n return {\n services: actors,\n percentComplete,\n }\n}\n\nexport const useGlobalServiceStatus = () => {\n const clientManager = getClient()\n const clientService = clientManager.getService()\n\n const status = useSelector(clientService, (snapshot) => {\n return snapshot.value\n })\n\n // Internal service functionality is now part of ClientManager\n // DB is ready when ClientManager reaches DB_INIT or later states\n const internalStatus = useSelector(clientService, (snapshot) => {\n const state = snapshot.value\n if (state === ClientManagerState.DB_INIT || \n state === ClientManagerState.SAVE_CONFIG ||\n state === ClientManagerState.PROCESS_SCHEMA_FILES ||\n state === ClientManagerState.ADD_MODELS_TO_STORE ||\n state === ClientManagerState.ADD_MODELS_TO_DB ||\n state === ClientManagerState.IDLE) {\n return 'ready'\n }\n return state\n })\n\n return {\n status,\n internalStatus,\n }\n}\n","import { useCallback, useEffect, useState } from 'react'\nimport { Subscription } from 'xstate'\nimport { getClient, ClientManagerState } from '@seedprotocol/sdk'\nimport debug from 'debug'\n\nconst logger = debug('seedSdk:react:db')\n\nexport const useDbsAreReady = () => {\n const [dbsAreReady, setDbsAreReady] = useState(false)\n\n const update = useCallback(() => {\n if (dbsAreReady) {\n return\n }\n setDbsAreReady(true)\n }, [])\n\n useEffect(() => {\n let subscription: Subscription | undefined\n\n const _waitForDbs = async (): Promise<void> => {\n const clientManager = getClient()\n const clientService = clientManager.getService()\n \n const currentState = clientService.getSnapshot().value\n // DB is ready when ClientManager reaches DB_INIT state or later\n if (currentState === ClientManagerState.DB_INIT || \n currentState === ClientManagerState.SAVE_CONFIG ||\n currentState === ClientManagerState.PROCESS_SCHEMA_FILES ||\n currentState === ClientManagerState.ADD_MODELS_TO_STORE ||\n currentState === ClientManagerState.ADD_MODELS_TO_DB ||\n currentState === ClientManagerState.IDLE) {\n update()\n return\n }\n \n subscription = clientService.subscribe((snapshot) => {\n const state = snapshot.value\n if (state === ClientManagerState.DB_INIT || \n state === ClientManagerState.SAVE_CONFIG ||\n state === ClientManagerState.PROCESS_SCHEMA_FILES ||\n state === ClientManagerState.ADD_MODELS_TO_STORE ||\n state === ClientManagerState.ADD_MODELS_TO_DB ||\n state === ClientManagerState.IDLE) {\n update()\n subscription?.unsubscribe()\n }\n })\n }\n\n _waitForDbs()\n\n return () => {\n if (subscription) {\n subscription.unsubscribe()\n }\n }\n }, [])\n\n return {\n dbsAreReady,\n }\n}\n","import { loadAllSchemasFromDb } from '@seedprotocol/sdk'\nimport { useCallback, useEffect, useRef, useState, useMemo } from \"react\"\nimport { flushSync } from \"react-dom\"\nimport debug from \"debug\"\nimport { useIsClientReady } from \"./client\"\nimport { Schema } from '@seedprotocol/sdk'\nimport { SnapshotFrom, Subscription } from \"xstate\"\nimport { schemaMachine, SEED_PROTOCOL_SCHEMA_NAME } from '@seedprotocol/sdk'\nimport { useLiveQuery } from \"./liveQuery\"\nimport { BaseDb, schemas as schemasTable } from '@seedprotocol/sdk'\nimport { desc } from \"drizzle-orm\"\nimport type { SchemaType as DbSchemaType } from '@seedprotocol/sdk'\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\"\n\nconst logger = debug('seedSdk:react:schema')\n\n/**\n * Hook to get a Schema class instance (with setters) that is reactive\n * This allows you to edit schema properties directly like: schema.name = 'New name'\n * The schema instance uses a Proxy to ensure React re-renders when properties change\n * @param schemaIdentifier - The name of the schema or the schema file ID\n * - If a name is provided, retrieves the latest version with that name\n * - If an ID is provided, retrieves the specific schema by ID\n * @returns Object with schema instance\n */\nexport const useSchema = (schemaIdentifier: string | null | undefined) => {\n const [schema, setSchema] = useState<Schema | null>(null)\n const [isLoading, setIsLoading] = useState(schemaIdentifier ? true : false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | null>(null)\n\n const isClientReady = useIsClientReady()\n\n const loadSchema = useCallback((identifier: string) => {\n setIsLoading(true)\n setError(null)\n try {\n const schemaInstance = Schema.create(identifier, {\n waitForReady: false,\n }) as Schema\n setSchema(schemaInstance)\n\n const service = schemaInstance.getService()\n const initialSnapshot = service.getSnapshot()\n\n // Set initial loading state based on whether status is 'idle'\n const isIdle = initialSnapshot.value === 'idle'\n if (isIdle) {\n flushSync(() => setIsLoading(false))\n setError(null)\n } else {\n setIsLoading(true)\n }\n\n // Subscribe to all status changes and update isLoading based on whether status is 'idle'\n subscriptionRef.current = service.subscribe((snapshot: SchemaSnapshot) => {\n const isIdle = snapshot.value === 'idle'\n if (isIdle) {\n flushSync(() => setIsLoading(false))\n setError(null)\n } else {\n setIsLoading(true)\n }\n })\n\n } catch (error) {\n logger('[useSchema] Error creating schema:', error)\n setError(error as Error)\n setSchema(null)\n setIsLoading(false)\n return null\n }\n }, [])\n\n useEffect(() => {\n // Clean up previous subscription before starting a new load\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n \n if (!isClientReady) {\n setSchema(null)\n setError(null)\n setIsLoading(false)\n return\n }\n if (!schemaIdentifier) {\n setSchema(null)\n setError(null)\n setIsLoading(false)\n return\n }\n\n loadSchema(schemaIdentifier)\n \n // Cleanup function to unsubscribe when effect re-runs or component unmounts\n return () => {\n if (subscriptionRef.current) {\n subscriptionRef.current.unsubscribe()\n subscriptionRef.current = null\n }\n }\n }, [schemaIdentifier, isClientReady, loadSchema])\n \n return {\n schema,\n isLoading,\n error,\n }\n\n}\n\nconst SEED_SCHEMAS_QUERY_KEY = ['seed', 'schemas'] as const\n\nexport const useSchemas = () => {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const previousSchemasTableDataRef = useRef<DbSchemaType[] | undefined>(undefined)\n const schemasRef = useRef<Schema[]>([])\n\n const {\n data: schemas = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey: SEED_SCHEMAS_QUERY_KEY,\n queryFn: () => Schema.all({ waitForReady: true }),\n enabled: isClientReady,\n })\n schemasRef.current = schemas\n\n // Watch the schemas table for changes and invalidate so useQuery refetches\n const db = isClientReady ? BaseDb.getAppDb() : null\n const schemasQuery = useMemo(() => {\n if (!db) return null\n return db.select().from(schemasTable).orderBy(schemasTable.name, desc(schemasTable.version))\n }, [db, isClientReady])\n const schemasTableData = useLiveQuery<DbSchemaType>(schemasQuery)\n\n // When a schema is created, addSchemaToDb posts to this channel; live query often doesn't re-run when schemas table is inserted.\n useEffect(() => {\n if (typeof BroadcastChannel === 'undefined') return\n const ch = new BroadcastChannel('seed-schemas-invalidate')\n const onMessage = () => {\n queryClient.invalidateQueries({ queryKey: SEED_SCHEMAS_QUERY_KEY })\n }\n ch.addEventListener('message', onMessage)\n return () => {\n ch.removeEventListener('message', onMessage)\n ch.close()\n }\n }, [queryClient])\n\n useEffect(() => {\n if (!isClientReady || !schemasTableData) {\n return\n }\n\n const prevData = previousSchemasTableDataRef.current\n const prevDataJson = prevData ? JSON.stringify(prevData) : 'undefined'\n const currDataJson = schemasTableData ? JSON.stringify(schemasTableData) : 'undefined'\n\n if (prevDataJson === currDataJson && prevData !== undefined) {\n return\n }\n\n previousSchemasTableDataRef.current = schemasTableData\n\n const currentSchemasSet = new Set<string>()\n for (const schema of schemasRef.current) {\n const schemaFileId = schema.id || schema.schemaFileId\n if (schemaFileId) {\n currentSchemasSet.add(schemaFileId)\n } else {\n const name = schema.metadata?.name\n const version = schema.version\n if (name && version !== undefined) {\n currentSchemasSet.add(`${name}:${version}`)\n }\n }\n }\n\n const tableDataSchemasSet = new Set<string>()\n for (const dbSchema of schemasTableData) {\n if (dbSchema.name === 'Seed Protocol') continue\n if (dbSchema.schemaFileId) {\n tableDataSchemasSet.add(dbSchema.schemaFileId)\n } else if (dbSchema.name != null && dbSchema.version !== undefined) {\n tableDataSchemasSet.add(`${dbSchema.name}:${dbSchema.version}`)\n }\n }\n\n const setsAreEqual =\n currentSchemasSet.size === tableDataSchemasSet.size &&\n [...currentSchemasSet].every((id) => tableDataSchemasSet.has(id))\n\n // Only invalidate when we have data and the table has rows we might be missing (live query saw new data).\n // Skip during initial load (currentSchemasSet empty) to avoid disrupting loading state.\n // Do NOT invalidate when we have more than the table: the live query may not have updated\n // yet, and refetching could overwrite cache with stale/empty data.\n const tableHasNewRows =\n currentSchemasSet.size > 0 &&\n tableDataSchemasSet.size > 0 &&\n [...tableDataSchemasSet].some((id) => !currentSchemasSet.has(id))\n\n if (!setsAreEqual && tableHasNewRows) {\n queryClient.invalidateQueries({ queryKey: SEED_SCHEMAS_QUERY_KEY })\n }\n }, [isClientReady, schemasTableData, queryClient])\n\n return {\n schemas,\n isLoading,\n error: queryError as Error | null,\n }\n}\n\nexport const useCreateSchema = () => {\n const subscriptionRef = useRef<{ unsubscribe: () => void } | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const createSchema = useCallback((schemaName: string) => {\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = null\n const schema = Schema.create(schemaName, {\n waitForReady: false,\n }) as Schema\n const subscription = schema.getService().subscribe((snapshot: SchemaSnapshot) => {\n if (snapshot.value === 'error') {\n const err = snapshot.context._loadingError?.error\n setError(err instanceof Error ? err : new Error('Failed to create schema'))\n setIsLoading(false)\n }\n if (snapshot.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return schema\n }, [])\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = null\n }\n }, [])\n\n return {\n createSchema,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroySchemaReturn = {\n destroy: (schema: Schema) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroySchema = (): UseDestroySchemaReturn => {\n const [currentInstance, setCurrentInstance] = useState<Schema | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (schema: Schema) => {\n if (!schema) return\n setCurrentInstance(schema)\n await schema.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}\n\nexport const useAllSchemaVersions = () => {\n const [schemaInstances, setSchemaInstances] = useState<Schema[] | undefined | null>()\n const schemaInstancesRef = useRef<Map<string, Schema>>(new Map())\n const isClientReady = useIsClientReady()\n\n const fetchSchemas = useCallback(async () => {\n if (!isClientReady) {\n return\n }\n\n try {\n // Use DB-first approach: load all schemas from database\n // This will also import any missing schemas from files\n const allSchemasData = await loadAllSchemasFromDb()\n\n // Extract unique schema names\n const schemaNames = new Set<string>()\n for (const schemaData of allSchemasData) {\n const schemaName = schemaData.schema.metadata?.name\n if (schemaName) {\n schemaNames.add(schemaName)\n }\n }\n\n // Create/update Schema instances\n const currentInstances = new Map<string, Schema>()\n \n for (const schemaName of schemaNames) {\n // Reuse existing instance if it exists\n if (schemaInstancesRef.current.has(schemaName)) {\n const existingInstance = schemaInstancesRef.current.get(schemaName)!\n currentInstances.set(schemaName, existingInstance)\n } else {\n // Create new instance\n const schema = Schema.create(schemaName, {\n waitForReady: false,\n }) as Schema\n currentInstances.set(schemaName, schema)\n }\n }\n\n // Cleanup instances that are no longer needed\n for (const [name, instance] of schemaInstancesRef.current.entries()) {\n if (!schemaNames.has(name)) {\n instance.unload()\n }\n }\n\n // Update ref and state\n schemaInstancesRef.current = currentInstances\n setSchemaInstances(Array.from(currentInstances.values()))\n } catch (error) {\n logger('Error fetching all schema versions from database:', error)\n setSchemaInstances(null)\n }\n }, [isClientReady])\n\n useEffect(() => {\n if (!isClientReady) {\n return\n }\n fetchSchemas()\n }, [isClientReady, fetchSchemas])\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n schemaInstancesRef.current.forEach((instance) => {\n instance.unload()\n })\n schemaInstancesRef.current.clear()\n }\n }, [])\n\n return schemaInstances\n}\n\ntype SchemaSnapshot = SnapshotFrom<typeof schemaMachine>\n\n\n/**\n * Hook to get the internal Seed Protocol schema (SDK-only schema)\n * This schema is managed by the SDK and should not be edited by app developers\n * @returns Object with schema instance and schemaData (version, metadata, etc.)\n */\nexport const useSeedProtocolSchema = () => {\n return useSchema(SEED_PROTOCOL_SCHEMA_NAME)\n}","import { useMemo, useState, useEffect, useCallback, useRef } from 'react'\nimport { Model } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport { useLiveQuery } from './liveQuery'\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { models as modelsTable, modelSchemas, schemas as schemasTable } from '@seedprotocol/sdk'\nimport { eq, or } from 'drizzle-orm'\nimport { Subscription } from 'xstate'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\n\ntype UseModelsResult = {\n models: Model[]\n isLoading: boolean\n error: Error | null\n}\n\ntype UseModelsParams = string | null | undefined\n\ntype UseModels = (schemaId: UseModelsParams) => UseModelsResult\n\n/**\n * Hook to get all Model instances for a specific schema\n * Uses useLiveQuery to watch for changes in the models table and automatically\n * updates the returned Model instances when changes occur.\n * @param schemaId - The schema ID (schema file ID) or schema name to get models from\n * @returns Array of Model instances belonging to the schema\n */\nconst getModelsQueryKey = (schemaId: UseModelsParams) => ['seed', 'models', schemaId] as const\n\n// Last-known-good models per schemaId so we never flash [] after remount or refetch race (survives component unmount).\nconst lastModelsBySchemaId = new Map<string, Model[]>()\n\nexport const useModels: UseModels = (schemaId) => {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n const modelsRef = useRef<Model[]>([])\n\n const queryKey = useMemo(() => getModelsQueryKey(schemaId), [schemaId])\n\n const {\n data: models = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey,\n queryFn: async () => {\n // Capture previous data before any async work so we don't overwrite good cache with [].\n const prev = queryClient.getQueryData<Model[]>(queryKey)\n // Use waitForReady: false so we return models as soon as they exist; waitForReady: true\n // filters to only idle models and can return [] while a model is in creatingProperties.\n const next = await Model.all(schemaId!, { waitForReady: false })\n // getModelsData can intermittently return [] after returning data; keep prev to avoid overwrite.\n if (Array.isArray(prev) && prev.length > 0 && Array.isArray(next) && next.length === 0) {\n return [...prev]\n }\n // If this refetch returned [], avoid overwriting non-empty cache (e.g. race where another refetch already wrote data).\n if (Array.isArray(next) && next.length === 0) {\n const current = queryClient.getQueryData<Model[]>(queryKey)\n if (Array.isArray(current) && current.length > 0) {\n return [...current]\n }\n }\n return next\n },\n enabled: isClientReady && !!schemaId,\n })\n // Never expose [] when we previously had models (avoids flash from refetch races, remounts, or intermittent getModelsData returning []).\n // When schemaId is null/undefined, always show [] — do not use fallback from a previous schema.\n const schemaIdKey = schemaId && typeof schemaId === 'string' ? schemaId : ''\n if (models.length > 0) {\n lastModelsBySchemaId.set(schemaIdKey, models)\n }\n const fallback = modelsRef.current.length > 0 ? modelsRef.current : lastModelsBySchemaId.get(schemaIdKey)\n const displayModels =\n !schemaId\n ? models\n : models.length > 0\n ? models\n : fallback?.length\n ? fallback\n : models\n modelsRef.current = displayModels\n\n // When a model is created, writeModelToDb posts to this channel; live query over join often doesn't re-run\n useEffect(() => {\n if (!schemaId || typeof BroadcastChannel === 'undefined') return\n const ch = new BroadcastChannel('seed-models-invalidate')\n const onMessage = (event: MessageEvent<{ schemaName?: string; schemaFileId?: string }>) => {\n const { schemaName, schemaFileId } = event.data || {}\n if (schemaId === schemaName || schemaId === schemaFileId) {\n queryClient.invalidateQueries({ queryKey })\n queryClient.refetchQueries({ queryKey })\n }\n }\n ch.addEventListener('message', onMessage)\n return () => {\n ch.removeEventListener('message', onMessage)\n ch.close()\n }\n }, [schemaId, queryClient, queryKey])\n\n // Stabilize query reference: only recreate when (schemaId, isClientReady) change, not when db reference changes.\n // This keeps the same liveQuery observable/subscription alive so effects can deliver updates when a new model is added.\n const stableModelsQueryKeyRef = useRef<{ schemaId: string; ready: boolean } | null>(null)\n const stableModelsQueryRef = useRef<ReturnType<typeof buildModelsQuery> | null>(null)\n function buildModelsQuery() {\n const currentDb = BaseDb.getAppDb()\n if (!currentDb || !schemaId) return null\n return currentDb\n .select({\n modelFileId: modelsTable.schemaFileId,\n modelName: modelsTable.name,\n })\n .from(schemasTable)\n .innerJoin(modelSchemas, eq(schemasTable.id, modelSchemas.schemaId))\n .innerJoin(modelsTable, eq(modelSchemas.modelId, modelsTable.id))\n .where(\n or(\n eq(schemasTable.schemaFileId, schemaId),\n eq(schemasTable.name, schemaId)\n )\n )\n }\n const modelsQuery = useMemo(() => {\n if (!schemaId || !isClientReady) return null\n const key = { schemaId, ready: isClientReady }\n const prevKey = stableModelsQueryKeyRef.current\n if (\n prevKey &&\n prevKey.schemaId === key.schemaId &&\n prevKey.ready === key.ready &&\n stableModelsQueryRef.current !== null\n ) {\n return stableModelsQueryRef.current\n }\n const q = buildModelsQuery()\n if (!q) return null\n stableModelsQueryKeyRef.current = key\n stableModelsQueryRef.current = q\n return q\n }, [schemaId, isClientReady])\n\n const modelsTableData = useLiveQuery<{ modelFileId: string | null; modelName: string }>(modelsQuery)\n\n useEffect(() => {\n if (!isClientReady || !modelsTableData || !schemaId) return\n\n const currentModelsSet = new Set<string>()\n for (const model of modelsRef.current) {\n const modelFileId = model.id || (model as any).modelFileId\n if (modelFileId) currentModelsSet.add(modelFileId)\n else if (model.modelName) currentModelsSet.add(model.modelName)\n }\n\n const tableDataModelsSet = new Set<string>()\n for (const dbModel of modelsTableData) {\n if (dbModel.modelFileId) tableDataModelsSet.add(dbModel.modelFileId)\n else if (dbModel.modelName) tableDataModelsSet.add(dbModel.modelName)\n }\n\n const setsAreEqual =\n currentModelsSet.size === tableDataModelsSet.size &&\n [...currentModelsSet].every((id) => tableDataModelsSet.has(id))\n\n // Only invalidate when the table has rows we might be missing (live query saw new data).\n // Do NOT invalidate when we have more than the table: the live query may not have updated\n // yet (e.g. join over model_schemas), and refetching would overwrite cache with [].\n const tableHasNewRows =\n tableDataModelsSet.size > 0 &&\n [...tableDataModelsSet].some((id) => !currentModelsSet.has(id))\n\n if (!setsAreEqual && tableHasNewRows) {\n queryClient.invalidateQueries({ queryKey })\n }\n }, [isClientReady, modelsTableData, schemaId, queryClient, queryKey])\n\n return {\n models: displayModels,\n isLoading,\n error: queryError as Error | null,\n }\n}\n\ntype UseModelResult = {\n model: Model | undefined\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook to get a specific Model instance\n * Can be called in two ways:\n * 1. With schemaId and modelName: useModel(schemaId, modelName)\n * 2. With modelId: useModel(modelId)\n * \n * @param schemaIdOrModelId - The schema ID (schema file ID) OR the model ID (modelFileId)\n * @param modelName - The name of the model to retrieve (required if first param is schemaId)\n * @returns Object with model, isLoading, and error\n */\nexport const useModel = (\n schemaIdOrModelId: string | null | undefined,\n modelName?: string | null | undefined\n): UseModelResult => {\n const isClientReady = useIsClientReady()\n const [model, setModel] = useState<Model | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [, setVersion] = useState(0) // Version counter to force re-renders\n\n // If modelName is provided, treat first param as schemaId\n // Otherwise, treat first param as modelId\n const isModelIdLookup = modelName === undefined || modelName === null\n\n // Determine initial loading state\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n if (isModelIdLookup) {\n return !!schemaIdOrModelId\n } else {\n return !!(schemaIdOrModelId && modelName)\n }\n }, [isClientReady, isModelIdLookup, schemaIdOrModelId, modelName])\n\n // Lookup model by ID if needed\n useEffect(() => {\n if (!isClientReady || !isModelIdLookup || !schemaIdOrModelId) {\n setModel(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n const lookupModelById = async () => {\n try {\n setIsLoading(true)\n setError(null)\n // Use Model.createById which handles cache + DB lookup\n const foundModel = await Model.createById(schemaIdOrModelId)\n setModel(foundModel || undefined)\n setIsLoading(false)\n setError(null)\n } catch (error) {\n console.error('[useModel] Error looking up model by ID:', error)\n setModel(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }\n\n lookupModelById()\n }, [isClientReady, isModelIdLookup, schemaIdOrModelId])\n\n // Subscribe to service changes when model is available (for modelId lookup)\n useEffect(() => {\n if (!isModelIdLookup || !model) {\n // Clean up subscription if model is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n // Subscribe to service changes\n const subscription = model.getService().subscribe((snapshot) => {\n // Force re-render by incrementing version counter\n setVersion(prev => prev + 1)\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [isModelIdLookup, model])\n\n // If doing modelId lookup, return the model directly\n if (isModelIdLookup) {\n return {\n model,\n isLoading,\n error,\n }\n }\n\n // Otherwise, use schemaId + modelName lookup via useModels\n const { models: modelsList, isLoading: modelsLoading, error: modelsError } = useModels(schemaIdOrModelId)\n const foundModel = useMemo(() => {\n if (!modelName) {\n return undefined\n }\n // Try both modelName property and name getter for compatibility\n return modelsList.find((m: Model) => {\n const mName = m.modelName ?? (m as any).name\n return mName === modelName\n })\n }, [modelsList, modelName])\n\n // Subscribe to service changes when model is available (for schemaId + modelName lookup)\n useEffect(() => {\n if (isModelIdLookup || !foundModel) {\n // Clean up subscription if model is not available\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n // Subscribe to service changes\n const subscription = foundModel.getService().subscribe((snapshot) => {\n // Force re-render by incrementing version counter\n setVersion(prev => prev + 1)\n })\n \n subscriptionRef.current = subscription\n\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [isModelIdLookup, foundModel])\n\n // For schemaId + modelName lookup, derive loading/error from useModels\n return {\n model: foundModel,\n isLoading: modelsLoading,\n error: modelsError,\n }\n}\n\nexport type UseCreateModelOptions = {\n modelFileId?: string\n properties?: { [propertyName: string]: any }\n registerWithSchema?: boolean\n}\n\nexport type UseCreateModelReturn = {\n create: (\n schemaName: string,\n modelName: string,\n options?: UseCreateModelOptions\n ) => Model\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useCreateModel = (): UseCreateModelReturn => {\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const create = useCallback(\n (schemaName: string, modelName: string, options?: UseCreateModelOptions): Model => {\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n const model = Model.create(modelName, schemaName, {\n ...options,\n waitForReady: false,\n }) as Model\n const subscription = model.getService().subscribe((snapshot) => {\n if (snapshot.value === 'error') {\n setError(\n (snapshot.context as any)._loadingError?.error ??\n new Error('Failed to create model')\n )\n setIsLoading(false)\n }\n if (snapshot.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return model\n },\n []\n )\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [])\n\n return {\n create,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroyModelReturn = {\n destroy: (model: Model) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroyModel = (): UseDestroyModelReturn => {\n const [currentInstance, setCurrentInstance] = useState<Model | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (model: Model) => {\n if (!model) return\n setCurrentInstance(model)\n await model.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}","import { useModel } from \"./model\"\nimport { useCallback, useEffect, useRef, useState, useMemo } from \"react\"\nimport { flushSync } from \"react-dom\"\nimport { debounce } from \"lodash-es\"\nimport { getPropertySchema, ModelProperty } from '@seedprotocol/sdk'\nimport { useIsClientReady } from \"./client\"\nimport { Subscription } from \"xstate\"\nimport debug from \"debug\"\nimport { useLiveQuery } from \"./liveQuery\"\nimport { BaseDb } from '@seedprotocol/sdk'\nimport { properties as propertiesTable, models as modelsTable } from '@seedprotocol/sdk'\nimport { eq } from \"drizzle-orm\"\nimport { Model } from '@seedprotocol/sdk'\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\"\nimport { getSchemaNameFromId } from '@seedprotocol/sdk'\n\nconst logger = debug('seedSdk:browser:react:modelProperty')\n\ntype UseModelPropertiesResult = {\n modelProperties: ModelProperty[]\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Hook to get all ModelProperty instances for a specific model\n * Can be called in two ways:\n * 1. With schemaId and modelName: useModelProperties(schemaId, modelName)\n * 2. With modelId: useModelProperties(modelId)\n * \n * Uses useLiveQuery to watch for changes in the properties table and automatically\n * updates the returned ModelProperty instances when changes occur.\n * \n * @param schemaIdOrModelId - The schema ID (schema file ID) OR the model ID (modelFileId)\n * @param modelName - The name of the model to get properties from (required if first param is schemaId)\n * @returns Object with modelProperties array, isLoading, and error\n */\nexport const useModelProperties = (\n schemaIdOrModelId: string | null | undefined,\n modelName?: string | null | undefined\n): UseModelPropertiesResult => {\n // Use useModel to handle both lookup patterns (by ID or by schemaId + modelName)\n const { model } = useModel(schemaIdOrModelId, modelName)\n \n // Determine the modelName for use in getPropertySchema\n const modelNameForProperty = useMemo(() => {\n if (!model) return undefined\n try {\n return model.modelName ?? (model as any).name\n } catch {\n return undefined\n }\n }, [model])\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n\n // Get _dbId (database ID) from model context\n const dbModelId = useMemo(() => {\n if (!model) return null\n try {\n const context = (model as any)._getSnapshotContext()\n return context._dbId as number | undefined\n } catch {\n return null\n }\n }, [model])\n\n const modelId = model?.id\n const modelPropertiesQueryKey = useMemo(\n () => ['seed', 'modelProperties', modelId ?? ''] as const,\n [modelId],\n )\n\n const {\n data: modelProperties = [],\n isLoading,\n error: queryError,\n } = useQuery({\n queryKey: modelPropertiesQueryKey,\n queryFn: () => ModelProperty.all(modelId!, { waitForReady: true }),\n enabled: isClientReady && !!modelId,\n })\n\n const db = isClientReady ? BaseDb.getAppDb() : null\n const propertiesQuery = useMemo(() => {\n if (!db || !dbModelId) return null\n return db\n .select({\n id: propertiesTable.id,\n name: propertiesTable.name,\n dataType: propertiesTable.dataType,\n schemaFileId: propertiesTable.schemaFileId,\n })\n .from(propertiesTable)\n .where(eq(propertiesTable.modelId, dbModelId))\n }, [db, isClientReady, dbModelId])\n const propertiesTableData = useLiveQuery<{ id: number; name: string; dataType: string; schemaFileId: string | null }>(propertiesQuery)\n\n const modelPropertiesRef = useRef<ModelProperty[]>([])\n modelPropertiesRef.current = modelProperties\n\n // Fallback: when we have modelId but query returned [] (e.g. properties not in DB yet or\n // propertiesTableData is undefined because model._dbId isn't set yet), schedule refetches\n // so we pick up properties after they're written.\n useEffect(() => {\n if (!modelId || modelProperties.length > 0 || !queryClient || !modelPropertiesQueryKey) return\n const delays = [400, 1200, 2500]\n const timers = delays.map((ms) =>\n setTimeout(() => {\n queryClient.invalidateQueries({ queryKey: modelPropertiesQueryKey })\n }, ms)\n )\n return () => timers.forEach((t) => clearTimeout(t))\n }, [modelId, modelProperties.length, queryClient, modelPropertiesQueryKey])\n\n useEffect(() => {\n if (!isClientReady || !model?.id || !propertiesTableData || !modelPropertiesQueryKey) return\n\n const currentPropertiesSet = new Set<string>()\n for (const prop of modelPropertiesRef.current) {\n const context = (prop as any)._getSnapshotContext()\n const propertyFileId = context?.id\n if (propertyFileId) currentPropertiesSet.add(propertyFileId)\n else if (prop.name) currentPropertiesSet.add(prop.name)\n }\n\n const tableDataPropertiesSet = new Set<string>()\n for (const dbProperty of propertiesTableData) {\n if (dbProperty.schemaFileId) tableDataPropertiesSet.add(dbProperty.schemaFileId)\n else if (dbProperty.name) tableDataPropertiesSet.add(dbProperty.name)\n }\n\n const setsAreEqual =\n currentPropertiesSet.size === tableDataPropertiesSet.size &&\n (currentPropertiesSet.size === 0 ||\n [...currentPropertiesSet].every((id) => tableDataPropertiesSet.has(id)))\n\n // Invalidate when cached list is out of sync with the table: either we have stale cached data\n // (currentPropertiesSet.size > 0) or the table has new rows we don't have yet (tableDataPropertiesSet.size > 0).\n // The latter handles the case where the initial query returned [] before properties were written.\n const shouldInvalidate =\n !setsAreEqual && (currentPropertiesSet.size > 0 || tableDataPropertiesSet.size > 0)\n\n if (shouldInvalidate) {\n queryClient.invalidateQueries({ queryKey: modelPropertiesQueryKey })\n }\n }, [isClientReady, propertiesTableData, model?.id, queryClient, modelPropertiesQueryKey])\n\n // When we have cached modelProperties, do not report isLoading: true even if the query\n // is refetching (e.g. after useModels refetch causes modelId to change briefly). UX expects\n // isLoading false once we have shown data.\n const effectiveIsLoading = isLoading && modelProperties.length === 0\n\n return {\n modelProperties,\n isLoading: effectiveIsLoading,\n error: queryError as Error | null,\n }\n}\n\n/**\n * Helper function to get property schema by modelFileId and propertyName\n */\nconst getPropertySchemaByModelFileId = async (\n modelFileId: string,\n propertyName: string\n): Promise<ReturnType<typeof getPropertySchema>> => {\n // Get model by modelFileId\n const model = await Model.createById(modelFileId)\n if (!model) {\n return undefined\n }\n\n // Get modelName from model\n const modelName = model.modelName ?? (model as any).name\n if (!modelName) {\n return undefined\n }\n\n // Use existing getPropertySchema function\n return getPropertySchema(modelName, propertyName)\n}\n\n/**\n * Hook to get a specific ModelProperty instance\n * Can be called in three ways:\n * 1. With propertyFileId: useModelProperty(propertyFileId)\n * 2. With modelFileId and propertyName: useModelProperty(modelFileId, propertyName)\n * 3. With schemaId, modelName, and propertyName: useModelProperty(schemaId, modelName, propertyName)\n * \n * @overload\n * @param propertyFileId - The property file ID (schemaFileId)\n * @returns Object with modelProperty, isLoading, and error\n * \n * @overload\n * @param modelFileId - The model file ID (modelFileId)\n * @param propertyName - The name of the property\n * @returns Object with modelProperty, isLoading, and error\n * \n * @overload\n * @param schemaId - The schema ID (schema file ID)\n * @param modelName - The name of the model\n * @param propertyName - The name of the property\n * @returns Object with modelProperty, isLoading, and error\n */\nexport function useModelProperty(propertyFileId: string): {\n modelProperty: ModelProperty | undefined\n isLoading: boolean\n error: Error | null\n}\nexport function useModelProperty(\n modelFileId: string,\n propertyName: string\n): {\n modelProperty: ModelProperty | undefined\n isLoading: boolean\n error: Error | null\n}\nexport function useModelProperty(\n schemaId: string,\n modelName: string,\n propertyName: string\n): {\n modelProperty: ModelProperty | undefined\n isLoading: boolean\n error: Error | null\n}\nexport function useModelProperty(\n arg1: string | null | undefined,\n arg2?: string | null | undefined,\n arg3?: string | null | undefined\n) {\n // Determine initial loading state - start loading if we have valid parameters\n const initialLoadingState = useMemo(() => {\n if (arg3 !== undefined && arg3 !== null) {\n // Three arguments: schemaId, modelName, propertyName\n return !!(arg1 && arg2 && arg3)\n } else if (arg2 !== undefined && arg2 !== null) {\n // Two arguments: modelFileId, propertyName\n return !!(arg1 && arg2)\n } else {\n // One argument: propertyFileId\n return !!arg1\n }\n }, [arg1, arg2, arg3])\n\n const [modelProperty, setModelProperty] = useState<ModelProperty | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(initialLoadingState)\n const [error, setError] = useState<Error | null>(null)\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n\n const isClientReady = useIsClientReady()\n\n // Determine which lookup mode we're in based on arguments\n const lookupMode = useMemo(() => {\n if (arg3 !== undefined && arg3 !== null) {\n // Three arguments: schemaId, modelName, propertyName\n return { type: 'schemaId' as const, schemaId: arg1, modelName: arg2, propertyName: arg3 }\n } else if (arg2 !== undefined && arg2 !== null) {\n // Two arguments: modelFileId, propertyName\n return { type: 'modelFileId' as const, modelFileId: arg1, propertyName: arg2 }\n } else {\n // One argument: propertyFileId\n return { type: 'propertyFileId' as const, propertyFileId: arg1 }\n }\n }, [arg1, arg2, arg3])\n\n // Determine if we should be loading based on parameters\n const shouldLoad = useMemo(() => {\n if (!isClientReady) return false\n if (lookupMode.type === 'propertyFileId') {\n return !!lookupMode.propertyFileId\n } else if (lookupMode.type === 'modelFileId') {\n return !!(lookupMode.modelFileId && lookupMode.propertyName)\n } else {\n return !!(lookupMode.schemaId && lookupMode.modelName && lookupMode.propertyName)\n }\n }, [isClientReady, lookupMode])\n\n const updateModelProperty = useCallback(async () => {\n if (!isClientReady) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n let propertyData: Awaited<ReturnType<typeof getPropertySchema>> | undefined\n let resolvedModelName: string | undefined\n\n try {\n setIsLoading(true)\n setError(null)\n\n if (lookupMode.type === 'propertyFileId') {\n if (!lookupMode.propertyFileId) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Use ModelProperty.createById for propertyFileId lookup\n const foundProperty = await ModelProperty.createById(lookupMode.propertyFileId)\n if (foundProperty) {\n setModelProperty(foundProperty)\n setIsLoading(false)\n setError(null)\n } else {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n }\n return\n } else if (lookupMode.type === 'modelFileId') {\n if (!lookupMode.modelFileId || !lookupMode.propertyName) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Get property schema by modelFileId and propertyName\n // This function already gets the model and resolves modelName\n propertyData = await getPropertySchemaByModelFileId(lookupMode.modelFileId, lookupMode.propertyName)\n \n // Get modelName from model (needed for ModelProperty.create)\n const model = await Model.createById(lookupMode.modelFileId)\n resolvedModelName = model?.modelName ?? (model as any)?.name\n } else {\n // lookupMode.type === 'schemaId'\n if (!lookupMode.schemaId || !lookupMode.modelName || !lookupMode.propertyName) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n\n // Use existing getPropertySchema for schemaId + modelName + propertyName\n propertyData = await getPropertySchema(lookupMode.modelName, lookupMode.propertyName)\n resolvedModelName = lookupMode.modelName\n }\n\n if (propertyData && resolvedModelName) {\n const createdProperty = ModelProperty.create(\n { ...propertyData, modelName: resolvedModelName },\n { waitForReady: false }\n )\n const resolvedProperty = createdProperty instanceof Promise ? await createdProperty : createdProperty\n flushSync(() => {\n setModelProperty(resolvedProperty)\n setIsLoading(false)\n setError(null)\n })\n } else {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n }\n } catch (error) {\n console.error('[useModelProperty] Error updating model property:', error)\n setModelProperty(undefined)\n setIsLoading(false)\n setError(error as Error)\n }\n }, [isClientReady, lookupMode.type, lookupMode.propertyFileId, lookupMode.modelFileId, lookupMode.propertyName, lookupMode.schemaId, lookupMode.modelName])\n\n // Fetch/refetch when lookup parameters change or client becomes ready\n useEffect(() => {\n if (!shouldLoad) {\n setModelProperty(undefined)\n setIsLoading(false)\n setError(null)\n return\n }\n updateModelProperty()\n }, [shouldLoad, updateModelProperty])\n\n // Subscribe to service changes when modelProperty is available.\n // Skip subscription for schemaId/modelFileId lookups where we created the instance locally—\n // refetching on every snapshot would set loading and can race with the initial render.\n // Debounce to reduce refetch frequency and avoid updateContext/refetch loops.\n const shouldSubscribe = lookupMode.type === 'propertyFileId'\n useEffect(() => {\n if (!modelProperty || !shouldSubscribe) {\n return\n }\n\n // Clean up previous subscription\n subscriptionRef.current?.unsubscribe()\n\n const debouncedUpdate = debounce(updateModelProperty, 100)\n\n // Subscribe to service changes\n const subscription = modelProperty.getService().subscribe(() => {\n debouncedUpdate()\n })\n\n subscriptionRef.current = subscription\n\n return () => {\n debouncedUpdate.cancel()\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [modelProperty, updateModelProperty, shouldSubscribe])\n\n return {\n modelProperty,\n isLoading,\n error,\n }\n}\n\nexport type UseCreateModelPropertyOptions = {\n name: string\n dataType: string\n [key: string]: any\n}\n\nexport type UseCreateModelPropertyReturn = {\n create: (\n schemaId: string,\n modelName: string,\n property: UseCreateModelPropertyOptions\n ) => ModelProperty\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\n/**\n * Hook to create a ModelProperty with loading and error state.\n * create(schemaId, modelName, property) creates a new property on the model.\n */\nexport const useCreateModelProperty = (): UseCreateModelPropertyReturn => {\n const subscriptionRef = useRef<Subscription | undefined>(undefined)\n const [isLoading, setIsLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const resetError = useCallback(() => setError(null), [])\n\n const create = useCallback(\n (\n schemaId: string,\n modelName: string,\n property: UseCreateModelPropertyOptions\n ): ModelProperty => {\n setError(null)\n setIsLoading(true)\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n\n if (!modelName || !property.name || !property.dataType) {\n const err = new Error('modelName, property name and dataType are required')\n setError(err)\n setIsLoading(false)\n throw err\n }\n\n // Resolve schema name: schemaId may be \"Blog-1\" (schemaName-version) or just \"Blog\"\n const schemaName = getSchemaNameFromId(schemaId) ?? schemaId\n\n const created = ModelProperty.create(\n { ...property, modelName } as Parameters<typeof ModelProperty.create>[0],\n { waitForReady: false, schemaName }\n ) as ModelProperty\n const subscription = created.getService().subscribe((snapshot) => {\n if ((snapshot as { value?: string }).value === 'error') {\n const err = (snapshot.context as any)._loadingError?.error ?? new Error('Failed to create model property')\n setError(err instanceof Error ? err : new Error(String(err)))\n setIsLoading(false)\n }\n if (snapshot.value === 'idle') {\n setError(null)\n setIsLoading(false)\n }\n })\n subscriptionRef.current = subscription\n return created\n },\n []\n )\n\n useEffect(() => {\n return () => {\n subscriptionRef.current?.unsubscribe()\n subscriptionRef.current = undefined\n }\n }, [])\n\n return {\n create,\n isLoading,\n error,\n resetError,\n }\n}\n\nexport type UseDestroyModelPropertyReturn = {\n destroy: (modelProperty: ModelProperty) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDestroyModelProperty = (): UseDestroyModelPropertyReturn => {\n const [currentInstance, setCurrentInstance] = useState<ModelProperty | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (modelProperty: ModelProperty) => {\n if (!modelProperty) return\n setCurrentInstance(modelProperty)\n await modelProperty.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}","import { useCallback, useEffect, useState } from 'react'\nimport { Item } from '@seedprotocol/sdk'\n\nexport type UseDeleteItemReturn = {\n deleteItem: (item: Item<any>) => Promise<void>\n isLoading: boolean\n error: Error | null\n resetError: () => void\n}\n\nexport const useDeleteItem = (): UseDeleteItemReturn => {\n const [currentInstance, setCurrentInstance] = useState<Item<any> | null>(null)\n const [destroyState, setDestroyState] = useState<{ isLoading: boolean; error: Error | null }>({\n isLoading: false,\n error: null,\n })\n\n useEffect(() => {\n if (!currentInstance) {\n setDestroyState({ isLoading: false, error: null })\n return\n }\n const service = currentInstance.getService()\n const update = () => {\n const snap = service.getSnapshot()\n const ctx = snap.context as { _destroyInProgress?: boolean; _destroyError?: { message: string } | null }\n setDestroyState({\n isLoading: !!ctx._destroyInProgress,\n error: ctx._destroyError ? new Error(ctx._destroyError.message) : null,\n })\n }\n update()\n const sub = service.subscribe(update)\n return () => sub.unsubscribe()\n }, [currentInstance])\n\n const destroy = useCallback(async (item: Item<any>) => {\n if (!item) return\n setCurrentInstance(item)\n await item.destroy()\n }, [])\n\n const resetError = useCallback(() => {\n if (currentInstance) {\n currentInstance.getService().send({ type: 'clearDestroyError' })\n }\n }, [currentInstance])\n\n return {\n deleteItem: destroy,\n isLoading: destroyState.isLoading,\n error: destroyState.error,\n resetError,\n }\n}\n","import { useEffect } from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { BaseFileManager } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\nimport { eventEmitter } from '@seedprotocol/sdk'\n\nconst IMAGE_FILES_QUERY_KEY = ['seed', 'imageFiles'] as const\n\n/**\n * Returns an up-to-date list of image filenames stored in the file system (OPFS in browser).\n * Automatically refetches when images are saved (file-saved) or after bulk downloads (fs.downloadAll.success).\n *\n * Must be used within SeedProvider and after client.init().\n *\n * @example\n * ```tsx\n * const { imageFiles, isLoading, error, refetch } = useImageFiles()\n * // imageFiles: ['photo.jpg', 'cover.png']\n * ```\n */\nexport function useImageFiles() {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n\n const {\n data: imageFiles = [],\n isLoading,\n error,\n refetch,\n } = useQuery({\n queryKey: IMAGE_FILES_QUERY_KEY,\n queryFn: () => BaseFileManager.listImageFiles(),\n enabled: isClientReady,\n })\n\n useEffect(() => {\n const fileSavedHandler = (filePath: string) => {\n if (filePath.includes('/images/')) {\n queryClient.invalidateQueries({ queryKey: IMAGE_FILES_QUERY_KEY })\n }\n }\n const downloadSuccessHandler = () => {\n queryClient.invalidateQueries({ queryKey: IMAGE_FILES_QUERY_KEY })\n }\n eventEmitter.on('file-saved', fileSavedHandler)\n eventEmitter.on('fs.downloadAll.success', downloadSuccessHandler)\n return () => {\n eventEmitter.off('file-saved', fileSavedHandler)\n eventEmitter.off('fs.downloadAll.success', downloadSuccessHandler)\n }\n }, [queryClient])\n\n return {\n imageFiles,\n isLoading,\n error: error instanceof Error ? error : null,\n refetch,\n }\n}\n","import { useEffect, useMemo } from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { BaseFileManager, eventEmitter } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\n\nexport const FILES_QUERY_KEY_PREFIX = ['seed', 'files'] as const\n\n/**\n * Returns an up-to-date list of filenames stored in the given directory.\n * Automatically refetches when files are saved (file-saved) or after bulk downloads (fs.downloadAll.success).\n *\n * Must be used within SeedProvider and after client.init().\n *\n * @param dir - Directory name under the files root (e.g. 'files', 'images'). Default: 'files'.\n *\n * @example\n * ```tsx\n * const { files, isLoading, error, refetch } = useFiles('files')\n * // files: ['document.pdf', 'contract.docx']\n * ```\n */\nexport function useFiles(dir: string = 'files') {\n const isClientReady = useIsClientReady()\n const queryClient = useQueryClient()\n\n const queryKey = useMemo(() => [...FILES_QUERY_KEY_PREFIX, dir] as const, [dir])\n\n const {\n data: files = [],\n isLoading,\n error,\n refetch,\n } = useQuery({\n queryKey,\n queryFn: () => BaseFileManager.listFiles(dir),\n enabled: isClientReady,\n })\n\n useEffect(() => {\n const fileSavedHandler = (filePath: string) => {\n if (filePath.includes(`/${dir}/`)) {\n queryClient.invalidateQueries({ queryKey })\n }\n }\n const downloadSuccessHandler = () => {\n queryClient.invalidateQueries({ queryKey })\n }\n eventEmitter.on('file-saved', fileSavedHandler)\n eventEmitter.on('fs.downloadAll.success', downloadSuccessHandler)\n return () => {\n eventEmitter.off('file-saved', fileSavedHandler)\n eventEmitter.off('fs.downloadAll.success', downloadSuccessHandler)\n }\n }, [queryClient, dir, queryKey])\n\n return {\n files,\n isLoading,\n error: error instanceof Error ? error : null,\n refetch,\n }\n}\n","import {\n type QueryClient,\n type DefaultOptions,\n QueryClient as ReactQueryClient,\n type QueryClientConfig,\n NetworkMode,\n} from '@tanstack/react-query'\n\nconst SEED_QUERY_DEFAULT_OPTIONS: DefaultOptions = {\n queries: {\n networkMode: 'offlineFirst' as NetworkMode,\n gcTime: 1000 * 60 * 60 * 24, // 24 hours\n staleTime: 1000 * 60, // 1 minute - list data can be slightly stale\n },\n}\n\n/**\n * Returns the default options used by Seed for list-query caching.\n * Use this when building your own QueryClient so Seed hooks get consistent behavior.\n */\nexport function getSeedQueryDefaultOptions(): DefaultOptions {\n return { ...SEED_QUERY_DEFAULT_OPTIONS }\n}\n\n/**\n * Merges Seed's default query options with your existing default options.\n * Your options take precedence over Seed's. Use when constructing your own QueryClient:\n *\n * @example\n * ```ts\n * const client = new QueryClient({\n * defaultOptions: mergeSeedQueryDefaults({\n * queries: { gcTime: 1000 * 60 * 60 },\n * }),\n * })\n * ```\n */\nexport function mergeSeedQueryDefaults(\n userOptions?: Partial<DefaultOptions> | null\n): DefaultOptions {\n const seed = getSeedQueryDefaultOptions()\n if (!userOptions) return seed\n return {\n queries: {\n ...seed.queries,\n ...(userOptions.queries ?? {}),\n },\n mutations: {\n ...(seed.mutations ?? {}),\n ...(userOptions.mutations ?? {}),\n },\n }\n}\n\n/**\n * Creates a QueryClient configured with Seed's default options.\n * Use this when you want to provide your own QueryClientProvider but still use Seed's defaults.\n *\n * @param overrides - Optional config to merge with Seed defaults (e.g. defaultOptions, logger).\n */\nexport function createSeedQueryClient(overrides?: Partial<QueryClientConfig>): QueryClient {\n const defaults = getSeedQueryDefaultOptions()\n const { defaultOptions: userDefaultOptions, ...restOverrides } = overrides ?? {}\n return new ReactQueryClient({\n ...restOverrides,\n defaultOptions: userDefaultOptions\n ? mergeSeedQueryDefaults(userDefaultOptions as DefaultOptions)\n : defaults,\n })\n}\n","import React, { type ReactNode, useMemo, useEffect } from 'react'\nimport { QueryClientProvider } from '@tanstack/react-query'\nimport type { QueryClient } from '@tanstack/react-query'\nimport { createSeedQueryClient } from './queryClient'\nimport { eventEmitter } from '@seedprotocol/sdk'\n\nexport type SeedProviderProps = {\n children: ReactNode\n /** Optional: use your own QueryClient. If not provided, a default client with Seed options is created. */\n queryClient?: QueryClient\n /** Optional: ref to receive the QueryClient instance (e.g. for tests). */\n queryClientRef?: React.MutableRefObject<QueryClient | null>\n}\n\ndeclare global {\n interface Window {\n __SEED_INVALIDATE_ITEM_PROPERTIES__?: ((canonicalId: string) => void) | null\n }\n}\n\n/** Module-level ref so invalidateItemPropertiesForItem works when test and app share the same bundle but not the same window (e.g. iframe). */\nlet invalidateItemPropertiesRef: ((canonicalId: string) => void | Promise<void>) | null = null\n\n/**\n * Invalidates and refetches the item-properties query for an item.\n * Call this after updating an ItemProperty (e.g. after save()) so useItemProperties\n * refetches and the UI updates. Returns a Promise that resolves when the refetch has completed (if available).\n */\nexport function invalidateItemPropertiesForItem(canonicalId: string): Promise<void> {\n const p1 = invalidateItemPropertiesRef?.(canonicalId)\n if (typeof window !== 'undefined' && window.__SEED_INVALIDATE_ITEM_PROPERTIES__) {\n window.__SEED_INVALIDATE_ITEM_PROPERTIES__(canonicalId)\n }\n return Promise.resolve(p1).then(() => {})\n}\n\nfunction SeedProviderEventSubscriber({ queryClient }: { queryClient: QueryClient }) {\n useEffect(() => {\n const invalidate = (canonicalId: string) => {\n const key: readonly [string, string, string] = ['seed', 'itemProperties', canonicalId]\n queryClient.invalidateQueries({ queryKey: key })\n return queryClient.refetchQueries({ queryKey: key })\n }\n invalidateItemPropertiesRef = invalidate\n if (typeof window !== 'undefined') {\n window.__SEED_INVALIDATE_ITEM_PROPERTIES__ = invalidate\n }\n const handler = (payload: { seedLocalId?: string; seedUid?: string }) => {\n const canonicalId = payload?.seedLocalId ?? payload?.seedUid\n if (canonicalId) {\n invalidate(canonicalId)\n }\n }\n eventEmitter.on('itemProperty.saved', handler)\n return () => {\n eventEmitter.off('itemProperty.saved', handler)\n invalidateItemPropertiesRef = null\n if (typeof window !== 'undefined') {\n window.__SEED_INVALIDATE_ITEM_PROPERTIES__ = null\n }\n }\n }, [queryClient])\n return null\n}\n\n/**\n * Provider that supplies a React Query client to Seed list hooks (useSchemas, useItems, useModels, etc.)\n * so results are cached and shared across components. Wrap your app (or the subtree that uses Seed hooks)\n * after calling client.init().\n *\n * - No props: uses an internal QueryClient with Seed defaults.\n * - queryClient prop: use your own client (e.g. merge getSeedQueryDefaultOptions when creating it).\n */\nexport function SeedProvider({ children, queryClient: queryClientProp, queryClientRef }: SeedProviderProps) {\n const queryClient = useMemo(\n () => queryClientProp ?? createSeedQueryClient(),\n [queryClientProp]\n )\n if (queryClientRef) {\n queryClientRef.current = queryClient\n if (typeof window !== 'undefined') {\n const w = window as { __TEST_SEED_QUERY_CLIENT__?: QueryClient }\n w.__TEST_SEED_QUERY_CLIENT__ = queryClient\n try {\n if (window.parent && window.parent !== window) (window.parent as { __TEST_SEED_QUERY_CLIENT__?: QueryClient }).__TEST_SEED_QUERY_CLIENT__ = queryClient\n } catch {\n // cross-origin frame, ignore\n }\n }\n }\n return (\n <QueryClientProvider client={queryClient}>\n <SeedProviderEventSubscriber queryClient={queryClient} />\n {children}\n </QueryClientProvider>\n )\n}\n","import React, { useEffect, type ReactNode } from 'react'\nimport { client } from '@seedprotocol/sdk'\nimport type { SeedConstructorOptions, SeedConfig, SchemaFileFormat } from '@seedprotocol/sdk'\nimport { useIsClientReady } from './client'\n\n/** Schema input: path string or SchemaFileFormat object. Merged into config.schema at init. */\ntype SchemaInput = string | SchemaFileFormat\n\nfunction DefaultLoading() {\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n width: '100%',\n }}\n >\n Loading...\n </div>\n )\n}\n\nexport type SeedClientGateProps = {\n /** Seed client init options (config + addresses). Required. */\n initConfig: SeedConstructorOptions\n /** Optional canonical schema. When provided, merged into config.schema and loaded at init (no separate import). */\n schema?: SchemaInput\n /** Custom loading UI. Default: simple centered \"Loading...\" text. */\n loadingComponent?: ReactNode\n /** @deprecated Schema is now loaded at init via config.schema; no separate import. Kept for backward compatibility. */\n onSchemaImportError?: (err: unknown) => void\n /** Class for the root wrapper. e.g. \"relative flex h-screen w-screen\" */\n wrapperClassName?: string\n /** Class for the loading overlay. e.g. \"absolute inset-0 z-50 flex items-center justify-center bg-zinc-950\" */\n loadingClassName?: string\n children: ReactNode\n}\n\n/**\n * Gates children until the Seed client is initialized and optionally imports a schema.\n * Mounted inside RouterProvider so we never swap the router—only the route content.\n * This avoids removeChild DOM errors and ensures QueryClientProvider stays stable.\n * Both overlay and content stay in DOM; we only toggle visibility via classes.\n */\nexport function SeedClientGate({\n initConfig,\n schema,\n loadingComponent,\n wrapperClassName,\n loadingClassName,\n children,\n}: SeedClientGateProps) {\n const isClientReady = useIsClientReady()\n\n useEffect(() => {\n const effectiveConfig: SeedConstructorOptions = schema\n ? {\n ...initConfig,\n config: {\n ...initConfig.config,\n schema,\n } as SeedConfig,\n }\n : initConfig\n client.init(effectiveConfig)\n }, [initConfig, schema])\n\n const loadingContent = loadingComponent ?? <DefaultLoading />\n\n const wrapperStyle = !wrapperClassName\n ? { position: 'relative' as const, display: 'flex' as const, height: '100vh', width: '100vw' }\n : undefined\n\n const overlayStyle: React.CSSProperties = {\n display: isClientReady ? 'none' : 'flex',\n ...(!loadingClassName && {\n position: 'absolute',\n inset: 0,\n zIndex: 50,\n alignItems: 'center',\n justifyContent: 'center',\n }),\n }\n\n const contentStyle: React.CSSProperties = {\n flex: 1,\n display: isClientReady ? 'flex' : 'none',\n flexDirection: 'column',\n }\n\n return (\n <div className={wrapperClassName} style={wrapperStyle}>\n <div\n className={loadingClassName}\n style={overlayStyle}\n aria-hidden={isClientReady}\n >\n {loadingContent}\n </div>\n <div style={contentStyle}>\n {children}\n </div>\n </div>\n )\n}\n","import { useState, useCallback, useEffect } from 'react'\n\nexport interface OPFSFile {\n name: string\n path: string\n size: number\n type: string\n lastModified: number\n}\n\nasync function scanDirectory(\n dirHandle: FileSystemDirectoryHandle,\n basePath: string = ''\n): Promise<OPFSFile[]> {\n const foundFiles: OPFSFile[] = []\n\n try {\n for await (const [name, handle] of dirHandle.entries()) {\n const currentPath = basePath ? `${basePath}/${name}` : name\n\n if (handle.kind === 'file') {\n try {\n const file = await (handle as FileSystemFileHandle).getFile()\n foundFiles.push({\n name,\n path: currentPath,\n size: file.size,\n type: file.type || 'application/octet-stream',\n lastModified: file.lastModified,\n })\n } catch (err) {\n console.warn(`Failed to read file ${currentPath}:`, err)\n }\n } else if (handle.kind === 'directory') {\n const subFiles = await scanDirectory(handle as FileSystemDirectoryHandle, currentPath)\n foundFiles.push(...subFiles)\n }\n }\n } catch (err) {\n console.warn(`Failed to scan directory ${basePath}:`, err)\n }\n\n return foundFiles\n}\n\nexport interface UseOPFSFilesOptions {\n /** Optional subdirectory to scan (e.g. 'app-files'). Default: root. */\n rootPath?: string\n}\n\n/**\n * Hook to scan and list all files in OPFS (Origin Private File System).\n * Uses navigator.storage.getDirectory() - works in browsers that support OPFS.\n *\n * @example\n * ```tsx\n * const { files, isLoading, error, refetch } = useOPFSFiles()\n * ```\n */\nexport function useOPFSFiles(options: UseOPFSFilesOptions = {}) {\n const { rootPath } = options\n const [files, setFiles] = useState<OPFSFile[]>([])\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n\n const load = useCallback(async () => {\n setIsLoading(true)\n setError(null)\n\n try {\n const root = await navigator.storage.getDirectory()\n let dirHandle: FileSystemDirectoryHandle = root\n\n if (rootPath) {\n const parts = rootPath.split('/').filter(Boolean)\n for (const part of parts) {\n dirHandle = await dirHandle.getDirectoryHandle(part)\n }\n }\n\n const allFiles = await scanDirectory(dirHandle, rootPath || '')\n setFiles(allFiles.sort((a, b) => a.path.localeCompare(b.path)))\n } catch (err) {\n setError(\n 'Failed to access OPFS: ' + (err instanceof Error ? err.message : String(err))\n )\n console.error('OPFS access error:', err)\n } finally {\n setIsLoading(false)\n }\n }, [rootPath])\n\n useEffect(() => {\n load()\n }, [load])\n\n return { files, isLoading, error, refetch: load }\n}\n","import React, { useState, useRef, useEffect } from 'react'\nimport { useOPFSFiles, type OPFSFile } from './useOPFSFiles'\n\n// Inline SVG icons to avoid external dependencies\nconst DownloadIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 20, height: 20 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3\" />\n </svg>\n)\nconst FolderIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 48, height: 48 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.25 12.75V12a2.25 2.25 0 012.25-2.25h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z\" />\n </svg>\n)\nconst DocumentIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 20, height: 20 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z\" />\n </svg>\n)\nconst TrashIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth={1.5} stroke=\"currentColor\" style={{ width: 20, height: 20 }}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0\" />\n </svg>\n)\nconst SpinnerIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n style={{ width: 32, height: 32 }}\n aria-hidden\n >\n <circle\n style={{ opacity: 0.25 }}\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n style={{ opacity: 0.75 }}\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n)\n\nfunction formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 Bytes'\n const k = 1024\n const sizes = ['Bytes', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i]\n}\n\nfunction formatDate(timestamp: number): string {\n return new Date(timestamp).toLocaleString()\n}\n\nasync function getFileBlob(file: OPFSFile, root: FileSystemDirectoryHandle): Promise<Blob> {\n const pathParts = file.path.split('/').filter(Boolean)\n if (pathParts.length === 0) throw new Error('Invalid file path')\n\n let currentHandle: FileSystemDirectoryHandle = root\n for (let i = 0; i < pathParts.length - 1; i++) {\n currentHandle = await currentHandle.getDirectoryHandle(pathParts[i])\n }\n const fileName = pathParts[pathParts.length - 1]\n const fileHandle = await currentHandle.getFileHandle(fileName)\n const opfsFile = await fileHandle.getFile()\n return opfsFile\n}\n\nasync function deleteFileAtPath(\n path: string,\n root: FileSystemDirectoryHandle\n): Promise<void> {\n const pathParts = path.split('/').filter(Boolean)\n if (pathParts.length === 0) throw new Error('Invalid file path')\n\n let currentHandle: FileSystemDirectoryHandle = root\n for (let i = 0; i < pathParts.length - 1; i++) {\n currentHandle = await currentHandle.getDirectoryHandle(pathParts[i])\n }\n const fileName = pathParts[pathParts.length - 1]\n await currentHandle.removeEntry(fileName)\n}\n\nexport type OPFSFilesManagerTheme = 'light' | 'dark'\n\nexport interface OPFSFilesManagerProps {\n /** Optional subdirectory to scan (e.g. 'app-files'). Default: root. */\n rootPath?: string\n /** Filter which files to include. */\n filter?: (file: OPFSFile) => boolean\n /** Called when a file is about to be deleted. Return false to cancel. */\n onBeforeDelete?: (file: OPFSFile) => boolean | Promise<boolean>\n /** Called after a file or files are deleted. Use for clearing app state (e.g. Seed DB). */\n onAfterDelete?: (paths: string[]) => void | Promise<void>\n /** Custom download handler (e.g. Electron). If not provided, uses browser blob download. */\n onDownload?: (file: OPFSFile, blob: Blob) => void | Promise<void>\n /** Title for the page. Default: \"Files\" */\n title?: string\n /** Description text. Default: OPFS description. */\n description?: string\n /** Visual theme. Default: \"dark\" */\n theme?: OPFSFilesManagerTheme\n /** Class for the container. */\n className?: string\n}\n\nconst themeClasses = {\n light: {\n title: 'text-gray-900',\n description: 'text-gray-500',\n batchBar: 'bg-gray-100 border-gray-200',\n batchText: 'text-gray-900',\n clearButton: 'text-gray-500 hover:text-gray-900',\n loadingText: 'text-gray-500',\n errorBox: 'bg-red-50 border-red-200',\n errorTitle: 'text-red-800',\n errorText: 'text-red-700',\n emptyIcon: 'text-gray-400',\n emptyTitle: 'text-gray-900',\n emptyText: 'text-gray-500',\n tableHeader: 'bg-gray-100 text-gray-900',\n tableRow: 'bg-white',\n tableBorder: 'border-gray-200 divide-gray-200',\n tableCell: 'text-gray-900',\n tableCellMuted: 'text-gray-500',\n codeBlock: 'bg-gray-100 border-gray-200 text-gray-800',\n actionButton: 'text-gray-500 hover:text-gray-700',\n deleteButton: 'text-gray-500 hover:text-red-600',\n },\n dark: {\n title: 'text-white',\n description: 'text-gray-400',\n batchBar: 'bg-gray-800 border-gray-700',\n batchText: 'text-white',\n clearButton: 'text-gray-400 hover:text-white',\n loadingText: 'text-gray-400',\n errorBox: 'bg-red-900/50 border-red-800',\n errorTitle: 'text-red-200',\n errorText: 'text-red-300',\n emptyIcon: 'text-gray-500',\n emptyTitle: 'text-white',\n emptyText: 'text-gray-400',\n tableHeader: 'bg-gray-900 text-white',\n tableRow: 'bg-gray-900',\n tableBorder: 'border-gray-800 divide-gray-800',\n tableCell: 'text-white',\n tableCellMuted: 'text-gray-400',\n codeBlock: 'bg-gray-800 border-gray-700 text-gray-300',\n actionButton: 'text-gray-400 hover:text-indigo-400',\n deleteButton: 'text-gray-400 hover:text-red-500',\n },\n} as const\n\nconst layoutStyles = {\n container: { padding: '2rem 0' } as React.CSSProperties,\n header: {\n display: 'flex',\n flexWrap: 'wrap' as const,\n alignItems: 'center',\n gap: '1rem',\n marginBottom: '1rem',\n },\n title: { fontSize: '1.5rem', fontWeight: 600, margin: 0 },\n description: { fontSize: '0.875rem', margin: '0.5rem 0 0 0' },\n button:\n 'rounded-md px-3 py-2 text-sm font-semibold border-0 cursor-pointer bg-indigo-600 text-white hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600',\n buttonDanger:\n 'rounded-md px-3 py-2 text-sm font-semibold border-0 cursor-pointer bg-red-600 text-white hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600',\n table: 'min-w-full divide-y',\n tableHeader: 'py-3.5 pl-4 pr-3 text-left text-sm font-semibold sm:pl-6',\n tableCell: 'whitespace-nowrap py-4 pl-4 pr-3 text-sm sm:pl-6',\n errorBox: 'rounded-md border p-4 mt-4',\n emptyState: 'text-center py-12',\n}\n\n/**\n * A React component to browse, download, and delete files stored in OPFS.\n * Useful for debugging and managing Origin Private File System storage.\n *\n * @example\n * ```tsx\n * <OPFSFilesManager\n * onAfterDelete={(paths) => {\n * if (paths.some(isSeedDbPath)) {\n * clearSeedDependentData()\n * window.location.reload()\n * }\n * }}\n * onDownload={async (file, blob) => {\n * if (window.electron?.downloadFile) {\n * await window.electron.downloadFile({ data: await blob.arrayBuffer(), filename: file.name })\n * }\n * }}\n * />\n * ```\n */\nexport function OPFSFilesManager({\n rootPath,\n filter,\n onBeforeDelete,\n onAfterDelete,\n onDownload,\n title = 'Files',\n description = 'Browse and download all files stored in the Origin Private File System (OPFS).',\n theme = 'dark',\n className,\n}: OPFSFilesManagerProps) {\n const t = themeClasses[theme]\n const { files: rawFiles, isLoading, error, refetch } = useOPFSFiles({ rootPath })\n const files = filter ? rawFiles.filter(filter) : rawFiles\n const [selectedFiles, setSelectedFiles] = useState<Set<string>>(new Set())\n const selectAllCheckboxRef = useRef<HTMLInputElement>(null)\n\n const allSelected = files.length > 0 && selectedFiles.size === files.length\n const someSelected = selectedFiles.size > 0 && selectedFiles.size < files.length\n\n const toggleFileSelection = (filePath: string) => {\n setSelectedFiles((prev) => {\n const next = new Set(prev)\n if (next.has(filePath)) next.delete(filePath)\n else next.add(filePath)\n return next\n })\n }\n\n const toggleSelectAll = () => {\n setSelectedFiles(\n selectedFiles.size === files.length ? new Set() : new Set(files.map((f) => f.path))\n )\n }\n\n useEffect(() => {\n setSelectedFiles(new Set())\n }, [files.length])\n\n useEffect(() => {\n if (selectAllCheckboxRef.current) {\n selectAllCheckboxRef.current.indeterminate = someSelected\n }\n }, [someSelected])\n\n const downloadFile = async (file: OPFSFile, suppressAlert = false) => {\n try {\n const root = await navigator.storage.getDirectory()\n const blob = await getFileBlob(file, root)\n\n if (onDownload) {\n await onDownload(file, blob)\n } else {\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = file.name\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n }\n } catch (err) {\n const msg = 'Failed to download file: ' + (err instanceof Error ? err.message : String(err))\n if (!suppressAlert) alert(msg)\n throw err\n }\n }\n\n const deleteFile = async (file: OPFSFile) => {\n if (onBeforeDelete) {\n const ok = await onBeforeDelete(file)\n if (!ok) return\n }\n if (!confirm(`Are you sure you want to delete \"${file.name}\"? This action cannot be undone.`)) {\n return\n }\n\n try {\n const root = await navigator.storage.getDirectory()\n await deleteFileAtPath(file.path, root)\n await refetch()\n await onAfterDelete?.([file.path])\n } catch (err) {\n alert('Failed to delete file: ' + (err instanceof Error ? err.message : String(err)))\n }\n }\n\n const downloadAllSelected = async () => {\n if (selectedFiles.size === 0) return\n const selected = files.filter((f) => selectedFiles.has(f.path))\n const errors: string[] = []\n for (const file of selected) {\n try {\n await downloadFile(file, true)\n await new Promise((r) => setTimeout(r, 100))\n } catch (err) {\n errors.push(`${file.name}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n if (errors.length > 0) {\n alert(`Some downloads failed:\\n${errors.join('\\n')}`)\n }\n }\n\n const deleteAllSelected = async () => {\n if (selectedFiles.size === 0) return\n const selected = files.filter((f) => selectedFiles.has(f.path))\n const names = selected.map((f) => f.name).join(', ')\n if (\n !confirm(\n `Are you sure you want to delete ${selectedFiles.size} file(s)?\\n\\nFiles: ${names}\\n\\nThis action cannot be undone.`\n )\n ) {\n return\n }\n\n const root = await navigator.storage.getDirectory()\n const deletedPaths: string[] = []\n const errors: string[] = []\n\n for (const file of selected) {\n if (onBeforeDelete) {\n const ok = await onBeforeDelete(file)\n if (!ok) continue\n }\n try {\n await deleteFileAtPath(file.path, root)\n deletedPaths.push(file.path)\n } catch (err) {\n errors.push(`${file.name}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n setSelectedFiles(new Set())\n await refetch()\n if (deletedPaths.length > 0) await onAfterDelete?.(deletedPaths)\n if (errors.length > 0) {\n alert(`Some deletions failed:\\n${errors.join('\\n')}`)\n }\n }\n\n return (\n <div className={className} style={layoutStyles.container}>\n <style>{`@keyframes opfs-spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}`}</style>\n <div style={layoutStyles.header}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <h1 style={layoutStyles.title} className={t.title}>\n {title}\n </h1>\n <p style={layoutStyles.description} className={t.description}>\n {description}\n </p>\n </div>\n <button type=\"button\" onClick={refetch} className={layoutStyles.button}>\n Refresh\n </button>\n </div>\n\n {selectedFiles.size > 0 && (\n <div\n className={`mt-4 flex items-center justify-between rounded-lg border px-4 py-3 ${t.batchBar}`}\n >\n <span className={`text-sm font-medium ${t.batchText}`}>\n {selectedFiles.size} file{selectedFiles.size === 1 ? '' : 's'} selected\n </span>\n <div className=\"flex items-center gap-3\">\n <button onClick={downloadAllSelected} className={layoutStyles.button}>\n <span className=\"inline-flex items-center gap-2\">\n <DownloadIcon /> Download All\n </span>\n </button>\n <button onClick={deleteAllSelected} className={layoutStyles.buttonDanger}>\n <span className=\"inline-flex items-center gap-2\">\n <TrashIcon /> Delete All\n </span>\n </button>\n <button\n onClick={() => setSelectedFiles(new Set())}\n className={`text-sm cursor-pointer bg-transparent border-0 ${t.clearButton}`}\n >\n Clear selection\n </button>\n </div>\n </div>\n )}\n\n <div className=\"mt-8\">\n {isLoading ? (\n <div className=\"flex justify-center items-center py-12 gap-3\">\n <span style={{ animation: 'opfs-spin 1s linear infinite' }}>\n <SpinnerIcon />\n </span>\n <span className={t.loadingText}>Loading files...</span>\n </div>\n ) : error ? (\n <div className={`${layoutStyles.errorBox} ${t.errorBox}`}>\n <h3 className={`m-0 text-sm font-medium ${t.errorTitle}`}>Error</h3>\n <div className={`mt-2 text-sm ${t.errorText}`}>{error}</div>\n </div>\n ) : files.length === 0 ? (\n <div className={layoutStyles.emptyState}>\n <span className={t.emptyIcon}>\n <FolderIcon />\n </span>\n <h3 className={`mt-2 text-sm font-semibold ${t.emptyTitle}`}>No files</h3>\n <p className={`mt-1 text-sm ${t.emptyText}`}>No files found in OPFS.</p>\n </div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className={layoutStyles.table}>\n <thead>\n <tr className={t.tableBorder}>\n <th className={`${layoutStyles.tableHeader} w-10 ${t.tableHeader}`}>\n <input\n ref={selectAllCheckboxRef}\n type=\"checkbox\"\n checked={allSelected}\n onChange={toggleSelectAll}\n aria-label=\"Select all\"\n />\n </th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Name</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Path</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Size</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Type</th>\n <th className={`${layoutStyles.tableHeader} ${t.tableHeader}`}>Modified</th>\n <th\n className={`${layoutStyles.tableHeader} w-24 ${t.tableHeader}`}\n aria-label=\"Actions\"\n />\n </tr>\n </thead>\n <tbody className={`divide-y ${t.tableBorder}`}>\n {files.map((file) => (\n <tr key={file.path} className={t.tableRow}>\n <td className={`${layoutStyles.tableCell} ${t.tableCell}`}>\n <input\n type=\"checkbox\"\n checked={selectedFiles.has(file.path)}\n onChange={() => toggleFileSelection(file.path)}\n aria-label={`Select ${file.name}`}\n />\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCell}`}>\n <span className=\"flex items-center gap-2\">\n <DocumentIcon />\n {file.name}\n </span>\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n <code className={`text-xs px-2 py-1 rounded border ${t.codeBlock}`}>\n {file.path}\n </code>\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n {formatFileSize(file.size)}\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n {file.type}\n </td>\n <td className={`${layoutStyles.tableCell} ${t.tableCellMuted}`}>\n {formatDate(file.lastModified)}\n </td>\n <td className={layoutStyles.tableCell}>\n <div className=\"flex gap-2 justify-end\">\n <button\n type=\"button\"\n onClick={() => downloadFile(file)}\n title=\"Download\"\n className={`p-1.5 rounded cursor-pointer bg-transparent border-0 transition-colors ${t.actionButton}`}\n >\n <DownloadIcon />\n </button>\n <button\n type=\"button\"\n onClick={() => deleteFile(file)}\n title=\"Delete\"\n className={`p-1.5 rounded cursor-pointer bg-transparent border-0 transition-colors ${t.deleteButton}`}\n >\n <TrashIcon />\n </button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </div>\n </div>\n )\n}\n","import React, { useState, useEffect, DetailedHTMLProps, ImgHTMLAttributes } from 'react'\nimport debug from 'debug'\nimport { BaseFileManager } from '@seedprotocol/sdk'\nimport { useItemProperty } from \"./itemProperty\"\nimport { ItemProperty } from '@seedprotocol/sdk'\n\nconst logger = debug('seedSdk:react:SeedImage')\n\n// Cache for content URLs\nconst contentUrlCache = new Map<string, string>()\n\nconst getFileNameWithoutExtension = (filePath: string): string => {\n // This regex has 3 parts:\n // 1. (.*[\\/\\\\]) - Captures the directory path (if any) ending with / or \\\n // 2. ([^\\/\\\\]+) - Captures the filename (anything that's not a / or \\)\n // 3. (\\.[^.\\/\\\\]*)?$ - Captures the last extension (if any)\n const regex = /^(.*[\\/\\\\])?([^\\/\\\\]+?)(\\.[^.\\/\\\\]*)?$/;\n \n const match = filePath.match(regex);\n \n if (match && match[2]) {\n return match[2];\n }\n \n return filePath; // Return original if no match (unlikely)\n}\n\n// Helper function to escape special regex characters\nfunction escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n}\n\nfunction matchFileNameWithoutExtension(fileName: string, targetName: string): boolean {\n // Create a regex pattern that matches the targetName\n // ^ - start of string\n // targetName is escaped to handle special regex characters\n // $ - end of string\n const regex = new RegExp(`^${escapeRegExp(targetName)}$`);\n \n // First get the filename without extension\n const nameWithoutExt = getFileNameWithoutExtension(fileName);\n \n // Then check if it matches the target name\n return regex.test(nameWithoutExt);\n}\n\ntype SeedImageProps = DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement> & {\n imageProperty: ItemProperty<any>\n alt?: string\n width?: number\n height?: number\n /** Optional filename override when property hasn't resolved yet (e.g. in tests) */\n filename?: string\n}\n\nconst SeedImageInner = ({ imageProperty, width, filename: filenameOverride, ...props }: SeedImageProps): React.ReactNode => {\n const [sizedContentUrl, setSizedContentUrl] = useState<string | undefined>()\n const [originalContentUrl, setOriginalContentUrl] = useState<string | undefined>()\n\n const { property: propertyFromHook } = useItemProperty({\n propertyName: imageProperty.propertyName,\n seedLocalId: imageProperty.seedLocalId,\n seedUid: imageProperty.seedUid\n })\n\n // Use passed imageProperty when parent provides it (e.g. direct pass from Item.properties); else use hook for reactive lookup\n const property = imageProperty ?? propertyFromHook\n\n // Resolved filename: explicit override, or from property\n const resolvedFilename = filenameOverride ?? (property?.refResolvedValue ?? property?.value) as string | undefined\n\n // Get display URL: value (blob URL or filename from ItemProperty.value getter), or resolvedFilename\n const rawValue = property?.value\n const srcUrl = (typeof rawValue === 'string' ? rawValue : resolvedFilename) as string | undefined\n const isFileOrBlob = rawValue != null && (rawValue instanceof File || rawValue instanceof Blob)\n const [blobPreviewUrl, setBlobPreviewUrl] = useState<string | null>(null)\n const blobPreviewRef = React.useRef<string | null>(null)\n useEffect(() => {\n if (isFileOrBlob && (rawValue instanceof File || rawValue instanceof Blob)) {\n if (!blobPreviewRef.current) {\n blobPreviewRef.current = URL.createObjectURL(rawValue)\n setBlobPreviewUrl(blobPreviewRef.current)\n }\n return () => {\n if (blobPreviewRef.current) {\n URL.revokeObjectURL(blobPreviewRef.current)\n blobPreviewRef.current = null\n }\n setBlobPreviewUrl(null)\n }\n }\n blobPreviewRef.current = null\n setBlobPreviewUrl(null)\n }, [isFileOrBlob, rawValue])\n\n // Fallback: when we have filename but no blob URL (e.g. after reload, or sized versions missing), load original file\n useEffect(() => {\n if (!resolvedFilename) return\n const isBlob = (s: unknown) => typeof s === 'string' && s.startsWith('blob:')\n if (rawValue && isBlob(rawValue)) return // Already have blob URL\n if (blobPreviewUrl) return // Have blob preview\n\n let cancelled = false\n const _getOriginalContentUrl = async () => {\n try {\n const filePath = property?.localStoragePath\n ? property.localStoragePath\n : `${BaseFileManager.getFilesPath('images')}/${resolvedFilename}`\n const exists = await BaseFileManager.pathExists(filePath)\n if (exists) {\n const url = await BaseFileManager.getContentUrlFromPath(filePath)\n if (!cancelled && url) setOriginalContentUrl(url)\n }\n } catch (err) {\n logger('_getOriginalContentUrl error', err)\n }\n }\n _getOriginalContentUrl()\n return () => {\n cancelled = true\n }\n }, [resolvedFilename, rawValue, blobPreviewUrl, property?.localStoragePath])\n\n useEffect(() => {\n if (!width || !resolvedFilename) {\n return\n }\n\n const _getSizedContentUrl = async () => {\n try {\n const fs = await BaseFileManager.getFs()\n const baseDir = property?.localStoragePath\n ? property.localStoragePath.split('/').slice(0, -1).join('/')\n : BaseFileManager.getFilesPath('images')\n const itemsInDir = fs.readdirSync(baseDir, {withFileTypes: true})\n const widthDirs = itemsInDir.filter((item: { isDirectory: () => boolean }) => item.isDirectory())\n const availableWidths = widthDirs.map((dir: { name: string }) => parseInt(dir.name))\n const closestWidth = availableWidths.reduce((prev: number, curr: number) => {\n return (Math.abs(curr - width) < Math.abs(prev - width) ? curr : prev)\n }, availableWidths[0])\n const filenameWithoutExtension = getFileNameWithoutExtension(resolvedFilename)\n\n // Check cache first\n const cacheKey = `${filenameWithoutExtension}-${closestWidth}`\n if (contentUrlCache.has(cacheKey)) {\n try {\n const contentUrl = contentUrlCache.get(cacheKey)\n if (contentUrl) {\n const response = await fetch(contentUrl)\n if (response.ok) {\n setSizedContentUrl(contentUrl)\n return\n }\n }\n } catch (error) {\n logger('error', error)\n contentUrlCache.delete(cacheKey)\n }\n }\n\n const itemsInSizedDir = fs.readdirSync(`${baseDir}/${closestWidth}`, {withFileTypes: true})\n\n const matchingFile = itemsInSizedDir.find((item: { name?: string }) => {\n if (!item.name) {\n return false\n }\n return matchFileNameWithoutExtension(item.name, filenameWithoutExtension)\n })\n if (!matchingFile) {\n return\n }\n const newPath = `${baseDir}/${closestWidth}/${matchingFile?.name}`\n const exists = await BaseFileManager.pathExists(newPath)\n if (exists) {\n const contentUrl = await BaseFileManager.getContentUrlFromPath(newPath)\n if (contentUrl) {\n contentUrlCache.set(cacheKey, contentUrl)\n setSizedContentUrl(contentUrl)\n }\n }\n } catch (err) {\n logger('_getSizedContentUrl error', err)\n }\n }\n\n _getSizedContentUrl()\n }, [property, width, srcUrl, resolvedFilename])\n\n // Render img when we have a content URL, or when we have filename (show placeholder while loading)\n const isBlobUrl = (s: unknown) => typeof s === 'string' && s.startsWith('blob:')\n const hasContentUrl = !!sizedContentUrl || !!originalContentUrl || !!blobPreviewUrl || (!!srcUrl && isBlobUrl(srcUrl))\n if (!hasContentUrl && !resolvedFilename) {\n return null\n }\n\n // Placeholder 1x1 transparent GIF while loading (ensures img exists for a11y and tests)\n const imgSrc = sizedContentUrl || originalContentUrl || blobPreviewUrl || (isBlobUrl(srcUrl) ? srcUrl : undefined) || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'\n\n return (\n <img src={imgSrc} alt={props.alt || imageProperty.propertyName || 'Image'} {...props} />\n )\n}\n\nexport const SeedImage = React.memo(SeedImageInner, (prev, next) =>\n prev.imageProperty === next.imageProperty &&\n prev.width === next.width &&\n prev.filename === next.filename\n)"],"names":["useIsClientReady","clientService","getClient","useSelector","snapshot","ClientManagerState","useLiveQuery","query","data","setData","useState","subscriptionRef","useRef","isClientReady","observable","useMemo","BaseDb","error","useEffect","subscription","results","err","logger","debug","useItem","modelName","seedLocalId","seedUid","item","setItem","isLoading","setIsLoading","setError","hasSeenIdleRef","modelNameRef","seedLocalIdRef","seedUidRef","shouldLoad","loadItem","useCallback","foundItem","Item","prev","getItemsQueryKey","deleted","includeEas","addressFilter","useItems","queryClient","useQueryClient","previousSeedsTableDataRef","itemsRef","lastFetchedIdsRef","addressesForFilter","setAddressesForFilter","cancelled","getAddressesForItemsFilter","addrs","queryKey","items","queryError","useQuery","db","seedsQuery","conditions","or","isNull","seeds","eq","toSnakeCase","inArray","sql","isNotNull","versionData","getVersionData","and","gt","seedsTableData","tableDataItemsSet","dbSeed","key","currentItemsSet","lastFetched","id","orderBy","useCreateItem","resetError","itemData","flushSync","createNewItem","usePublishItem","publishingItem","setPublishingItem","publishItem","service","value","ctx","publishError","snap","propertiesLogger","useItemProperty","arg1","arg2","property","setProperty","setVersion","obj","itemIdFromObj","propertyNameFromObj","itemId","propertyName","lookupMode","resolvedSeedLocalId","resolvedSeedUid","useLayoutEffect","updateItemProperty","foundProperty","ItemProperty","lastVersionAt","wasIdle","lastIdleValueSig","THROTTLE_MS","sig","now","useDebouncedItemProperty","params","debounceMs","normalizedParams","latestValueRef","debouncedPersist","debounce","prop","setValue","fetchItemPropertiesList","baseList","_itemProperties","propertiesWithMetadata","p","first","startCase","seedRecords","modelProperties","Model","model","modelProperty","itemProperty","createdAtPropertyName","createdAtProperty","useItemProperties","previousTableDataRef","canonicalItemKey","itemPropertiesQueryKey","properties","propertiesQuery","metadata","rawPropertiesTableData","propertiesTableData","latestByProperty","record","existing","existingTime","tableDataString","a","b","useCreateItemProperty","create","props","instance","useDestroyItemProperty","currentInstance","setCurrentInstance","destroyState","setDestroyState","update","sub","destroy","finalStrings","getServiceName","name","serviceAny","getServiceUniqueKey","getServiceValue","config","uniqueKey","context","pluralize","useService","timeElapsed","setTimeElapsed","getPercentComplete","percentComplete","stateNames","startupStates","stateName","state","totalStates","updateTime","interval","status","startInterval","useIsDbReady","isDbReady","setIsDbReady","internalStatus","useGlobalServiceStatus","usePersistedSnapshots","initialized","setInitialized","hasSavedSnapshots","useHasSavedSnapshots","services","useServices","save","actor","load","appDb","appState","like","persistedSnapshots","setHasSavedSnapshots","rows","actors","setActors","setPercentComplete","clientActor","percent","useDbsAreReady","dbsAreReady","setDbsAreReady","currentState","useSchema","schemaIdentifier","schema","setSchema","loadSchema","identifier","schemaInstance","Schema","SEED_SCHEMAS_QUERY_KEY","useSchemas","previousSchemasTableDataRef","schemasRef","schemas","schemasQuery","schemasTable","desc","schemasTableData","ch","onMessage","prevData","prevDataJson","currDataJson","currentSchemasSet","schemaFileId","version","tableDataSchemasSet","dbSchema","setsAreEqual","tableHasNewRows","useCreateSchema","createSchema","schemaName","useDestroySchema","useAllSchemaVersions","schemaInstances","setSchemaInstances","schemaInstancesRef","fetchSchemas","allSchemasData","loadAllSchemasFromDb","schemaNames","schemaData","currentInstances","existingInstance","useSeedProtocolSchema","SEED_PROTOCOL_SCHEMA_NAME","getModelsQueryKey","schemaId","lastModelsBySchemaId","useModels","modelsRef","models","next","current","schemaIdKey","fallback","displayModels","event","stableModelsQueryKeyRef","stableModelsQueryRef","buildModelsQuery","currentDb","modelsTable","modelSchemas","modelsQuery","prevKey","q","modelsTableData","currentModelsSet","modelFileId","tableDataModelsSet","dbModel","useModel","schemaIdOrModelId","setModel","isModelIdLookup","foundModel","modelsList","modelsLoading","modelsError","m","useCreateModel","options","useDestroyModel","useModelProperties","dbModelId","modelId","modelPropertiesQueryKey","ModelProperty","propertiesTable","modelPropertiesRef","timers","ms","t","currentPropertiesSet","propertyFileId","tableDataPropertiesSet","dbProperty","effectiveIsLoading","getPropertySchemaByModelFileId","getPropertySchema","useModelProperty","arg3","initialLoadingState","setModelProperty","updateModelProperty","propertyData","resolvedModelName","createdProperty","resolvedProperty","shouldSubscribe","debouncedUpdate","useCreateModelProperty","getSchemaNameFromId","created","useDestroyModelProperty","useDeleteItem","IMAGE_FILES_QUERY_KEY","useImageFiles","imageFiles","refetch","BaseFileManager","fileSavedHandler","filePath","downloadSuccessHandler","eventEmitter","FILES_QUERY_KEY_PREFIX","useFiles","dir","files","SEED_QUERY_DEFAULT_OPTIONS","getSeedQueryDefaultOptions","mergeSeedQueryDefaults","userOptions","seed","createSeedQueryClient","overrides","defaults","userDefaultOptions","restOverrides","ReactQueryClient","invalidateItemPropertiesRef","invalidateItemPropertiesForItem","canonicalId","p1","SeedProviderEventSubscriber","invalidate","handler","payload","SeedProvider","children","queryClientProp","queryClientRef","w","jsxs","QueryClientProvider","jsx","DefaultLoading","SeedClientGate","initConfig","loadingComponent","wrapperClassName","loadingClassName","effectiveConfig","client","loadingContent","wrapperStyle","overlayStyle","scanDirectory","dirHandle","basePath","foundFiles","handle","currentPath","file","subFiles","useOPFSFiles","rootPath","setFiles","parts","part","allFiles","DownloadIcon","FolderIcon","DocumentIcon","TrashIcon","SpinnerIcon","formatFileSize","bytes","k","sizes","i","formatDate","timestamp","getFileBlob","root","pathParts","currentHandle","fileName","deleteFileAtPath","path","themeClasses","layoutStyles","OPFSFilesManager","filter","onBeforeDelete","onAfterDelete","onDownload","title","description","theme","className","rawFiles","selectedFiles","setSelectedFiles","selectAllCheckboxRef","allSelected","someSelected","toggleFileSelection","toggleSelectAll","f","downloadFile","suppressAlert","blob","url","msg","deleteFile","downloadAllSelected","selected","errors","r","deleteAllSelected","names","deletedPaths","contentUrlCache","getFileNameWithoutExtension","regex","match","escapeRegExp","string","matchFileNameWithoutExtension","targetName","nameWithoutExt","SeedImageInner","imageProperty","width","filenameOverride","sizedContentUrl","setSizedContentUrl","originalContentUrl","setOriginalContentUrl","propertyFromHook","resolvedFilename","rawValue","srcUrl","isFileOrBlob","blobPreviewUrl","setBlobPreviewUrl","blobPreviewRef","React","s","fs","baseDir","availableWidths","closestWidth","curr","filenameWithoutExtension","cacheKey","contentUrl","matchingFile","newPath","isBlobUrl","imgSrc","SeedImage"],"mappings":"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"}
|